debian-control-0.1.28/.cargo_vcs_info.json0000644000000001540000000000100140240ustar { "git": { "sha1": "eb27c98a1e99226b40391a1991063db486806f3b" }, "path_in_vcs": "debian-control" }debian-control-0.1.28/Cargo.lock0000644000000400500000000000100117760ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "cc" version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" dependencies = [ "shlex", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-targets", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "countme" version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" [[package]] name = "deb822-lossless" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "286f48b96d8b0b1430db71c92b8a641f5edf0d926d44f51bf2159aabcf526a2a" dependencies = [ "pyo3", "regex", "rowan", "serde", ] [[package]] name = "debian-control" version = "0.1.28" dependencies = [ "chrono", "deb822-lossless", "debversion", "pyo3", "regex", "rowan", "url", ] [[package]] name = "debversion" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6c96844ac16a110ee3ea355b7e511ffe0221242caebb2cc5e1bbfd285744cf" dependencies = [ "lazy-regex", ] [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "iana-time-zone" version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "idna" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "indoc" version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "js-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy-regex" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d8e41c97e6bc7ecb552016274b99fbb5d035e8de288c582d9b933af6677bfda" dependencies = [ "lazy-regex-proc_macros", "once_cell", "regex", ] [[package]] name = "lazy-regex-proc_macros" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76e1d8b05d672c53cb9c7b920bbba8783845ae4f0b076e02a3db1d02c81b4163" dependencies = [ "proc-macro2", "quote", "regex", "syn", ] [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "portable-atomic" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", "unindent", ] [[package]] name = "pyo3-build-config" version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8" dependencies = [ "once_cell", "target-lexicon", ] [[package]] name = "pyo3-ffi" version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6" dependencies = [ "libc", "pyo3-build-config", ] [[package]] name = "pyo3-macros" version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", "syn", ] [[package]] name = "pyo3-macros-backend" version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372" dependencies = [ "heck", "proc-macro2", "pyo3-build-config", "quote", "syn", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rowan" version = "0.15.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a542b0253fa46e632d27a1dc5cf7b930de4df8659dc6e720b647fc72147ae3d" dependencies = [ "countme", "hashbrown", "rustc-hash", "text-size", ] [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "serde" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "target-lexicon" version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "text-size" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" [[package]] name = "tinyvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "unicode-bidi" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unindent" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" [[package]] name = "url" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "wasm-bindgen" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" debian-control-0.1.28/Cargo.toml0000644000000023330000000000100120230ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "debian-control" version = "0.1.28" authors = ["Jelmer Vernooij "] description = "A parser for Debian copyright files" homepage = "https://github.com/jelmer/deb822-lossless" readme = "README.md" license = "Apache-2.0" repository = "https://github.com/jelmer/deb822-lossless" [dependencies.chrono] version = "0.4" optional = true [dependencies.deb822-lossless] version = ">=0.1.20" [dependencies.debversion] version = ">=0.3" [dependencies.pyo3] version = "0.22" optional = true [dependencies.regex] version = "1" [dependencies.rowan] version = ">=0.15" [dependencies.url] version = "2" [features] chrono = ["dep:chrono"] default = ["chrono"] python-debian = [ "dep:pyo3", "deb822-lossless/python-debian", ] debian-control-0.1.28/Cargo.toml.orig000064400000000000000000000011331046102023000155010ustar 00000000000000[package] name = "debian-control" authors = ["Jelmer Vernooij "] edition = "2021" version = "0.1.28" license = "Apache-2.0" description = "A parser for Debian copyright files" repository = { workspace = true } homepage = { workspace = true } [dependencies] rowan = ">=0.15" debversion = ">=0.3" regex = "1" deb822-lossless = { version = ">=0.1.20", path = ".." } url = "2" pyo3 = { workspace = true, optional = true } chrono = { version = "0.4", optional = true } [features] default = ["chrono"] python-debian = ["dep:pyo3", "deb822-lossless/python-debian"] chrono = ["dep:chrono"] debian-control-0.1.28/README.md000064400000000000000000000013551046102023000140770ustar 00000000000000# Lossless parser for Debian Control files This crate provides a parser for Debian control files. It is lossless, meaning that it will preserve the original formatting of the file. It also provides a way to serialize the parsed data back to a string. ```rust use debian_control::{Control, Priority}; use std::fs::File; let mut control = Control::new(); let mut source = control.add_source("hello"); source.set_section("rust"); let mut binary = control.add_binary("hello"); binary.set_architecture("amd64"); binary.set_priority(Priority::Optional); binary.set_description("Hello, world!"); assert_eq!(control.to_string(), r#"Source: hello Section: rust Package: hello Architecture: amd64 Priority: optional Description: Hello, world! "#); ``` debian-control-0.1.28/examples/create-file.rs000064400000000000000000000006351046102023000171640ustar 00000000000000use debian_control::{Control, Priority}; pub fn main() { let mut control = Control::new(); let mut source = control.add_source("hello"); source.set_section(Some("rust")); let mut binary = control.add_binary("hello"); binary.set_architecture(Some("amd64")); binary.set_priority(Some(Priority::Optional)); binary.set_description(Some("Hello, world!")); println!("{}", control); } debian-control-0.1.28/src/apt.rs000064400000000000000000001007741046102023000145460ustar 00000000000000use crate::control::MultiArch; use crate::fields::{Priority, Sha1Checksum, Sha256Checksum, Sha512Checksum}; use crate::relations::Relations; /// A source package in the APT package manager. pub struct Source(deb822_lossless::Paragraph); #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)] pub struct MD5Checksum { pub md5sum: String, pub size: usize, pub filename: String, } impl std::fmt::Display for MD5Checksum { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{} {} {}", self.md5sum, self.size, self.filename) } } impl std::str::FromStr for MD5Checksum { type Err = (); fn from_str(s: &str) -> Result { let mut parts = s.split_whitespace(); let md5sum = parts.next().ok_or(())?; let size = parts.next().ok_or(())?.parse().map_err(|_| ())?; let filename = parts.next().ok_or(())?.to_string(); Ok(Self { md5sum: md5sum.to_string(), size, filename, }) } } #[cfg(feature = "python-debian")] impl pyo3::ToPyObject for Source { fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject { use pyo3::prelude::*; let d = self.0.to_object(py); let m = py.import_bound("debian.deb822").unwrap(); let cls = m.getattr("Sources").unwrap(); cls.call1((d,)).unwrap().to_object(py) } } #[cfg(feature = "python-debian")] impl pyo3::FromPyObject<'_> for Source { fn extract_bound(ob: &pyo3::Bound) -> pyo3::PyResult { use pyo3::prelude::*; Ok(Source(ob.extract()?)) } } impl Source { pub fn new(paragraph: deb822_lossless::Paragraph) -> Self { Self(paragraph) } pub fn package(&self) -> Option { self.0.get("Package").map(|s| s.to_string()) } pub fn set_package(&mut self, package: &str) { self.0.insert("Package", package); } pub fn version(&self) -> Option { self.0.get("Version").map(|s| s.parse().unwrap()) } pub fn set_version(&mut self, version: debversion::Version) { self.0.insert("Version", &version.to_string()); } pub fn maintainer(&self) -> Option { self.0.get("Maintainer").map(|s| s.to_string()) } pub fn set_maintainer(&mut self, maintainer: &str) { self.0.insert("Maintainer", maintainer); } pub fn uploaders(&self) -> Option> { self.0.get("Uploaders").map(|s| { s.split(',') .map(|s| s.trim().to_string()) .collect::>() }) } pub fn set_uploaders(&mut self, uploaders: Vec) { self.0.insert("Uploaders", &uploaders.join(", ")); } pub fn standards_version(&self) -> Option { self.0.get("Standards-Version").map(|s| s.to_string()) } pub fn set_standards_version(&mut self, version: &str) { self.0.insert("Standards-Version", version); } pub fn format(&self) -> Option { self.0.get("Format").map(|s| s.to_string()) } pub fn set_format(&mut self, format: &str) { self.0.insert("Format", format); } pub fn vcs_browser(&self) -> Option { self.0.get("Vcs-Browser").map(|s| s.to_string()) } pub fn set_vcs_browser(&mut self, url: &str) { self.0.insert("Vcs-Browser", url); } pub fn vcs_git(&self) -> Option { self.0.get("Vcs-Git").map(|s| s.to_string()) } pub fn set_vcs_git(&mut self, url: &str) { self.0.insert("Vcs-Git", url); } pub fn vcs_svn(&self) -> Option { self.0.get("Vcs-Svn").map(|s| s.to_string()) } pub fn set_vcs_svn(&mut self, url: &str) { self.0.insert("Vcs-Svn", url); } pub fn vcs_hg(&self) -> Option { self.0.get("Vcs-Hg").map(|s| s.to_string()) } pub fn set_vcs_hg(&mut self, url: &str) { self.0.insert("Vcs-Hg", url); } pub fn vcs_bzr(&self) -> Option { self.0.get("Vcs-Bzr").map(|s| s.to_string()) } pub fn set_vcs_bzr(&mut self, url: &str) { self.0.insert("Vcs-Bzr", url); } pub fn vcs_arch(&self) -> Option { self.0.get("Vcs-Arch").map(|s| s.to_string()) } pub fn set_vcs_arch(&mut self, url: &str) { self.0.insert("Vcs-Arch", url); } pub fn vcs_svk(&self) -> Option { self.0.get("Vcs-Svk").map(|s| s.to_string()) } pub fn set_vcs_svk(&mut self, url: &str) { self.0.insert("Vcs-Svk", url); } pub fn vcs_darcs(&self) -> Option { self.0.get("Vcs-Darcs").map(|s| s.to_string()) } pub fn set_vcs_darcs(&mut self, url: &str) { self.0.insert("Vcs-Darcs", url); } pub fn vcs_mtn(&self) -> Option { self.0.get("Vcs-Mtn").map(|s| s.to_string()) } pub fn set_vcs_mtn(&mut self, url: &str) { self.0.insert("Vcs-Mtn", url); } pub fn vcs_cvs(&self) -> Option { self.0.get("Vcs-Cvs").map(|s| s.to_string()) } pub fn set_vcs_cvs(&mut self, url: &str) { self.0.insert("Vcs-Cvs", url); } pub fn build_depends(&self) -> Option { self.0.get("Build-Depends").map(|s| s.parse().unwrap()) } pub fn set_build_depends(&mut self, relations: Relations) { self.0 .insert("Build-Depends", relations.to_string().as_str()); } pub fn build_depends_indep(&self) -> Option { self.0 .get("Build-Depends-Indep") .map(|s| s.parse().unwrap()) } pub fn set_build_depends_indep(&mut self, relations: Relations) { self.0.insert("Build-Depends-Indep", &relations.to_string()); } pub fn build_depends_arch(&self) -> Option { self.0.get("Build-Depends-Arch").map(|s| s.parse().unwrap()) } pub fn set_build_depends_arch(&mut self, relations: Relations) { self.0.insert("Build-Depends-Arch", &relations.to_string()); } pub fn build_conflicts(&self) -> Option { self.0.get("Build-Conflicts").map(|s| s.parse().unwrap()) } pub fn set_build_conflicts(&mut self, relations: Relations) { self.0.insert("Build-Conflicts", &relations.to_string()); } pub fn build_conflicts_indep(&self) -> Option { self.0 .get("Build-Conflicts-Indep") .map(|s| s.parse().unwrap()) } pub fn set_build_conflicts_indep(&mut self, relations: Relations) { self.0 .insert("Build-Conflicts-Indep", &relations.to_string()); } pub fn build_conflicts_arch(&self) -> Option { self.0 .get("Build-Conflicts-Arch") .map(|s| s.parse().unwrap()) } pub fn set_build_conflicts_arch(&mut self, relations: Relations) { self.0 .insert("Build-Conflicts-Arch", &relations.to_string()); } pub fn binary(&self) -> Option { self.0.get("Binary").map(|s| s.parse().unwrap()) } pub fn set_binary(&mut self, relations: Relations) { self.0.insert("Binary", &relations.to_string()); } pub fn homepage(&self) -> Option { self.0.get("Homepage").map(|s| s.to_string()) } pub fn set_homepage(&mut self, url: &str) { self.0.insert("Homepage", url); } pub fn section(&self) -> Option { self.0.get("Section").map(|s| s.to_string()) } pub fn set_section(&mut self, section: &str) { self.0.insert("Section", section); } pub fn priority(&self) -> Option { self.0.get("Priority").and_then(|v| v.parse().ok()) } pub fn set_priority(&mut self, priority: Priority) { self.0.insert("Priority", priority.to_string().as_str()); } /// The architecture of the package. pub fn architecture(&self) -> Option { self.0.get("Architecture") } pub fn set_architecture(&mut self, arch: &str) { self.0.insert("Architecture", arch); } pub fn directory(&self) -> Option { self.0.get("Directory").map(|s| s.to_string()) } pub fn set_directory(&mut self, dir: &str) { self.0.insert("Directory", dir); } pub fn testsuite(&self) -> Option { self.0.get("Testsuite").map(|s| s.to_string()) } pub fn set_testsuite(&mut self, testsuite: &str) { self.0.insert("Testsuite", testsuite); } pub fn files(&self) -> Vec { self.0 .get("Files") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_files(&mut self, files: Vec) { self.0.insert( "Files", &files .iter() .map(|f| f.to_string()) .collect::>() .join("\n"), ); } pub fn checksums_sha1(&self) -> Vec { self.0 .get("Checksums-Sha1") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_checksums_sha1(&mut self, checksums: Vec) { self.0.insert( "Checksums-Sha1", &checksums .iter() .map(|c| c.to_string()) .collect::>() .join("\n"), ); } pub fn checksums_sha256(&self) -> Vec { self.0 .get("Checksums-Sha256") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_checksums_sha256(&mut self, checksums: Vec) { self.0.insert( "Checksums-Sha256", &checksums .iter() .map(|c| c.to_string()) .collect::>() .join("\n"), ); } pub fn checksums_sha512(&self) -> Vec { self.0 .get("Checksums-Sha512") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_checksums_sha512(&mut self, checksums: Vec) { self.0.insert( "Checksums-Sha512", &checksums .iter() .map(|c| c.to_string()) .collect::>() .join("\n"), ); } } impl std::str::FromStr for Source { type Err = deb822_lossless::ParseError; fn from_str(s: &str) -> Result { Ok(Self(s.parse()?)) } } pub struct Package(deb822_lossless::Paragraph); #[cfg(feature = "python-debian")] impl pyo3::ToPyObject for Package { fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject { use pyo3::prelude::*; let d = self.0.to_object(py); let m = py.import_bound("debian.deb822").unwrap(); let cls = m.getattr("Packages").unwrap(); cls.call1((d,)).unwrap().to_object(py) } } #[cfg(feature = "python-debian")] impl pyo3::FromPyObject<'_> for Package { fn extract_bound(ob: &pyo3::Bound) -> pyo3::PyResult { use pyo3::prelude::*; Ok(Package(ob.extract()?)) } } impl Package { pub fn new(paragraph: deb822_lossless::Paragraph) -> Self { Self(paragraph) } pub fn name(&self) -> Option { self.0.get("Package").map(|s| s.to_string()) } pub fn set_name(&mut self, name: &str) { self.0.insert("Package", name); } pub fn version(&self) -> Option { self.0.get("Version").map(|s| s.parse().unwrap()) } pub fn set_version(&mut self, version: debversion::Version) { self.0.insert("Version", &version.to_string()); } pub fn installed_size(&self) -> Option { self.0.get("Installed-Size").map(|s| s.parse().unwrap()) } pub fn set_installed_size(&mut self, size: usize) { self.0.insert("Installed-Size", &size.to_string()); } pub fn maintainer(&self) -> Option { self.0.get("Maintainer").map(|s| s.to_string()) } pub fn set_maintainer(&mut self, maintainer: &str) { self.0.insert("Maintainer", maintainer); } pub fn architecture(&self) -> Option { self.0.get("Architecture").map(|s| s.to_string()) } pub fn set_architecture(&mut self, arch: &str) { self.0.insert("Architecture", arch); } pub fn depends(&self) -> Option { self.0.get("Depends").map(|s| s.parse().unwrap()) } pub fn set_depends(&mut self, relations: Relations) { self.0.insert("Depends", &relations.to_string()); } pub fn recommends(&self) -> Option { self.0.get("Recommends").map(|s| s.parse().unwrap()) } pub fn set_recommends(&mut self, relations: Relations) { self.0.insert("Recommends", &relations.to_string()); } pub fn suggests(&self) -> Option { self.0.get("Suggests").map(|s| s.parse().unwrap()) } pub fn set_suggests(&mut self, relations: Relations) { self.0.insert("Suggests", &relations.to_string()); } pub fn enhances(&self) -> Option { self.0.get("Enhances").map(|s| s.parse().unwrap()) } pub fn set_enhances(&mut self, relations: Relations) { self.0.insert("Enhances", &relations.to_string()); } pub fn pre_depends(&self) -> Option { self.0.get("Pre-Depends").map(|s| s.parse().unwrap()) } pub fn set_pre_depends(&mut self, relations: Relations) { self.0.insert("Pre-Depends", &relations.to_string()); } pub fn breaks(&self) -> Option { self.0.get("Breaks").map(|s| s.parse().unwrap()) } pub fn set_breaks(&mut self, relations: Relations) { self.0.insert("Breaks", &relations.to_string()); } pub fn conflicts(&self) -> Option { self.0.get("Conflicts").map(|s| s.parse().unwrap()) } pub fn set_conflicts(&mut self, relations: Relations) { self.0.insert("Conflicts", &relations.to_string()); } pub fn replaces(&self) -> Option { self.0.get("Replaces").map(|s| s.parse().unwrap()) } pub fn set_replaces(&mut self, relations: Relations) { self.0.insert("Replaces", &relations.to_string()); } pub fn provides(&self) -> Option { self.0.get("Provides").map(|s| s.parse().unwrap()) } pub fn set_provides(&mut self, relations: Relations) { self.0.insert("Provides", &relations.to_string()); } pub fn section(&self) -> Option { self.0.get("Section").map(|s| s.to_string()) } pub fn set_section(&mut self, section: &str) { self.0.insert("Section", section); } pub fn priority(&self) -> Option { self.0.get("Priority").and_then(|v| v.parse().ok()) } pub fn set_priority(&mut self, priority: Priority) { self.0.insert("Priority", priority.to_string().as_str()); } pub fn description(&self) -> Option { self.0.get("Description").map(|s| s.to_string()) } pub fn set_description(&mut self, description: &str) { self.0.insert("Description", description); } pub fn homepage(&self) -> Option { self.0.get("Homepage").map(|s| s.parse().unwrap()) } pub fn set_homepage(&mut self, url: &url::Url) { self.0.insert("Homepage", url.as_ref()); } pub fn source(&self) -> Option { self.0.get("Source").map(|s| s.to_string()) } pub fn set_source(&mut self, source: &str) { self.0.insert("Source", source); } pub fn description_md5(&self) -> Option { self.0.get("Description-md5").map(|s| s.to_string()) } pub fn set_description_md5(&mut self, md5: &str) { self.0.insert("Description-md5", md5); } pub fn tags(&self, tag: &str) -> Option> { self.0 .get(tag) .map(|s| s.split(',').map(|s| s.trim().to_string()).collect()) } pub fn set_tags(&mut self, tag: &str, tags: Vec) { self.0.insert(tag, &tags.join(", ")); } pub fn filename(&self) -> Option { self.0.get("Filename").map(|s| s.to_string()) } pub fn set_filename(&mut self, filename: &str) { self.0.insert("Filename", filename); } pub fn size(&self) -> Option { self.0.get("Size").map(|s| s.parse().unwrap()) } pub fn set_size(&mut self, size: usize) { self.0.insert("Size", &size.to_string()); } pub fn md5sum(&self) -> Option { self.0.get("MD5sum").map(|s| s.to_string()) } pub fn set_md5sum(&mut self, md5sum: &str) { self.0.insert("MD5sum", md5sum); } pub fn sha256(&self) -> Option { self.0.get("SHA256").map(|s| s.to_string()) } pub fn set_sha256(&mut self, sha256: &str) { self.0.insert("SHA256", sha256); } pub fn multi_arch(&self) -> Option { self.0.get("Multi-Arch").map(|s| s.parse().unwrap()) } pub fn set_multi_arch(&mut self, arch: MultiArch) { self.0.insert("Multi-Arch", arch.to_string().as_str()); } } impl std::str::FromStr for Package { type Err = deb822_lossless::ParseError; fn from_str(s: &str) -> Result { Ok(Self(s.parse()?)) } } pub struct Release(deb822_lossless::Paragraph); #[cfg(feature = "python-debian")] impl pyo3::ToPyObject for Release { fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject { use pyo3::prelude::*; let d = self.0.to_object(py); let m = py.import_bound("debian.deb822").unwrap(); let cls = m.getattr("Release").unwrap(); cls.call1((d,)).unwrap().to_object(py) } } #[cfg(feature = "python-debian")] impl pyo3::FromPyObject<'_> for Release { fn extract_bound(ob: &pyo3::Bound) -> pyo3::PyResult { use pyo3::prelude::*; Ok(Release(ob.extract()?)) } } impl Release{ pub fn new(paragraph: deb822_lossless::Paragraph) -> Self { Self(paragraph) } pub fn origin(&self) -> Option { self.0.get("Origin").map(|s| s.to_string()) } pub fn set_origin(&mut self, origin: &str) { self.0.insert("Origin", origin); } pub fn label(&self) -> Option { self.0.get("Label").map(|s| s.to_string()) } pub fn set_label(&mut self, label: &str) { self.0.insert("Label", label); } pub fn suite(&self) -> Option { self.0.get("Suite").map(|s| s.to_string()) } pub fn set_suite(&mut self, suite: &str) { self.0.insert("Suite", suite); } pub fn codename(&self) -> Option { self.0.get("Codename").map(|s| s.to_string()) } pub fn set_codename(&mut self, codename: &str) { self.0.insert("Codename", codename); } pub fn changelogs(&self) -> Option> { self.0.get("Changelogs").map(|s| { s.split(',') .map(|s| s.trim().to_string()) .collect::>() }) } pub fn set_changelogs(&mut self, changelogs: Vec) { self.0.insert("Changelogs", &changelogs.join(", ")); } #[cfg(feature = "chrono")] pub fn date(&self) -> Option> { self.0.get("Date").as_ref().map(|s| chrono::DateTime::parse_from_rfc2822(s).unwrap()) } #[cfg(feature = "chrono")] pub fn set_date(&mut self, date: chrono::DateTime) { self.0.insert("Date", date.to_rfc2822().as_str()); } #[cfg(feature = "chrono")] pub fn valid_until(&self) -> Option> { self.0.get("Valid-Until").as_ref().map(|s| chrono::DateTime::parse_from_rfc2822(s).unwrap()) } #[cfg(feature = "chrono")] pub fn set_valid_until(&mut self, date: chrono::DateTime) { self.0.insert("Valid-Until", date.to_rfc2822().as_str()); } pub fn acquire_by_hash(&self) -> bool { self.0.get("Acquire-By-Hash").map(|s| s == "yes").unwrap_or(false) } pub fn set_acquire_by_hash(&mut self, acquire_by_hash: bool) { self.0.insert("Acquire-By-Hash", if acquire_by_hash { "yes" } else { "no" }); } pub fn no_support_for_architecture_all(&self) -> bool { self.0.get("No-Support-For-Architecture-All").map(|s| s == "yes").unwrap_or(false) } pub fn set_no_support_for_architecture_all(&mut self, no_support_for_architecture_all: bool) { self.0.insert("No-Support-For-Architecture-All", if no_support_for_architecture_all { "yes" } else { "no" }); } pub fn architectures(&self) -> Option> { self.0.get("Architectures").map(|s| { s.split_whitespace() .map(|s| s.trim().to_string()) .collect::>() }) } pub fn set_architectures(&mut self, architectures: Vec) { self.0.insert("Architectures", &architectures.join(" ")); } pub fn components(&self) -> Option> { self.0.get("Components").map(|s| { s.split_whitespace() .map(|s| s.trim().to_string()) .collect::>() }) } pub fn set_components(&mut self, components: Vec) { self.0.insert("Components", &components.join(" ")); } pub fn description(&self) -> Option { self.0.get("Description").map(|s| s.to_string()) } pub fn set_description(&mut self, description: &str) { self.0.insert("Description", description); } pub fn checksums_md5(&self) -> Vec { self.0 .get("MD5Sum") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_checksums_md5(&mut self, files: Vec) { self.0.insert( "MD5Sum", &files .iter() .map(|f| f.to_string()) .collect::>() .join("\n"), ); } pub fn checksums_sha1(&self) -> Vec { self.0 .get("SHA1") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_checksums_sha1(&mut self, checksums: Vec) { self.0.insert( "SHA1", &checksums .iter() .map(|c| c.to_string()) .collect::>() .join("\n"), ); } pub fn checksums_sha256(&self) -> Vec { self.0 .get("SHA256") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_checksums_sha256(&mut self, checksums: Vec) { self.0.insert( "SHA256", &checksums .iter() .map(|c| c.to_string()) .collect::>() .join("\n"), ); } pub fn checksums_sha512(&self) -> Vec { self.0 .get("SHA512") .map(|s| { s.lines() .map(|line| line.parse().unwrap()) .collect::>() }) .unwrap_or_default() } pub fn set_checksums_sha512(&mut self, checksums: Vec) { self.0.insert( "SHA512", &checksums .iter() .map(|c| c.to_string()) .collect::>() .join("\n"), ); } } impl std::str::FromStr for Release { type Err = deb822_lossless::ParseError; fn from_str(s: &str) -> Result { Ok(Self(s.parse()?)) } } #[cfg(test)] mod tests { use super::*; use crate::fields::PackageListEntry; #[test] fn test_parse_package_list() { let s = "package1 binary section standard extra1=foo extra2=bar"; let p: PackageListEntry = s.parse().unwrap(); assert_eq!(p.package, "package1"); assert_eq!(p.package_type, "binary"); assert_eq!(p.section, "section"); assert_eq!(p.priority, super::Priority::Standard); assert_eq!(p.extra.get("extra1"), Some(&"foo".to_string())); assert_eq!(p.extra.get("extra2"), Some(&"bar".to_string())); } #[test] fn test_parse_package_list_no_extra() { let s = "package1 binary section standard"; let p: PackageListEntry = s.parse().unwrap(); assert_eq!(p.package, "package1"); assert_eq!(p.package_type, "binary"); assert_eq!(p.section, "section"); assert_eq!(p.priority, super::Priority::Standard); assert!(p.extra.is_empty()); } #[test] fn test_files() { let s = "md5sum 1234 filename"; let f: super::MD5Checksum= s.parse().unwrap(); assert_eq!(f.md5sum, "md5sum"); assert_eq!(f.size, 1234); assert_eq!(f.filename, "filename"); } #[test] fn test_sha1_checksum() { let s = "sha1 1234 filename"; let f: super::Sha1Checksum = s.parse().unwrap(); assert_eq!(f.sha1, "sha1"); assert_eq!(f.size, 1234); assert_eq!(f.filename, "filename"); } #[test] fn test_sha256_checksum() { let s = "sha256 1234 filename"; let f: super::Sha256Checksum = s.parse().unwrap(); assert_eq!(f.sha256, "sha256"); assert_eq!(f.size, 1234); assert_eq!(f.filename, "filename"); } #[test] fn test_sha512_checksum() { let s = "sha512 1234 filename"; let f: super::Sha512Checksum = s.parse().unwrap(); assert_eq!(f.sha512, "sha512"); assert_eq!(f.size, 1234); assert_eq!(f.filename, "filename"); } #[test] fn test_source() { let s = r#"Package: foo Version: 1.0 Maintainer: John Doe Uploaders: Jane Doe Standards-Version: 3.9.8 Format: 3.0 (quilt) Vcs-Browser: https://example.com/foo Vcs-Git: https://example.com/foo.git Build-Depends: debhelper (>= 9) Build-Depends-Indep: python Build-Depends-Arch: gcc Build-Conflicts: bar Build-Conflicts-Indep: python Build-Conflicts-Arch: gcc Binary: foo, bar Homepage: https://example.com/foo Section: devel Priority: optional Architecture: any Directory: pool/main/f/foo Files: 25dcf3b4b6b3b3b3b3b3b3b3b3b3b3b3 1234 foo_1.0.tar.gz Checksums-Sha1: b72b5fae3b3b3b3b3b3b3b3b3b3b3b3 1234 foo_1.0.tar.gz "#; let p: super::Source = s.parse().unwrap(); assert_eq!(p.package(), Some("foo".to_string())); assert_eq!(p.version(), Some("1.0".parse().unwrap())); assert_eq!( p.maintainer(), Some("John Doe ".to_string()) ); assert_eq!( p.uploaders(), Some(vec!["Jane Doe ".to_string()]) ); assert_eq!(p.standards_version(), Some("3.9.8".to_string())); assert_eq!(p.format(), Some("3.0 (quilt)".to_string())); assert_eq!(p.vcs_browser(), Some("https://example.com/foo".to_string())); assert_eq!(p.vcs_git(), Some("https://example.com/foo.git".to_string())); assert_eq!( p.build_depends_indep().map(|x| x.to_string()), Some("python".parse().unwrap()) ); assert_eq!(p.build_depends(), Some("debhelper (>= 9)".parse().unwrap())); assert_eq!(p.build_depends_arch(), Some("gcc".parse().unwrap())); assert_eq!(p.build_conflicts(), Some("bar".parse().unwrap())); assert_eq!(p.build_conflicts_indep(), Some("python".parse().unwrap())); assert_eq!(p.build_conflicts_arch(), Some("gcc".parse().unwrap())); assert_eq!(p.binary(), Some("foo, bar".parse().unwrap())); assert_eq!(p.homepage(), Some("https://example.com/foo".to_string())); assert_eq!(p.section(), Some("devel".to_string())); assert_eq!(p.priority(), Some(super::Priority::Optional)); assert_eq!(p.architecture(), Some("any".to_string())); assert_eq!(p.directory(), Some("pool/main/f/foo".to_string())); assert_eq!(p.files().len(), 1); assert_eq!( p.files()[0].md5sum, "25dcf3b4b6b3b3b3b3b3b3b3b3b3b3b3".to_string() ); assert_eq!(p.files()[0].size, 1234); assert_eq!(p.files()[0].filename, "foo_1.0.tar.gz".to_string()); assert_eq!(p.checksums_sha1().len(), 1); assert_eq!( p.checksums_sha1()[0].sha1, "b72b5fae3b3b3b3b3b3b3b3b3b3b3b3".to_string() ); } #[test] fn test_package() { let s = r#"Package: foo Version: 1.0 Source: bar Maintainer: John Doe Architecture: any Depends: bar Recommends: baz Suggests: qux Enhances: quux Pre-Depends: quuz Breaks: corge Conflicts: grault Replaces: garply Provides: waldo Section: devel Priority: optional Description: Foo is a bar Homepage: https://example.com/foo Description-md5: 1234 Tags: foo, bar Filename: pool/main/f/foo/foo_1.0.deb Size: 1234 Installed-Size: 1234 MD5sum: 1234 SHA256: 1234 Multi-Arch: same "#; let p: super::Package = s.parse().unwrap(); assert_eq!(p.name(), Some("foo".to_string())); assert_eq!(p.version(), Some("1.0".parse().unwrap())); assert_eq!(p.source(), Some("bar".to_string())); assert_eq!( p.maintainer(), Some("John Doe ".to_string()) ); assert_eq!(p.architecture(), Some("any".to_string())); assert_eq!(p.depends(), Some("bar".parse().unwrap())); assert_eq!(p.recommends(), Some("baz".parse().unwrap())); assert_eq!(p.suggests(), Some("qux".parse().unwrap())); assert_eq!(p.enhances(), Some("quux".parse().unwrap())); assert_eq!(p.pre_depends(), Some("quuz".parse().unwrap())); assert_eq!(p.breaks(), Some("corge".parse().unwrap())); assert_eq!(p.conflicts(), Some("grault".parse().unwrap())); assert_eq!(p.replaces(), Some("garply".parse().unwrap())); assert_eq!(p.provides(), Some("waldo".parse().unwrap())); assert_eq!(p.section(), Some("devel".to_string())); assert_eq!(p.priority(), Some(super::Priority::Optional)); assert_eq!(p.description(), Some("Foo is a bar".to_string())); assert_eq!( p.homepage(), Some(url::Url::parse("https://example.com/foo").unwrap()) ); assert_eq!(p.description_md5(), Some("1234".to_string())); assert_eq!( p.tags("Tags"), Some(vec!["foo".to_string(), "bar".to_string()]) ); assert_eq!( p.filename(), Some("pool/main/f/foo/foo_1.0.deb".to_string()) ); assert_eq!(p.size(), Some(1234)); assert_eq!(p.installed_size(), Some(1234)); assert_eq!(p.md5sum(), Some("1234".to_string())); assert_eq!(p.sha256(), Some("1234".to_string())); assert_eq!(p.multi_arch(), Some(MultiArch::Same)); } #[test] fn test_release() { let s = include_str!("testdata/Release"); let release: super::Release = s.parse().unwrap(); assert_eq!(release.origin(), Some("Debian".to_string())); assert_eq!(release.label(), Some("Debian".to_string())); assert_eq!(release.suite(), Some("testing".to_string())); assert_eq!(release.architectures(), vec!["all".to_string(), "amd64".to_string(), "arm64".to_string(), "armel".to_string(), "armhf".to_string()].into()); assert_eq!(release.components(), vec!["main".to_string(), "contrib".to_string(), "non-free-firmware".to_string(), "non-free".to_string()].into()); assert_eq!(release.description(), Some("Debian x.y Testing distribution - Not Released".to_string())); assert_eq!(318, release.checksums_md5().len()); } } debian-control-0.1.28/src/changes.rs000064400000000000000000000253001046102023000153610ustar 00000000000000pub struct Changes(deb822_lossless::Paragraph); #[derive(Debug)] pub enum ParseError { Deb822(deb822_lossless::Error), NoParagraphs, MultipleParagraphs, } impl std::fmt::Display for ParseError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Self::Deb822(e) => write!(f, "{}", e), Self::NoParagraphs => write!(f, "no paragraphs found"), Self::MultipleParagraphs => write!(f, "multiple paragraphs found"), } } } impl std::error::Error for ParseError {} impl From for ParseError { fn from(e: deb822_lossless::Error) -> Self { Self::Deb822(e) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct File { pub md5sum: String, pub size: usize, pub section: String, pub priority: crate::Priority, pub filename: String, } impl std::fmt::Display for File { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, "{} {} {} {} {}", self.md5sum, self.size, self.section, self.priority, self.filename ) } } impl std::str::FromStr for File { type Err = (); fn from_str(s: &str) -> Result { let mut parts = s.split_whitespace(); let md5sum = parts.next().ok_or(())?; let size = parts.next().ok_or(())?.parse().map_err(|_| ())?; let section = parts.next().ok_or(())?.to_string(); let priority = parts.next().ok_or(())?.parse().map_err(|_| ())?; let filename = parts.next().ok_or(())?.to_string(); Ok(Self { md5sum: md5sum.to_string(), size, section, priority, filename, }) } } impl Changes { pub fn format(&self) -> Option { self.0.get("Format").map(|s| s.to_string()) } pub fn set_format(&mut self, value: &str) { self.0.insert("Format", value); } pub fn source(&self) -> Option { self.0.get("Source").map(|s| s.to_string()) } pub fn binary(&self) -> Option> { self.0 .get("Binary") .map(|s| s.split_whitespace().map(|s| s.to_string()).collect()) } pub fn architecture(&self) -> Option> { self.0 .get("Architecture") .map(|s| s.split_whitespace().map(|s| s.to_string()).collect()) } pub fn version(&self) -> Option { self.0.get("Version").map(|s| s.parse().unwrap()) } pub fn distribution(&self) -> Option { self.0.get("Distribution").map(|s| s.to_string()) } pub fn urgency(&self) -> Option { self.0.get("Urgency").map(|s| s.parse().unwrap()) } pub fn maintainer(&self) -> Option { self.0.get("Maintainer").map(|s| s.to_string()) } pub fn changed_by(&self) -> Option { self.0.get("Changed-By").map(|s| s.to_string()) } pub fn description(&self) -> Option { self.0.get("Description").map(|s| s.to_string()) } pub fn checksums_sha1(&self) -> Option> { self.0 .get("Checksums-Sha1") .map(|s| s.lines().map(|line| line.parse().unwrap()).collect()) } pub fn checksums_sha256(&self) -> Option> { self.0 .get("Checksums-Sha256") .map(|s| s.lines().map(|line| line.parse().unwrap()).collect()) } /// Returns the list of files in the source package. pub fn files(&self) -> Option> { self.0 .get("Files") .map(|s| s.lines().map(|line| line.parse().unwrap()).collect()) } /// Returns the path to the pool directory for the source package. pub fn get_pool_path(&self) -> Option { let files = self.files()?; let section = &files.first().unwrap().section; let section = if let Some((section, _subsection)) = section.split_once('/') { section } else { "main" }; let source = self.source()?; let subdir = if source.starts_with("lib") { "lib".to_string() } else { source[..1].to_lowercase() }; Some(format!("pool/{}/{}/{}", section, subdir, source)) } pub fn new() -> Self { let mut slf = Self(deb822_lossless::Paragraph::new()); slf.set_format("1.8"); slf } pub fn from_file>(path: P) -> Result { let deb822 = deb822_lossless::Deb822::from_file(path)?; let mut paras = deb822.paragraphs(); let para = match paras.next() { Some(para) => para, None => return Err(ParseError::NoParagraphs), }; if paras.next().is_some() { return Err(ParseError::MultipleParagraphs); } Ok(Self(para)) } pub fn from_file_relaxed>( path: P, ) -> Result<(Self, Vec), std::io::Error> { let (mut deb822, mut errors) = deb822_lossless::Deb822::from_file_relaxed(path)?; let mut paras = deb822.paragraphs(); let para = match paras.next() { Some(para) => para, None => deb822.add_paragraph(), }; if paras.next().is_some() { errors.push("multiple paragraphs found".to_string()); } Ok((Self(para), errors)) } pub fn read(mut r: R) -> Result { let deb822 = deb822_lossless::Deb822::read(&mut r)?; let mut paras = deb822.paragraphs(); let para = match paras.next() { Some(para) => para, None => return Err(ParseError::NoParagraphs), }; if paras.next().is_some() { return Err(ParseError::MultipleParagraphs); } Ok(Self(para)) } pub fn read_relaxed( mut r: R, ) -> Result<(Self, Vec), deb822_lossless::Error> { let (mut deb822, mut errors) = deb822_lossless::Deb822::read_relaxed(&mut r)?; let mut paras = deb822.paragraphs(); let para = match paras.next() { Some(para) => para, None => deb822.add_paragraph(), }; if paras.next().is_some() { errors.push("multiple paragraphs found".to_string()); } Ok((Self(para), errors)) } } impl Default for Changes { fn default() -> Self { Self::new() } } #[cfg(feature = "python-debian")] impl pyo3::ToPyObject for Changes { fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject { self.0.to_object(py) } } #[cfg(feature = "python-debian")] impl pyo3::FromPyObject<'_> for Changes { fn extract_bound(ob: &pyo3::Bound) -> pyo3::PyResult { use pyo3::prelude::*; Ok(Changes(ob.extract()?)) } } #[cfg(test)] mod tests { #[test] fn test_new() { let changes = super::Changes::new(); assert_eq!(changes.format(), Some("1.8".to_string())); } #[test] fn test_parse() { let changes = r#"Format: 1.8 Date: Fri, 08 Sep 2023 18:23:59 +0100 Source: buildlog-consultant Binary: python3-buildlog-consultant Architecture: all Version: 0.0.34-1 Distribution: unstable Urgency: medium Maintainer: Jelmer Vernooij Changed-By: Jelmer Vernooij Description: python3-buildlog-consultant - build log parser and analyser Changes: buildlog-consultant (0.0.34-1) UNRELEASED; urgency=medium . * New upstream release. * Update standards version to 4.6.2, no changes needed. Checksums-Sha1: f1657e628254428ad74542e82c253a181894e8d0 17153 buildlog-consultant_0.0.34-1_amd64.buildinfo b44493c05d014bcd59180942d0125b20ddf45d03 2550812 python3-buildlog-consultant_0.0.34-1_all.deb Checksums-Sha256: 342a5782bf6a4f282d9002f726d2cac9c689c7e0fa7f61a1b0ecbf4da7916bdb 17153 buildlog-consultant_0.0.34-1_amd64.buildinfo 7f7e5df81ee23fbbe89015edb37e04f4bb40672fa6e9b1afd4fd698e57db78fd 2550812 python3-buildlog-consultant_0.0.34-1_all.deb Files: aa83112b0f8774a573bcf0b7b5cc12cc 17153 python optional buildlog-consultant_0.0.34-1_amd64.buildinfo a55858b90fe0ca728c89c1a1132b45c5 2550812 python optional python3-buildlog-consultant_0.0.34-1_all.deb "#; let changes = super::Changes::read(changes.as_bytes()).unwrap(); assert_eq!(changes.format(), Some("1.8".to_string())); assert_eq!(changes.source(), Some("buildlog-consultant".to_string())); assert_eq!( changes.binary(), Some(vec!["python3-buildlog-consultant".to_string()]) ); assert_eq!(changes.architecture(), Some(vec!["all".to_string()])); assert_eq!(changes.version(), Some("0.0.34-1".parse().unwrap())); assert_eq!(changes.distribution(), Some("unstable".to_string())); assert_eq!(changes.urgency(), Some(crate::fields::Urgency::Medium)); assert_eq!( changes.maintainer(), Some("Jelmer Vernooij ".to_string()) ); assert_eq!( changes.changed_by(), Some("Jelmer Vernooij ".to_string()) ); assert_eq!( changes.description(), Some("python3-buildlog-consultant - build log parser and analyser".to_string()) ); assert_eq!( changes.checksums_sha1(), Some(vec![ "f1657e628254428ad74542e82c253a181894e8d0 17153 buildlog-consultant_0.0.34-1_amd64.buildinfo".parse().unwrap(), "b44493c05d014bcd59180942d0125b20ddf45d03 2550812 python3-buildlog-consultant_0.0.34-1_all.deb".parse().unwrap() ]) ); assert_eq!( changes.checksums_sha256(), Some(vec![ "342a5782bf6a4f282d9002f726d2cac9c689c7e0fa7f61a1b0ecbf4da7916bdb 17153 buildlog-consultant_0.0.34-1_amd64.buildinfo" .parse() .unwrap(), "7f7e5df81ee23fbbe89015edb37e04f4bb40672fa6e9b1afd4fd698e57db78fd 2550812 python3-buildlog-consultant_0.0.34-1_all.deb" .parse() .unwrap() ]) ); assert_eq!( changes.files(), Some(vec![ "aa83112b0f8774a573bcf0b7b5cc12cc 17153 python optional buildlog-consultant_0.0.34-1_amd64.buildinfo".parse().unwrap(), "a55858b90fe0ca728c89c1a1132b45c5 2550812 python optional python3-buildlog-consultant_0.0.34-1_all.deb".parse().unwrap() ]) ); assert_eq!( changes.get_pool_path(), Some("pool/main/b/buildlog-consultant".to_string()) ); } } debian-control-0.1.28/src/control.rs000064400000000000000000000500671046102023000154410ustar 00000000000000use crate::fields::Priority; use crate::relations::Relations; use crate::vcs::Vcs; pub struct Control(deb822_lossless::Deb822); impl Control { pub fn new() -> Self { Control(deb822_lossless::Deb822::new()) } pub fn as_mut_deb822(&mut self) -> &mut deb822_lossless::Deb822 { &mut self.0 } pub fn as_deb822(&self) -> &deb822_lossless::Deb822 { &self.0 } pub fn source(&self) -> Option { self.0 .paragraphs() .find(|p| p.get("Source").is_some()) .map(Source) } pub fn binaries(&self) -> impl Iterator { self.0 .paragraphs() .filter(|p| p.get("Package").is_some()) .map(Binary) } /// Add a new source package /// /// # Arguments /// * `name` - The name of the source package /// /// # Returns /// The newly created source package /// /// # Example /// ```rust /// use debian_control::control::Control; /// let mut control = Control::new(); /// let source = control.add_source("foo"); /// assert_eq!(source.name(), Some("foo".to_owned())); /// ``` pub fn add_source(&mut self, name: &str) -> Source { let mut p = self.0.add_paragraph(); p.insert("Source", name); self.source().unwrap() } /// Add new binary package /// /// # Arguments /// * `name` - The name of the binary package /// /// # Returns /// The newly created binary package /// /// # Example /// ```rust /// use debian_control::control::Control; /// let mut control = Control::new(); /// let binary = control.add_binary("foo"); /// assert_eq!(binary.name(), Some("foo".to_owned())); /// ``` pub fn add_binary(&mut self, name: &str) -> Binary { let mut p = self.0.add_paragraph(); p.insert("Package", name); Binary(p) } pub fn from_file>(path: P) -> Result { Ok(Control(deb822_lossless::Deb822::from_file(path)?)) } pub fn from_file_relaxed>( path: P, ) -> Result<(Self, Vec), std::io::Error> { let (control, errors) = deb822_lossless::Deb822::from_file_relaxed(path)?; Ok((Control(control), errors)) } pub fn read(mut r: R) -> Result { Ok(Control(deb822_lossless::Deb822::read(&mut r)?)) } pub fn read_relaxed( mut r: R, ) -> Result<(Self, Vec), deb822_lossless::Error> { let (control, errors) = deb822_lossless::Deb822::read_relaxed(&mut r)?; Ok((Self(control), errors)) } } impl Default for Control { fn default() -> Self { Self::new() } } impl std::str::FromStr for Control { type Err = deb822_lossless::ParseError; fn from_str(s: &str) -> Result { Ok(Control(s.parse()?)) } } pub struct Source(deb822_lossless::Paragraph); impl Source { /// The name of the source package. pub fn name(&self) -> Option { self.0.get("Source") } pub fn as_mut_deb822(&mut self) -> &mut deb822_lossless::Paragraph { &mut self.0 } pub fn as_deb822(&self) -> &deb822_lossless::Paragraph { &self.0 } pub fn set_name(&mut self, name: &str) { self.0.insert("Source", name); } /// The default section of the packages built from this source package. pub fn section(&self) -> Option { self.0.get("Section") } pub fn set_section(&mut self, section: Option<&str>) { if let Some(section) = section { self.0.insert("Section", section); } else { self.0.remove("Section"); } } /// The default priority of the packages built from this source package. pub fn priority(&self) -> Option { self.0.get("Priority").and_then(|v| v.parse().ok()) } pub fn set_priority(&mut self, priority: Option) { if let Some(priority) = priority { self.0.insert("Priority", priority.to_string().as_str()); } else { self.0.remove("Priority"); } } /// The maintainer of the package. pub fn maintainer(&self) -> Option { self.0.get("Maintainer") } pub fn set_maintainer(&mut self, maintainer: &str) { self.0.insert("Maintainer", maintainer); } /// The build dependencies of the package. pub fn build_depends(&self) -> Option { self.0.get("Build-Depends").map(|s| s.parse().unwrap()) } pub fn set_build_depends(&mut self, relations: &Relations) { self.0 .insert("Build-Depends", relations.to_string().as_str()); } pub fn build_depends_indep(&self) -> Option { self.0 .get("Build-Depends-Indep") .map(|s| s.parse().unwrap()) } pub fn build_depends_arch(&self) -> Option { self.0.get("Build-Depends-Arch").map(|s| s.parse().unwrap()) } pub fn build_conflicts(&self) -> Option { self.0.get("Build-Conflicts").map(|s| s.parse().unwrap()) } pub fn build_conflicts_indep(&self) -> Option { self.0 .get("Build-Conflicts-Indep") .map(|s| s.parse().unwrap()) } pub fn build_conflicts_arch(&self) -> Option { self.0 .get("Build-Conflicts-Arch") .map(|s| s.parse().unwrap()) } pub fn standards_version(&self) -> Option { self.0.get("Standards-Version") } pub fn set_standards_version(&mut self, version: &str) { self.0.insert("Standards-Version", version); } pub fn homepage(&self) -> Option { self.0.get("Homepage").and_then(|s| s.parse().ok()) } pub fn set_homepage(&mut self, homepage: &url::Url) { self.0.insert("Homepage", homepage.to_string().as_str()); } pub fn vcs_git(&self) -> Option { self.0.get("Vcs-Git") } pub fn set_vcs_git(&mut self, url: &str) { self.0.insert("Vcs-Git", url); } pub fn vcs_svn(&self) -> Option { self.0.get("Vcs-Svn").map(|s| s.to_string()) } pub fn set_vcs_svn(&mut self, url: &str) { self.0.insert("Vcs-Svn", url); } pub fn vcs_bzr(&self) -> Option { self.0.get("Vcs-Bzr").map(|s| s.to_string()) } pub fn set_vcs_bzr(&mut self, url: &str) { self.0.insert("Vcs-Bzr", url); } pub fn vcs_arch(&self) -> Option { self.0.get("Vcs-Arch").map(|s| s.to_string()) } pub fn set_vcs_arch(&mut self, url: &str) { self.0.insert("Vcs-Arch", url); } pub fn vcs_svk(&self) -> Option { self.0.get("Vcs-Svk").map(|s| s.to_string()) } pub fn set_vcs_svk(&mut self, url: &str) { self.0.insert("Vcs-Svk", url); } pub fn vcs_darcs(&self) -> Option { self.0.get("Vcs-Darcs").map(|s| s.to_string()) } pub fn set_vcs_darcs(&mut self, url: &str) { self.0.insert("Vcs-Darcs", url); } pub fn vcs_mtn(&self) -> Option { self.0.get("Vcs-Mtn").map(|s| s.to_string()) } pub fn set_vcs_mtn(&mut self, url: &str) { self.0.insert("Vcs-Mtn", url); } pub fn vcs_cvs(&self) -> Option { self.0.get("Vcs-Cvs").map(|s| s.to_string()) } pub fn set_vcs_cvs(&mut self, url: &str) { self.0.insert("Vcs-Cvs", url); } pub fn vcs_hg(&self) -> Option { self.0.get("Vcs-Hg").map(|s| s.to_string()) } pub fn set_vcs_hg(&mut self, url: &str) { self.0.insert("Vcs-Hg", url); } pub fn vcs_browser(&self) -> Option { self.0.get("Vcs-Browser") } pub fn set_vcs_browser(&mut self, url: Option<&str>) { if let Some(url) = url { self.0.insert("Vcs-Browser", url); } else { self.0.remove("Vcs-Browser"); } } pub fn uploaders(&self) -> Option> { self.0 .get("Uploaders") .map(|s| s.split(',').map(|s| s.trim().to_owned()).collect()) } pub fn set_uploaders(&mut self, uploaders: &[&str]) { self.0.insert( "Uploaders", uploaders .iter() .map(|s| s.to_string()) .collect::>() .join(", ") .as_str(), ); } pub fn architecture(&self) -> Option { self.0.get("Architecture") } pub fn set_architecture(&mut self, arch: Option<&str>) { if let Some(arch) = arch { self.0.insert("Architecture", arch); } else { self.0.remove("Architecture"); } } pub fn rules_requires_root(&self) -> Option { self.0 .get("Rules-Requires-Root") .map(|s| match s.to_lowercase().as_str() { "yes" => true, "no" => false, _ => panic!("invalid Rules-Requires-Root value"), }) } pub fn testsuite(&self) -> Option { self.0.get("Testsuite") } pub fn set_testsuite(&mut self, testsuite: &str) { self.0.insert("Testsuite", testsuite); } } #[cfg(feature = "python-debian")] impl pyo3::ToPyObject for Source { fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject { self.0.to_object(py) } } #[cfg(feature = "python-debian")] impl pyo3::FromPyObject<'_> for Source { fn extract_bound(ob: &pyo3::Bound) -> pyo3::PyResult { use pyo3::prelude::*; Ok(Source(ob.extract()?)) } } impl std::fmt::Display for Control { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { self.0.fmt(f) } } pub struct Binary(deb822_lossless::Paragraph); #[cfg(feature = "python-debian")] impl pyo3::ToPyObject for Binary { fn to_object(&self, py: pyo3::Python) -> pyo3::PyObject { self.0.to_object(py) } } #[cfg(feature = "python-debian")] impl pyo3::FromPyObject<'_> for Binary { fn extract_bound(ob: &pyo3::Bound) -> pyo3::PyResult { use pyo3::prelude::*; Ok(Binary(ob.extract()?)) } } impl Binary { pub fn as_mut_deb822(&mut self) -> &mut deb822_lossless::Paragraph { &mut self.0 } pub fn as_deb822(&self) -> &deb822_lossless::Paragraph { &self.0 } /// The name of the package. pub fn name(&self) -> Option { self.0.get("Package") } pub fn set_name(&mut self, name: &str) { self.0.insert("Package", name); } /// The section of the package. pub fn section(&self) -> Option { self.0.get("Section") } pub fn set_section(&mut self, section: Option<&str>) { if let Some(section) = section { self.0.insert("Section", section); } else { self.0.remove("Section"); } } /// The priority of the package. pub fn priority(&self) -> Option { self.0.get("Priority").and_then(|v| v.parse().ok()) } pub fn set_priority(&mut self, priority: Option) { if let Some(priority) = priority { self.0.insert("Priority", priority.to_string().as_str()); } else { self.0.remove("Priority"); } } /// The architecture of the package. pub fn architecture(&self) -> Option { self.0.get("Architecture") } pub fn set_architecture(&mut self, arch: Option<&str>) { if let Some(arch) = arch { self.0.insert("Architecture", arch); } else { self.0.remove("Architecture"); } } /// The dependencies of the package. pub fn depends(&self) -> Option { self.0.get("Depends").map(|s| s.parse().unwrap()) } pub fn set_depends(&mut self, depends: Option<&Relations>) { if let Some(depends) = depends { self.0.insert("Depends", depends.to_string().as_str()); } else { self.0.remove("Depends"); } } pub fn recommends(&self) -> Option { self.0.get("Recommends").map(|s| s.parse().unwrap()) } pub fn set_recommends(&mut self, recommends: Option<&Relations>) { if let Some(recommends) = recommends { self.0.insert("Recommends", recommends.to_string().as_str()); } else { self.0.remove("Recommends"); } } pub fn suggests(&self) -> Option { self.0.get("Suggests").map(|s| s.parse().unwrap()) } pub fn set_suggests(&mut self, suggests: Option<&Relations>) { if let Some(suggests) = suggests { self.0.insert("Suggests", suggests.to_string().as_str()); } else { self.0.remove("Suggests"); } } pub fn enhances(&self) -> Option { self.0.get("Enhances").map(|s| s.parse().unwrap()) } pub fn set_enhances(&mut self, enhances: Option<&Relations>) { if let Some(enhances) = enhances { self.0.insert("Enhances", enhances.to_string().as_str()); } else { self.0.remove("Enhances"); } } pub fn pre_depends(&self) -> Option { self.0.get("Pre-Depends").map(|s| s.parse().unwrap()) } pub fn set_pre_depends(&mut self, pre_depends: Option<&Relations>) { if let Some(pre_depends) = pre_depends { self.0 .insert("Pre-Depends", pre_depends.to_string().as_str()); } else { self.0.remove("Pre-Depends"); } } pub fn breaks(&self) -> Option { self.0.get("Breaks").map(|s| s.parse().unwrap()) } pub fn set_breaks(&mut self, breaks: Option<&Relations>) { if let Some(breaks) = breaks { self.0.insert("Breaks", breaks.to_string().as_str()); } else { self.0.remove("Breaks"); } } pub fn conflicts(&self) -> Option { self.0.get("Conflicts").map(|s| s.parse().unwrap()) } pub fn set_conflicts(&mut self, conflicts: Option<&Relations>) { if let Some(conflicts) = conflicts { self.0.insert("Conflicts", conflicts.to_string().as_str()); } else { self.0.remove("Conflicts"); } } pub fn replaces(&self) -> Option { self.0.get("Replaces").map(|s| s.parse().unwrap()) } pub fn set_replaces(&mut self, replaces: Option<&Relations>) { if let Some(replaces) = replaces { self.0.insert("Replaces", replaces.to_string().as_str()); } else { self.0.remove("Replaces"); } } pub fn provides(&self) -> Option { self.0.get("Provides").map(|s| s.parse().unwrap()) } pub fn set_provides(&mut self, provides: Option<&Relations>) { if let Some(provides) = provides { self.0.insert("Provides", provides.to_string().as_str()); } else { self.0.remove("Provides"); } } pub fn built_using(&self) -> Option { self.0.get("Built-Using").map(|s| s.parse().unwrap()) } pub fn set_built_using(&mut self, built_using: Option<&Relations>) { if let Some(built_using) = built_using { self.0 .insert("Built-Using", built_using.to_string().as_str()); } else { self.0.remove("Built-Using"); } } pub fn multi_arch(&self) -> Option { self.0.get("Multi-Arch").map(|s| s.parse().unwrap()) } pub fn set_multi_arch(&mut self, multi_arch: Option) { if let Some(multi_arch) = multi_arch { self.0.insert("Multi-Arch", multi_arch.to_string().as_str()); } else { self.0.remove("Multi-Arch"); } } pub fn essential(&self) -> bool { self.0.get("Essential").map(|s| s == "yes").unwrap_or(false) } pub fn set_essential(&mut self, essential: bool) { if essential { self.0.insert("Essential", "yes"); } else { self.0.remove("Essential"); } } /// Binary package description pub fn description(&self) -> Option { self.0.get("Description") } pub fn set_description(&mut self, description: Option<&str>) { if let Some(description) = description { self.0.insert("Description", description); } else { self.0.remove("Description"); } } pub fn homepage(&self) -> Option { self.0.get("Homepage").and_then(|s| s.parse().ok()) } pub fn set_homepage(&mut self, url: &url::Url) { self.0.insert("Homepage", url.as_str()); } } #[cfg(test)] mod tests { use super::*; use crate::relations::VersionConstraint; #[test] fn test_parse() { let control: Control = r#"Source: foo Section: libs Priority: optional Build-Depends: bar (>= 1.0.0), baz (>= 1.0.0) Homepage: https://example.com "# .parse() .unwrap(); let source = control.source().unwrap(); assert_eq!(source.name(), Some("foo".to_owned())); assert_eq!(source.section(), Some("libs".to_owned())); assert_eq!(source.priority(), Some(super::Priority::Optional)); assert_eq!( source.homepage(), Some("https://example.com".parse().unwrap()) ); let bd = source.build_depends().unwrap(); let entries = bd.entries().collect::>(); assert_eq!(entries.len(), 2); let rel = entries[0].relations().collect::>().pop().unwrap(); assert_eq!(rel.name(), "bar"); assert_eq!( rel.version(), Some(( VersionConstraint::GreaterThanEqual, "1.0.0".parse().unwrap() )) ); let rel = entries[1].relations().collect::>().pop().unwrap(); assert_eq!(rel.name(), "baz"); assert_eq!( rel.version(), Some(( VersionConstraint::GreaterThanEqual, "1.0.0".parse().unwrap() )) ); } #[test] fn test_description() { let control: Control = r#"Source: foo Package: foo Description: this is the short description And the longer one . is on the next lines "# .parse() .unwrap(); let binary = control.binaries().next().unwrap(); assert_eq!( binary.description(), Some( "this is the short description\nAnd the longer one\n.\nis on the next lines" .to_owned() ) ); } #[test] fn test_as_mut_deb822() { let mut control = Control::new(); let deb822 = control.as_mut_deb822(); let mut p = deb822.add_paragraph(); p.insert("Source", "foo"); assert_eq!(control.source().unwrap().name(), Some("foo".to_owned())); } #[test] fn test_as_deb822() { let control = Control::new(); let _deb822: &deb822_lossless::Deb822 = control.as_deb822(); } #[test] fn test_set_depends() { let mut control = Control::new(); let mut binary = control.add_binary("foo"); let relations: Relations = "bar (>= 1.0.0)".parse().unwrap(); binary.set_depends(Some(&relations)); } } #[derive(PartialEq, Eq, Debug)] pub enum MultiArch { Same, Foreign, No, Allowed, } impl std::str::FromStr for MultiArch { type Err = (); fn from_str(s: &str) -> Result { match s { "same" => Ok(MultiArch::Same), "foreign" => Ok(MultiArch::Foreign), "no" => Ok(MultiArch::No), "allowed" => Ok(MultiArch::Allowed), _ => Err(()), } } } impl std::fmt::Display for MultiArch { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(match self { MultiArch::Same => "same", MultiArch::Foreign => "foreign", MultiArch::No => "no", MultiArch::Allowed => "allowed", }) } } debian-control-0.1.28/src/fields.rs000064400000000000000000000153101046102023000152170ustar 00000000000000use std::str::FromStr; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)] pub enum Priority { Required, Important, Standard, Optional, Extra, } impl std::fmt::Display for Priority { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(match self { Priority::Required => "required", Priority::Important => "important", Priority::Standard => "standard", Priority::Optional => "optional", Priority::Extra => "extra", }) } } impl std::str::FromStr for Priority { type Err = (); fn from_str(s: &str) -> Result { match s { "required" => Ok(Priority::Required), "important" => Ok(Priority::Important), "standard" => Ok(Priority::Standard), "optional" => Ok(Priority::Optional), "extra" => Ok(Priority::Extra), _ => Err(()), } } } pub trait Checksum { fn filename(&self) -> String; fn size(&self) -> usize; } #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)] pub struct Sha1Checksum { pub sha1: String, pub size: usize, pub filename: String, } impl Checksum for Sha1Checksum { fn filename(&self) -> String { self.filename.clone() } fn size(&self) -> usize { self.size } } impl std::fmt::Display for Sha1Checksum { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{} {} {}", self.sha1, self.size, self.filename) } } impl std::str::FromStr for Sha1Checksum { type Err = (); fn from_str(s: &str) -> Result { let mut parts = s.split_whitespace(); let sha1 = parts.next().ok_or(())?; let size = parts.next().ok_or(())?.parse().map_err(|_| ())?; let filename = parts.next().ok_or(())?.to_string(); Ok(Self { sha1: sha1.to_string(), size, filename, }) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)] pub struct Sha256Checksum { pub sha256: String, pub size: usize, pub filename: String, } impl Checksum for Sha256Checksum { fn filename(&self) -> String { self.filename.clone() } fn size(&self) -> usize { self.size } } impl std::fmt::Display for Sha256Checksum { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{} {} {}", self.sha256, self.size, self.filename) } } impl std::str::FromStr for Sha256Checksum { type Err = (); fn from_str(s: &str) -> Result { let mut parts = s.split_whitespace(); let sha256 = parts.next().ok_or(())?; let size = parts.next().ok_or(())?.parse().map_err(|_| ())?; let filename = parts.next().ok_or(())?.to_string(); Ok(Self { sha256: sha256.to_string(), size, filename, }) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)] pub struct Sha512Checksum { pub sha512: String, pub size: usize, pub filename: String, } impl Checksum for Sha512Checksum { fn filename(&self) -> String { self.filename.clone() } fn size(&self) -> usize { self.size } } impl std::fmt::Display for Sha512Checksum { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{} {} {}", self.sha512, self.size, self.filename) } } impl std::str::FromStr for Sha512Checksum { type Err = (); fn from_str(s: &str) -> Result { let mut parts = s.split_whitespace(); let sha512 = parts.next().ok_or(())?; let size = parts.next().ok_or(())?.parse().map_err(|_| ())?; let filename = parts.next().ok_or(())?.to_string(); Ok(Self { sha512: sha512.to_string(), size, filename, }) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct PackageListEntry { pub package: String, pub package_type: String, pub section: String, pub priority: Priority, pub extra: std::collections::HashMap, } impl PackageListEntry { pub fn new(package: &str, package_type: &str, section: &str, priority: Priority) -> Self { Self { package: package.to_string(), package_type: package_type.to_string(), section: section.to_string(), priority, extra: std::collections::HashMap::new(), } } } impl std::fmt::Display for PackageListEntry { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( f, "{} {} {} {}", self.package, self.package_type, self.section, self.priority )?; for (k, v) in &self.extra { write!(f, " {}={}", k, v)?; } Ok(()) } } impl std::str::FromStr for PackageListEntry { type Err = (); fn from_str(s: &str) -> Result { let mut parts = s.split_whitespace(); let package = parts.next().ok_or(())?.to_string(); let package_type = parts.next().ok_or(())?.to_string(); let section = parts.next().ok_or(())?.to_string(); let priority = parts.next().ok_or(())?.parse().map_err(|_| ())?; let mut extra = std::collections::HashMap::new(); for part in parts { let mut kv = part.split('='); let k = kv.next().ok_or(())?.to_string(); let v = kv.next().ok_or(())?.to_string(); extra.insert(k, v); } Ok(Self { package, package_type, section, priority, extra, }) } } #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)] pub enum Urgency { #[default] Low, Medium, High, Emergency, Critical, } impl std::fmt::Display for Urgency { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Urgency::Low => f.write_str("low"), Urgency::Medium => f.write_str("medium"), Urgency::High => f.write_str("high"), Urgency::Emergency => f.write_str("emergency"), Urgency::Critical => f.write_str("critical"), } } } impl FromStr for Urgency { type Err = String; fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { "low" => Ok(Urgency::Low), "medium" => Ok(Urgency::Medium), "high" => Ok(Urgency::High), "emergency" => Ok(Urgency::Emergency), "critical" => Ok(Urgency::Critical), _ => Err(format!("invalid urgency: {}", s)), } } } debian-control-0.1.28/src/lib.rs000064400000000000000000000054151046102023000145240ustar 00000000000000//! Lossless parser for Debian control files. //! //! This crate provides a parser for Debian control files. It is lossless, meaning that it will //! preserve the original formatting of the file. It also provides a way to serialize the parsed //! data back to a string. //! //! # Example //! //! ```rust //! use debian_control::{Control, Priority}; //! use std::fs::File; //! //! let mut control = Control::new(); //! let mut source = control.add_source("hello"); //! source.set_section(Some("rust")); //! //! let mut binary = control.add_binary("hello"); //! binary.set_architecture(Some("amd64")); //! binary.set_priority(Some(Priority::Optional)); //! binary.set_description(Some("Hello, world!")); //! //! assert_eq!(control.to_string(), r#"Source: hello //! Section: rust //! //! Package: hello //! Architecture: amd64 //! Priority: optional //! Description: Hello, world! //! "#); //! ``` pub mod apt; pub mod changes; pub mod control; pub use control::{Binary, Control, Source}; pub mod fields; pub use fields::*; pub mod pgp; pub mod relations; pub mod vcs; #[derive(Debug, PartialEq)] pub enum ParseIdentityError { NoEmail, } impl std::fmt::Display for ParseIdentityError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { ParseIdentityError::NoEmail => write!(f, "No email found"), } } } impl std::error::Error for ParseIdentityError {} /// Parse an identity string into a name and an email address. /// /// The input string should be in the format `Name `. If the email is missing, an error is /// returned. /// /// # Example /// ``` /// use debian_control::parse_identity; /// assert_eq!(parse_identity("Joe Example "), Ok(("Joe Example", "joe@example.com"))); /// ``` /// /// # Arguments /// * `s` - The input string. /// /// # Returns /// A tuple with the name and the email address. pub fn parse_identity(s: &str) -> Result<(&str, &str), ParseIdentityError> { // Support Name and email, but ensure email contains an "@". if let Some((name, email)) = s.split_once('<') { if let Some(email) = email.strip_suffix('>') { Ok((name.trim(), email.trim())) } else { Err(ParseIdentityError::NoEmail) } } else if s.contains('@') { Ok(("", s.trim())) } else { Err(ParseIdentityError::NoEmail) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_identity() { assert_eq!( parse_identity("Joe Example "), Ok(("Joe Example", "joe@example.com")) ); assert_eq!( parse_identity("joe@example.com"), Ok(("", "joe@example.com")) ); assert_eq!(parse_identity("somebody"), Err(ParseIdentityError::NoEmail)); } } debian-control-0.1.28/src/pgp.rs000064400000000000000000000163341046102023000145460ustar 00000000000000#[derive(Debug, PartialEq, Eq)] pub enum Error { MissingPgpSignature, MissingPayload, TruncatedPgpSignature, JunkAfterPgpSignature, } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Error::MissingPgpSignature => write!(f, "missing PGP signature"), Error::TruncatedPgpSignature => write!(f, "truncated PGP signature"), Error::JunkAfterPgpSignature => write!(f, "junk after PGP signature"), Error::MissingPayload => write!(f, "missing payload"), } } } impl std::error::Error for Error {} /// Strip a PGP signature from a signed message. /// /// This function takes a signed message and returns the payload and the PGP signature. /// If the input is not a signed message, the function returns the input as the payload and `None` /// as the signature. /// /// # Arguments /// * `input` - The signed message. /// /// # Errors /// This function returns an error if the input is a signed message but the payload, PGP signature, /// or the PGP signature metadata is missing, or if there is junk after the PGP signature. /// The error indicates the reason for the failure. /// /// # Returns /// A tuple containing the payload and the PGP signature, if present. /// /// # Examples /// ``` /// let input = "-----BEGIN PGP SIGNED MESSAGE----- /// Hash: SHA256 /// /// Hello, world! /// -----BEGIN PGP SIGNATURE----- /// iQIzBAEBCAAdFiEEpyNohvPMyq0Uiif4DphATThvodkFAmbJ6swACgkQDphATThv /// odkUiw//VDVOwHGRVxpvyIjSvH0AMQmANOvolJ5EoCu1I5UG2x98UPiMV5oTNv1r /// ... /// =olY7 /// -----END PGP SIGNATURE----- /// "; /// let (output, signature) = debian_control::pgp::strip_pgp_signature(input).unwrap(); /// assert_eq!(output, "Hello, world!\n"); /// assert_eq!(signature.unwrap().len(), 136); /// ``` pub fn strip_pgp_signature(input: &str) -> Result<(String, Option), Error> { let mut lines = input.lines(); let first_line = if let Some(line) = lines.next() { line } else { return Ok((input.to_string(), None)); }; if first_line != "-----BEGIN PGP SIGNED MESSAGE-----" { return Ok((input.to_string(), None)); } // Read the metadata let mut metadata = String::new(); loop { let line = if let Some(line) = lines.next() { line } else { return Err(Error::MissingPayload); }; if line.is_empty() { break; } metadata.push_str(line); metadata.push('\n'); } let mut payload = String::new(); loop { let line = if let Some(line) = lines.next() { line } else { return Err(Error::MissingPgpSignature); }; if line == "-----BEGIN PGP SIGNATURE-----" { break; } payload.push_str(line); payload.push('\n'); } let mut signature = String::new(); loop { let line = if let Some(line) = lines.next() { line } else { return Err(Error::TruncatedPgpSignature); }; if line == "-----END PGP SIGNATURE-----" { break; } signature.push_str(line); } if let Some(_line) = lines.next() { return Err(Error::JunkAfterPgpSignature); } Ok((payload, Some(signature))) } #[cfg(test)] mod tests { #[test] fn test_strip_pgp_wrapper() { let input = include_str!("testdata/InRelease"); let (output, signature) = super::strip_pgp_signature(input).unwrap(); assert_eq!(output, r###"Origin: Debian Label: Debian Suite: experimental Codename: rc-buggy Changelogs: https://metadata.ftp-master.debian.org/changelogs/@CHANGEPATH@_changelog Date: Sat, 24 Aug 2024 14:13:49 UTC Valid-Until: Sat, 31 Aug 2024 14:13:49 UTC NotAutomatic: yes Acquire-By-Hash: yes No-Support-for-Architecture-all: Packages Architectures: all amd64 arm64 armel armhf i386 mips64el ppc64el riscv64 s390x Components: main contrib non-free-firmware non-free Description: Experimental packages - not released; use at your own risk. "###); assert_eq!(signature.as_deref(), Some(r###"iQIzBAEBCAAdFiEEpyNohvPMyq0Uiif4DphATThvodkFAmbJ6swACgkQDphATThv odkUiw//VDVOwHGRVxpvyIjSvH0AMQmANOvolJ5EoCu1I5UG2x98UPiMV5oTNv1r B79A3nb+FL2toeuHUJBN3G1WNg6xeH0vD43hGcxhCgVn6NADogv8pBEpyynn1qC0 iketp6kEiHvGMpEj4JqOUEcq2Mafq2TTf9zEqYuTr8NqL9hC/pG8YqPKT3rhPdc3 /D4/0dTT7L+wqLgVTjjNFNcmKU1ywvaWLF5b0VktZ1W6xIqnZYfHyP0iMqolrGqF +NG+igpsMuLI6JtoqoE+yKtWlaQi7pY7VB+OFroywNxEobzPgwdqz0r8pdJq8S4V CMXJqoY18KHdVd4qbU9yGr6qkqopHdMMcpvV9X1UG5xDKUb2OrdbBYttKFGuIuuM S6ZzM+26bztVXLzSra/w7gn7Qm1GluT+EncYrleAAgUvruCRrLFptDpHMAuKWKs5 OyNLh1ZUe/TrkmYGhehsVEBNmG+/HnzS7VKzLfpANHLAXthoEF9Lzqe0lPETa9NZ rSF/EfQwh8omsaBDfighU46fZJwKGSWOIz69jXrQ6YV9hBI/frUDHQUkMLBwjnVo 8hvr0s6/8hHRwNlLRW3XQuwL+wiz0qyk6u6RRudglqSyN1FwIAtTsGkERWN82au2 DY6KLpnfN7/0bIueDUWCP40Dib+eW5Y0/Z536WhNbp8C/OIKeVyJAjMEAQEIAB0W IQRMtQGQIHtHWKP3Onlu0Oe4JkPhMQUCZsnq6QAKCRBu0Oe4JkPhMUJsD/0ZTGIM oI9bzhP6NadhiNNruxLQfq/+fVx/oJbyOJy4IaYPOE0JVeqzZv/wFL/XOVXw6Gg2 V/SHe0cT+iuwdKd+8oMEYaOHQUeU8RhAguypeTdizZef3YjIL+2n4v0mLeq/jMHO a6Hyd09eUQrHedmcgViwQYOX/9/oqls0j3OGtyx1gmpIsmCxJtqsWNsXEcBLaNlm xSAp5YYa5USenFAph4VlR2sG+VdJrG/wtCj8TuDtJCA4tOML3JB5zwgnzfpLMVU6 l+WFKkSzl0f/dlMUYRtRoU9ccpWpyajMs968QsOp0lKLZ5Kq98fSXqOzKriDimpv 4WSmlLRptRgKL0J/Nc1eYRVEPnu+tBsitLdip52SLrqYcbCOErtxOLMIIbbC2HiR Q0lYYgky2TwO8bbCWhTyQIznldnSRhNE1STf5bctphNeWQE6zRFmMGyHh9pQYVNF KkmCbzHcv6EbUOp7Q7c5D/mijN8On/h9TEYU6EbbrQ1AEc+IulXukzlaLCMKJ0Tx XqsogWqW/nbOxTdudMn+qjd7gVsLtNIDKA42Csyac5Hwl9YDqgicyOMGBY88gocV 8fDXnyUhX5Es35AgO25Sh8CbISC29479o4/MdZXCGMIJEocjPx46Dy+hP1sIcFyp KYQwHDLf3TLHWF9z0lvGFYSAq1H8gOwchDISGA== =olY7 "###.replace('\n', "").as_ref())); } #[test] fn test_strip_pgp_no_pgp_signature() { let input = "Hello, world!"; let (output, signature) = super::strip_pgp_signature(input).unwrap(); assert_eq!(output, input); assert_eq!(signature, None); } #[test] fn test_strip_pgp_missing_payload() { let input = r###"-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 "###; let err = super::strip_pgp_signature(input).unwrap_err(); assert_eq!(err, super::Error::MissingPayload); } #[test] fn test_strip_pgp_missing_pgp_signature() { let input = r###"-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Hello, world! "###; let err = super::strip_pgp_signature(input).unwrap_err(); assert_eq!(err, super::Error::MissingPgpSignature); } #[test] fn test_strip_pgp_truncated_pgp_signature() { let input = r###"-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Hello, world! -----BEGIN PGP SIGNATURE----- B79A3nb+FL2toeuHUJBN3G1WNg6xeH0vD43hGcxhCgVn6NADogv8pBEpyynn1qC0 "###; let err = super::strip_pgp_signature(input).unwrap_err(); assert_eq!(err, super::Error::TruncatedPgpSignature); } #[test] fn test_strip_pgp_junk_after_pgp_signature() { let input = r###"-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Hello, world! -----BEGIN PGP SIGNATURE----- B79A3nb+FL2toeuHUJBN3G1WNg6xeH0vD43hGcxhCgVn6NADogv8pBEpyynn1qC0 -----END PGP SIGNATURE----- Junk after PGP signature "###; let err = super::strip_pgp_signature(input).unwrap_err(); assert_eq!(err, super::Error::JunkAfterPgpSignature); } } debian-control-0.1.28/src/relations.rs000064400000000000000000001503411046102023000157550ustar 00000000000000//! Parser for relationship fields like `Depends`, `Recommends`, etc. //! //! # Example //! ``` //! use debian_control::relations::{Relations, Relation, VersionConstraint}; //! //! let mut relations: Relations = r"python3-dulwich (>= 0.19.0), python3-requests, python3-urllib3 (<< 1.26.0)".parse().unwrap(); //! assert_eq!(relations.to_string(), "python3-dulwich (>= 0.19.0), python3-requests, python3-urllib3 (<< 1.26.0)"); //! assert!(relations.satisfied_by(&mut |name| { //! match name { //! "python3-dulwich" => Some("0.19.0".parse().unwrap()), //! "python3-requests" => Some("2.25.1".parse().unwrap()), //! "python3-urllib3" => Some("1.25.11".parse().unwrap()), //! _ => None //! }})); //! relations.remove(1); //! relations.get_entry(0).unwrap().get_relation(0).unwrap().set_archqual("amd64"); //! assert_eq!(relations.to_string(), "python3-dulwich:amd64 (>= 0.19.0), python3-urllib3 (<< 1.26.0)"); //! ``` use debversion::Version; use rowan::{Direction, NodeOrToken}; use std::iter::Peekable; use std::str::Chars; /// Let's start with defining all kinds of tokens and /// composite nodes. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[allow(non_camel_case_types)] #[repr(u16)] pub enum SyntaxKind { IDENT = 0, // package name COLON, // : PIPE, COMMA, // , L_PARENS, // ( R_PARENS, // ) L_BRACKET, // [ R_BRACKET, // ] NOT, // ! L_ANGLE, // < R_ANGLE, // > EQUAL, // = WHITESPACE, // whitespace NEWLINE, // newline COMMENT, // comments DOLLAR, // $ L_CURLY, R_CURLY, ERROR, // as well as errors // composite nodes ROOT, // The entire file ENTRY, // A single entry RELATION, // An alternative in a dependency ARCHQUAL, // An architecture qualifier VERSION, // A version constraint CONSTRAINT, // (">=", "<=", "=", ">>", "<<") ARCHITECTURES, PROFILES, SUBSTVAR, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum VersionConstraint { GreaterThanEqual, // >= LessThanEqual, // <= Equal, // = GreaterThan, // >> LessThan, // << } impl std::str::FromStr for VersionConstraint { type Err = ParseError; fn from_str(s: &str) -> Result { match s { ">=" => Ok(VersionConstraint::GreaterThanEqual), "<=" => Ok(VersionConstraint::LessThanEqual), "=" => Ok(VersionConstraint::Equal), ">>" => Ok(VersionConstraint::GreaterThan), "<<" => Ok(VersionConstraint::LessThan), _ => Err(ParseError(vec![format!( "Invalid version constraint: {}", s )])), } } } impl std::fmt::Display for VersionConstraint { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { VersionConstraint::GreaterThanEqual => f.write_str(">="), VersionConstraint::LessThanEqual => f.write_str("<="), VersionConstraint::Equal => f.write_str("="), VersionConstraint::GreaterThan => f.write_str(">>"), VersionConstraint::LessThan => f.write_str("<<"), } } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum BuildProfile { Enabled(String), Disabled(String), } impl std::fmt::Display for BuildProfile { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { BuildProfile::Enabled(s) => f.write_str(s), BuildProfile::Disabled(s) => write!(f, "!{}", s), } } } impl std::str::FromStr for BuildProfile { type Err = ParseError; fn from_str(s: &str) -> Result { if let Some(s) = s.strip_prefix('!') { Ok(BuildProfile::Disabled(s.to_string())) } else { Ok(BuildProfile::Enabled(s.to_string())) } } } use SyntaxKind::*; /// Convert our `SyntaxKind` into the rowan `SyntaxKind`. impl From for rowan::SyntaxKind { fn from(kind: SyntaxKind) -> Self { Self(kind as u16) } } pub struct Lexer<'a> { input: Peekable>, } impl<'a> Lexer<'a> { pub fn new(input: &'a str) -> Self { Lexer { input: input.chars().peekable(), } } fn is_whitespace(c: char) -> bool { c == ' ' || c == '\t' || c == '\r' } fn is_valid_ident_char(c: char) -> bool { c.is_ascii_alphanumeric() || c == '-' || c == '.' || c == '+' || c == '~' } fn read_while(&mut self, predicate: F) -> String where F: Fn(char) -> bool, { let mut result = String::new(); while let Some(&c) = self.input.peek() { if predicate(c) { result.push(c); self.input.next(); } else { break; } } result } fn next_token(&mut self) -> Option<(SyntaxKind, String)> { if let Some(&c) = self.input.peek() { match c { ':' => { self.input.next(); Some((SyntaxKind::COLON, ":".to_owned())) } '|' => { self.input.next(); Some((SyntaxKind::PIPE, "|".to_owned())) } ',' => { self.input.next(); Some((SyntaxKind::COMMA, ",".to_owned())) } '(' => { self.input.next(); Some((SyntaxKind::L_PARENS, "(".to_owned())) } ')' => { self.input.next(); Some((SyntaxKind::R_PARENS, ")".to_owned())) } '[' => { self.input.next(); Some((SyntaxKind::L_BRACKET, "[".to_owned())) } ']' => { self.input.next(); Some((SyntaxKind::R_BRACKET, "]".to_owned())) } '!' => { self.input.next(); Some((SyntaxKind::NOT, "!".to_owned())) } '$' => { self.input.next(); Some((SyntaxKind::DOLLAR, "$".to_owned())) } '{' => { self.input.next(); Some((SyntaxKind::L_CURLY, "{".to_owned())) } '}' => { self.input.next(); Some((SyntaxKind::R_CURLY, "}".to_owned())) } '<' => { self.input.next(); Some((SyntaxKind::L_ANGLE, "<".to_owned())) } '>' => { self.input.next(); Some((SyntaxKind::R_ANGLE, ">".to_owned())) } '=' => { self.input.next(); Some((SyntaxKind::EQUAL, "=".to_owned())) } '\n' => { self.input.next(); Some((SyntaxKind::NEWLINE, "\n".to_owned())) } _ if Self::is_whitespace(c) => { let whitespace = self.read_while(Self::is_whitespace); Some((SyntaxKind::WHITESPACE, whitespace)) } '#' => { self.input.next(); let comment = self.read_while(|c| c != '\n' && c != '\r'); Some((SyntaxKind::COMMENT, format!("#{}", comment))) } // TODO: separate handling for package names and versions? _ if Self::is_valid_ident_char(c) => { let key = self.read_while(Self::is_valid_ident_char); Some((SyntaxKind::IDENT, key)) } _ => { self.input.next(); Some((SyntaxKind::ERROR, c.to_string())) } } } else { None } } } impl Iterator for Lexer<'_> { type Item = (SyntaxKind, String); fn next(&mut self) -> Option { self.next_token() } } pub(crate) fn lex(input: &str) -> Vec<(SyntaxKind, String)> { let mut lexer = Lexer::new(input); lexer.by_ref().collect::>() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ParseError(Vec); impl std::fmt::Display for ParseError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { for err in &self.0 { writeln!(f, "{}", err)?; } Ok(()) } } impl std::error::Error for ParseError {} /// Second, implementing the `Language` trait teaches rowan to convert between /// these two SyntaxKind types, allowing for a nicer SyntaxNode API where /// "kinds" are values from our `enum SyntaxKind`, instead of plain u16 values. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] enum Lang {} impl rowan::Language for Lang { type Kind = SyntaxKind; fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind { unsafe { std::mem::transmute::(raw.0) } } fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind { kind.into() } } /// GreenNode is an immutable tree, which is cheap to change, /// but doesn't contain offsets and parent pointers. use rowan::{GreenNode, GreenToken}; /// You can construct GreenNodes by hand, but a builder /// is helpful for top-down parsers: it maintains a stack /// of currently in-progress nodes use rowan::GreenNodeBuilder; /// The parse results are stored as a "green tree". /// We'll discuss working with the results later struct Parse { green_node: GreenNode, #[allow(unused)] errors: Vec, } fn parse(text: &str, allow_substvar: bool) -> Parse { struct Parser { /// input tokens, including whitespace, /// in *reverse* order. tokens: Vec<(SyntaxKind, String)>, /// the in-progress tree. builder: GreenNodeBuilder<'static>, /// the list of syntax errors we've accumulated /// so far. errors: Vec, /// whether to allow substvars allow_substvar: bool, } impl Parser { fn parse_substvar(&mut self) { self.builder.start_node(SyntaxKind::SUBSTVAR.into()); self.bump(); if self.current() != Some(L_CURLY) { self.error(format!("expected {{ but got {:?}", self.current()).to_string()); } else { self.bump(); } loop { match self.current() { Some(IDENT) | Some(COLON) => { self.bump(); } Some(R_CURLY) => { break; } e => { self.error(format!("expected identifier or : but got {:?}", e).to_string()); } } } if self.current() != Some(R_CURLY) { self.error(format!("expected }} but got {:?}", self.current()).to_string()); } else { self.bump(); } self.builder.finish_node(); } fn parse_entry(&mut self) { self.skip_ws(); self.builder.start_node(SyntaxKind::ENTRY.into()); loop { self.parse_relation(); self.skip_ws(); match self.current() { Some(COMMA) => { break; } Some(PIPE) => { self.bump(); self.skip_ws(); } None => { break; } e => { self.builder.start_node(SyntaxKind::ERROR.into()); match self.tokens.pop() { Some((k, t)) => { self.builder.token(k.into(), t.as_str()); self.errors .push(format!("Expected comma or pipe, not {:?}", (k, t))); } None => { self.errors .push("Expected comma or pipe, got end of file".to_string()); } } self.builder.finish_node(); } } } self.builder.finish_node(); } fn error(&mut self, error: String) { self.errors.push(error); self.builder.start_node(SyntaxKind::ERROR.into()); if self.current().is_some() { self.bump(); } self.builder.finish_node(); } fn parse_relation(&mut self) { self.builder.start_node(SyntaxKind::RELATION.into()); if self.current() == Some(IDENT) { self.bump(); } else { self.error("Expected package name".to_string()); } self.skip_ws(); match self.current() { Some(COLON) => { self.builder.start_node(ARCHQUAL.into()); self.bump(); self.skip_ws(); if self.current() == Some(IDENT) { self.bump(); } else { self.error("Expected architecture name".to_string()); } self.builder.finish_node(); self.skip_ws(); } None | Some(L_PARENS) | Some(L_BRACKET) | Some(PIPE) | Some(COMMA) => {} e => { self.error(format!("Expected ':' or '|' or '[' or ',' but got {:?}", e)); } } self.skip_ws(); if self.current() == Some(L_PARENS) { self.builder.start_node(VERSION.into()); self.bump(); self.skip_ws(); self.builder.start_node(CONSTRAINT.into()); while self.current() == Some(L_ANGLE) || self.current() == Some(R_ANGLE) || self.current() == Some(EQUAL) { self.bump(); } self.builder.finish_node(); self.skip_ws(); if self.current() == Some(IDENT) { self.bump(); } else { self.error("Expected version".to_string()); } if self.current() == Some(R_PARENS) { self.bump(); } else { self.error("Expected ')'".to_string()); } self.builder.finish_node(); } self.skip_ws(); if self.current() == Some(L_BRACKET) { self.builder.start_node(ARCHITECTURES.into()); self.bump(); loop { self.skip_ws(); match self.current() { Some(NOT) => { self.bump(); } Some(IDENT) => { self.bump(); } Some(R_BRACKET) => { self.bump(); break; } _ => { self.error("Expected architecture name or '!' or ']'".to_string()); } } } self.builder.finish_node(); } self.skip_ws(); while self.current() == Some(L_ANGLE) { self.builder.start_node(PROFILES.into()); self.bump(); loop { self.skip_ws(); match self.current() { Some(IDENT) => { self.bump(); } Some(NOT) => { self.bump(); self.skip_ws(); if self.current() == Some(IDENT) { self.bump(); } else { self.error("Expected profile".to_string()); } } Some(R_ANGLE) => { self.bump(); break; } None => { self.error("Expected profile or '>'".to_string()); break; } _ => { self.error("Expected profile or '!' or '>'".to_string()); } } } self.builder.finish_node(); self.skip_ws(); } self.builder.finish_node(); } fn parse(mut self) -> Parse { self.builder.start_node(SyntaxKind::ROOT.into()); self.skip_ws(); while self.current().is_some() { match self.current() { Some(IDENT) => self.parse_entry(), Some(DOLLAR) => { if self.allow_substvar { self.parse_substvar() } else { self.error("Substvars are not allowed".to_string()); } } Some(c) => { self.error(format!("expected $ or identifier but got {:?}", c)); } None => { self.error("expected identifier but got end of file".to_string()); } } self.skip_ws(); match self.current() { Some(COMMA) => { self.bump(); } None => { break; } c => { self.error(format!("expected comma or end of file but got {:?}", c)); } } self.skip_ws(); } self.builder.finish_node(); // Turn the builder into a GreenNode Parse { green_node: self.builder.finish(), errors: self.errors, } } /// Advance one token, adding it to the current branch of the tree builder. fn bump(&mut self) { let (kind, text) = self.tokens.pop().unwrap(); self.builder.token(kind.into(), text.as_str()); } /// Peek at the first unprocessed token fn current(&self) -> Option { self.tokens.last().map(|(kind, _)| *kind) } fn skip_ws(&mut self) { while self.current() == Some(WHITESPACE) || self.current() == Some(COMMENT) || self.current() == Some(NEWLINE) { self.bump() } } } let mut tokens = lex(text); tokens.reverse(); Parser { tokens, builder: GreenNodeBuilder::new(), errors: Vec::new(), allow_substvar, } .parse() } /// To work with the parse results we need a view into the /// green tree - the Syntax tree. /// It is also immutable, like a GreenNode, /// but it contains parent pointers, offsets, and /// has identity semantics. type SyntaxNode = rowan::SyntaxNode; #[allow(unused)] type SyntaxToken = rowan::SyntaxToken; #[allow(unused)] type SyntaxElement = rowan::NodeOrToken; impl Parse { fn syntax(&self) -> SyntaxNode { SyntaxNode::new_root(self.green_node.clone()).clone_for_update() } fn root(&self) -> Relations { Relations::cast(self.syntax()).unwrap() } } macro_rules! ast_node { ($ast:ident, $kind:ident) => { #[repr(transparent)] pub struct $ast(SyntaxNode); impl $ast { #[allow(unused)] fn cast(node: SyntaxNode) -> Option { if node.kind() == $kind { Some(Self(node)) } else { None } } } impl std::fmt::Display for $ast { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0.text().to_string()) } } }; } ast_node!(Relations, ROOT); ast_node!(Entry, ENTRY); ast_node!(Relation, RELATION); ast_node!(Substvar, SUBSTVAR); impl PartialEq for Relations { fn eq(&self, other: &Self) -> bool { self.entries().collect::>() == other.entries().collect::>() } } impl PartialEq for Entry { fn eq(&self, other: &Self) -> bool { self.relations().collect::>() == other.relations().collect::>() } } impl PartialEq for Relation { fn eq(&self, other: &Self) -> bool { self.name() == other.name() && self.version() == other.version() } } impl std::fmt::Debug for Relations { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut s = f.debug_struct("Relations"); for entry in self.entries() { s.field("entry", &entry); } s.finish() } } impl std::fmt::Debug for Entry { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut s = f.debug_struct("Entry"); for relation in self.relations() { s.field("relation", &relation); } s.finish() } } impl std::fmt::Debug for Relation { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut s = f.debug_struct("Relation"); s.field("name", &self.name()); if let Some((vc, version)) = self.version() { s.field("version", &vc); s.field("version", &version); } s.finish() } } impl Relations { pub fn new() -> Self { Self::from(vec![]) } pub fn entries(&self) -> impl Iterator + '_ { self.0.children().filter_map(Entry::cast) } /// Remove the entry at the given index pub fn get_entry(&self, idx: usize) -> Option { self.entries().nth(idx) } /// Remove the entry at the given index pub fn remove(&mut self, idx: usize) { self.get_entry(idx).unwrap().remove(); } /// Insert a new entry at the given index pub fn insert(&mut self, idx: usize, entry: Entry) { let is_empty = !self.0.children_with_tokens().any(|n| n.kind() == COMMA); let (position, new_children) = if let Some(current_entry) = self.entries().nth(idx) { let to_insert: Vec> = if idx == 0 && is_empty { vec![entry.0.green().into()] } else { vec![ entry.0.green().into(), NodeOrToken::Token(GreenToken::new(COMMA.into(), ",")), NodeOrToken::Token(GreenToken::new(WHITESPACE.into(), " ")), ] }; (current_entry.0.index(), to_insert) } else { let child_count = self.0.children_with_tokens().count(); ( child_count, if idx == 0 { vec![entry.0.green().into()] } else { vec![ NodeOrToken::Token(GreenToken::new(COMMA.into(), ",")), NodeOrToken::Token(GreenToken::new(WHITESPACE.into(), " ")), entry.0.green().into(), ] }, ) }; self.0 = SyntaxNode::new_root( self.0.replace_with( self.0 .green() .splice_children(position..position, new_children), ), ) .clone_for_update(); } pub fn replace(&mut self, idx: usize, entry: Entry) { let current_entry = self.get_entry(idx).unwrap(); self.0.splice_children( current_entry.0.index()..current_entry.0.index() + 1, vec![entry.0.into()], ); } pub fn push(&mut self, entry: Entry) { let pos = self.entries().count(); self.insert(pos, entry); } pub fn substvars(&self) -> impl Iterator + '_ { self.0 .children() .filter_map(Substvar::cast) .map(|s| s.to_string()) } pub fn parse_relaxed(s: &str, allow_substvar: bool) -> (Relations, Vec) { let parse = parse(s, allow_substvar); (parse.root(), parse.errors) } pub fn satisfied_by(&self, package_version: &mut dyn FnMut(&str) -> Option) -> bool { self.entries().all(|e| e.satisfied_by(package_version)) } } impl From> for Relations { fn from(entries: Vec) -> Self { let mut builder = GreenNodeBuilder::new(); builder.start_node(ROOT.into()); for (i, entry) in entries.into_iter().enumerate() { if i > 0 { builder.token(COMMA.into(), ","); builder.token(WHITESPACE.into(), " "); } inject(&mut builder, entry.0); } builder.finish_node(); Relations(SyntaxNode::new_root(builder.finish()).clone_for_update()) } } impl From for Relations { fn from(entry: Entry) -> Self { Self::from(vec![entry]) } } impl Default for Entry { fn default() -> Self { Self::new() } } impl Entry { pub fn new() -> Self { let mut builder = GreenNodeBuilder::new(); builder.start_node(SyntaxKind::ENTRY.into()); builder.finish_node(); Entry(SyntaxNode::new_root(builder.finish()).clone_for_update()) } pub fn relations(&self) -> impl Iterator + '_ { self.0.children().filter_map(Relation::cast) } pub fn get_relation(&self, idx: usize) -> Option { self.relations().nth(idx) } /// Check if this entry is satisfied by the given package versions. /// /// # Arguments /// * `package_version` - A function that returns the version of a package. /// /// # Example /// ``` /// use debian_control::relations::Entry; /// let entry = Entry::from(vec!["samba (>= 2.0)".parse().unwrap()]); /// assert!(entry.satisfied_by(&mut |name| { /// match name { /// "samba" => Some("2.0".parse().unwrap()), /// _ => None /// }})); /// ``` pub fn satisfied_by(&self, package_version: &mut dyn FnMut(&str) -> Option) -> bool { self.relations().any(|r| { let actual = package_version(r.name().as_str()); if let Some((vc, version)) = r.version() { if let Some(actual) = actual { match vc { VersionConstraint::GreaterThanEqual => actual >= version, VersionConstraint::LessThanEqual => actual <= version, VersionConstraint::Equal => actual == version, VersionConstraint::GreaterThan => actual > version, VersionConstraint::LessThan => actual < version, } } else { false } } else { actual.is_some() } }) } /// Remove this entry pub fn remove(&mut self) { let mut removed_comma = false; let is_first = !self .0 .siblings(Direction::Prev) .skip(1) .any(|n| n.kind() == ENTRY); while let Some(n) = self.0.next_sibling_or_token() { if n.kind() == WHITESPACE || n.kind() == COMMENT || n.kind() == NEWLINE { n.detach(); } else if n.kind() == COMMA { n.detach(); removed_comma = true; break; } else { panic!("Unexpected node: {:?}", n); } } if !is_first { while let Some(n) = self.0.prev_sibling_or_token() { if n.kind() == WHITESPACE || n.kind() == NEWLINE { n.detach(); } else if !removed_comma && n.kind() == COMMA { n.detach(); break; } else { break; } } } else { while let Some(n) = self.0.next_sibling_or_token() { if n.kind() == WHITESPACE || n.kind() == NEWLINE { n.detach(); } else { break; } } } self.0.detach(); } } fn inject(builder: &mut GreenNodeBuilder, node: SyntaxNode) { builder.start_node(node.kind().into()); for child in node.children_with_tokens() { match child { rowan::NodeOrToken::Node(child) => { inject(builder, child); } rowan::NodeOrToken::Token(token) => { builder.token(token.kind().into(), token.text()); } } } builder.finish_node(); } impl From> for Entry { fn from(relations: Vec) -> Self { let mut builder = GreenNodeBuilder::new(); builder.start_node(SyntaxKind::ENTRY.into()); for (i, relation) in relations.into_iter().enumerate() { if i > 0 { builder.token(WHITESPACE.into(), " "); builder.token(COMMA.into(), "|"); builder.token(WHITESPACE.into(), " "); } inject(&mut builder, relation.0); } builder.finish_node(); Entry(SyntaxNode::new_root(builder.finish()).clone_for_update()) } } impl From for Entry { fn from(relation: Relation) -> Self { Self::from(vec![relation]) } } impl Relation { pub fn new(name: &str, version_constraint: Option<(VersionConstraint, Version)>) -> Self { let mut builder = GreenNodeBuilder::new(); builder.start_node(SyntaxKind::RELATION.into()); builder.token(IDENT.into(), name); if let Some((vc, version)) = version_constraint { builder.token(WHITESPACE.into(), " "); builder.start_node(SyntaxKind::VERSION.into()); builder.token(L_PARENS.into(), "("); builder.start_node(SyntaxKind::CONSTRAINT.into()); for c in vc.to_string().chars() { builder.token( match c { '>' => R_ANGLE.into(), '<' => L_ANGLE.into(), '=' => EQUAL.into(), _ => unreachable!(), }, c.to_string().as_str(), ); } builder.finish_node(); builder.token(WHITESPACE.into(), " "); builder.token(IDENT.into(), version.to_string().as_str()); builder.token(R_PARENS.into(), ")"); builder.finish_node(); } builder.finish_node(); Relation(SyntaxNode::new_root(builder.finish()).clone_for_update()) } /// Create a new simple relation, without any version constraints. /// /// # Example /// ``` /// use debian_control::relations::Relation; /// let relation = Relation::simple("samba"); /// assert_eq!(relation.to_string(), "samba"); /// ``` pub fn simple(name: &str) -> Self { Self::new(name, None) } /// Remove the version constraint from the relation. /// /// # Example /// ``` /// use debian_control::relations::{Relation, VersionConstraint}; /// let mut relation = Relation::new("samba", Some((VersionConstraint::GreaterThanEqual, "2.0".parse().unwrap()))); /// relation.drop_constraint(); /// assert_eq!(relation.to_string(), "samba"); /// ``` pub fn drop_constraint(&mut self) -> bool { let version_token = self.0.children().find(|n| n.kind() == VERSION); if let Some(version_token) = version_token { // Remove any whitespace before the version token while let Some(prev) = version_token.prev_sibling_or_token() { if prev.kind() == WHITESPACE || prev.kind() == NEWLINE { prev.detach(); } else { break; } } version_token.detach(); return true; } false } /// Return the name of the package in the relation. /// /// # Example /// ``` /// use debian_control::relations::Relation; /// let relation = Relation::simple("samba"); /// assert_eq!(relation.name(), "samba"); /// ``` pub fn name(&self) -> String { self.0 .children_with_tokens() .find_map(|it| match it { SyntaxElement::Token(token) if token.kind() == IDENT => Some(token), _ => None, }) .unwrap() .text() .to_string() } /// Return the archqual /// /// # Example /// ``` /// use debian_control::relations::Relation; /// let relation: Relation = "samba:any".parse().unwrap(); /// assert_eq!(relation.archqual(), Some("any".to_string())); /// ``` pub fn archqual(&self) -> Option { let archqual = self.0.children().find(|n| n.kind() == ARCHQUAL); let node = if let Some(archqual) = archqual { archqual.children_with_tokens().find_map(|it| match it { SyntaxElement::Token(token) if token.kind() == IDENT => Some(token), _ => None, }) } else { None }; node.map(|n| n.text().to_string()) } /// Set the architecture qualifier for this relation. /// /// # Example /// ``` /// use debian_control::relations::Relation; /// let mut relation = Relation::simple("samba"); /// relation.set_archqual("any"); /// assert_eq!(relation.to_string(), "samba:any"); /// ``` pub fn set_archqual(&mut self, archqual: &str) { let mut builder = GreenNodeBuilder::new(); builder.start_node(ARCHQUAL.into()); builder.token(COLON.into(), ":"); builder.token(IDENT.into(), archqual); builder.finish_node(); let node_archqual = self.0.children().find(|n| n.kind() == ARCHQUAL); if let Some(node_archqual) = node_archqual { self.0 = SyntaxNode::new_root(node_archqual.replace_with(builder.finish())) .clone_for_update(); } else { let name_node = self.0.children_with_tokens().find(|n| n.kind() == IDENT); let idx = if let Some(name_node) = name_node { name_node.index() + 1 } else { 0 }; self.0.splice_children( idx..idx, vec![SyntaxNode::new_root(builder.finish()) .clone_for_update() .into()], ); } } /// Return the version constraint and the version it is constrained to. pub fn version(&self) -> Option<(VersionConstraint, Version)> { let vc = self.0.children().find(|n| n.kind() == VERSION); let vc = vc.as_ref()?; let constraint = vc.children().find(|n| n.kind() == CONSTRAINT); let version = vc.children_with_tokens().find_map(|it| match it { SyntaxElement::Token(token) if token.kind() == IDENT => Some(token), _ => None, }); if let (Some(constraint), Some(version)) = (constraint, version) { let vc: VersionConstraint = constraint.to_string().parse().unwrap(); return Some((vc, (version.text().to_string()).parse().unwrap())); } else { None } } /// Return an iterator over the architectures for this relation pub fn architectures(&self) -> impl Iterator + '_ { let architectures = self.0.children().find(|n| n.kind() == ARCHITECTURES); let architectures = architectures.as_ref().unwrap(); architectures.children_with_tokens().filter_map(|node| { let token = node.as_token()?; if token.kind() == IDENT { Some(token.text().to_string()) } else { None } }) } /// Returns an iterator over the build profiles for this relation pub fn profiles(&self) -> impl Iterator> + '_ { let profiles = self.0.children().filter(|n| n.kind() == PROFILES); profiles.map(|profile| { // iterate over nodes separated by whitespace tokens let mut ret = vec![]; let mut current = vec![]; for token in profile.children_with_tokens() { match token.kind() { WHITESPACE | NEWLINE => { if !current.is_empty() { ret.push(current.join("").parse::().unwrap()); current = vec![]; } } L_ANGLE | R_ANGLE => {} _ => { current.push(token.to_string()); } } } if !current.is_empty() { ret.push(current.concat().parse().unwrap()); } ret }) } } impl std::str::FromStr for Relations { type Err = String; fn from_str(s: &str) -> Result { let parse = parse(s, false); if parse.errors.is_empty() { Ok(parse.root()) } else { Err(parse.errors.join("\n")) } } } impl std::str::FromStr for Entry { type Err = String; fn from_str(s: &str) -> Result { let root: Relations = s.parse()?; let mut entries = root.entries(); let entry = if let Some(entry) = entries.next() { entry } else { return Err("No entry found".to_string()); }; if entries.next().is_some() { return Err("Multiple entries found".to_string()); } Ok(entry) } } impl std::str::FromStr for Relation { type Err = String; fn from_str(s: &str) -> Result { let entry: Entry = s.parse()?; let mut relations = entry.relations(); let relation = if let Some(relation) = relations.next() { relation } else { return Err("No relation found".to_string()); }; if relations.next().is_some() { return Err("Multiple relations found".to_string()); } Ok(relation) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse() { let input = "python3-dulwich"; let parsed: Relations = input.parse().unwrap(); assert_eq!(parsed.to_string(), input); assert_eq!(parsed.entries().count(), 1); let entry = parsed.entries().next().unwrap(); assert_eq!(entry.to_string(), "python3-dulwich"); assert_eq!(entry.relations().count(), 1); let relation = entry.relations().next().unwrap(); assert_eq!(relation.to_string(), "python3-dulwich"); assert_eq!(relation.version(), None); let input = "python3-dulwich (>= 0.20.21)"; let parsed: Relations = input.parse().unwrap(); assert_eq!(parsed.to_string(), input); assert_eq!(parsed.entries().count(), 1); let entry = parsed.entries().next().unwrap(); assert_eq!(entry.to_string(), "python3-dulwich (>= 0.20.21)"); assert_eq!(entry.relations().count(), 1); let relation = entry.relations().next().unwrap(); assert_eq!(relation.to_string(), "python3-dulwich (>= 0.20.21)"); assert_eq!( relation.version(), Some(( VersionConstraint::GreaterThanEqual, "0.20.21".parse().unwrap() )) ); } #[test] fn test_multiple() { let input = "python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)"; let parsed: Relations = input.parse().unwrap(); assert_eq!(parsed.to_string(), input); assert_eq!(parsed.entries().count(), 2); let entry = parsed.entries().next().unwrap(); assert_eq!(entry.to_string(), "python3-dulwich (>= 0.20.21)"); assert_eq!(entry.relations().count(), 1); let relation = entry.relations().next().unwrap(); assert_eq!(relation.to_string(), "python3-dulwich (>= 0.20.21)"); assert_eq!( relation.version(), Some(( VersionConstraint::GreaterThanEqual, "0.20.21".parse().unwrap() )) ); let entry = parsed.entries().nth(1).unwrap(); assert_eq!(entry.to_string(), "python3-dulwich (<< 0.21)"); assert_eq!(entry.relations().count(), 1); let relation = entry.relations().next().unwrap(); assert_eq!(relation.to_string(), "python3-dulwich (<< 0.21)"); assert_eq!( relation.version(), Some((VersionConstraint::LessThan, "0.21".parse().unwrap())) ); } #[test] fn test_architectures() { let input = "python3-dulwich [amd64 arm64 armhf i386 mips mips64el mipsel ppc64el s390x]"; let parsed: Relations = input.parse().unwrap(); assert_eq!(parsed.to_string(), input); assert_eq!(parsed.entries().count(), 1); let entry = parsed.entries().next().unwrap(); assert_eq!( entry.to_string(), "python3-dulwich [amd64 arm64 armhf i386 mips mips64el mipsel ppc64el s390x]" ); assert_eq!(entry.relations().count(), 1); let relation = entry.relations().next().unwrap(); assert_eq!( relation.to_string(), "python3-dulwich [amd64 arm64 armhf i386 mips mips64el mipsel ppc64el s390x]" ); assert_eq!(relation.version(), None); assert_eq!( relation.architectures().collect::>(), vec![ "amd64", "arm64", "armhf", "i386", "mips", "mips64el", "mipsel", "ppc64el", "s390x" ] .into_iter() .map(|s| s.to_string()) .collect::>() ); } #[test] fn test_profiles() { let input = "foo (>= 1.0) [i386 arm] , bar"; let parsed: Relations = input.parse().unwrap(); assert_eq!(parsed.to_string(), input); assert_eq!(parsed.entries().count(), 2); let entry = parsed.entries().next().unwrap(); assert_eq!( entry.to_string(), "foo (>= 1.0) [i386 arm] " ); assert_eq!(entry.relations().count(), 1); let relation = entry.relations().next().unwrap(); assert_eq!( relation.to_string(), "foo (>= 1.0) [i386 arm] " ); assert_eq!( relation.version(), Some((VersionConstraint::GreaterThanEqual, "1.0".parse().unwrap())) ); assert_eq!( relation.architectures().collect::>(), vec!["i386", "arm"] .into_iter() .map(|s| s.to_string()) .collect::>() ); assert_eq!( relation.profiles().collect::>(), vec![ vec![BuildProfile::Disabled("nocheck".to_string())], vec![BuildProfile::Disabled("cross".to_string())] ] ); } #[test] fn test_substvar() { let input = "${shlibs:Depends}"; let (parsed, errors) = Relations::parse_relaxed(input, true); assert_eq!(errors, Vec::::new()); assert_eq!(parsed.to_string(), input); assert_eq!(parsed.entries().count(), 0); assert_eq!( parsed.substvars().collect::>(), vec!["${shlibs:Depends}"] ); } #[test] fn test_new() { let r = Relation::new( "samba", Some((VersionConstraint::GreaterThanEqual, "2.0".parse().unwrap())), ); assert_eq!(r.to_string(), "samba (>= 2.0)"); } #[test] fn test_drop_constraint() { let mut r = Relation::new( "samba", Some((VersionConstraint::GreaterThanEqual, "2.0".parse().unwrap())), ); r.drop_constraint(); assert_eq!(r.to_string(), "samba"); } #[test] fn test_simple() { let r = Relation::simple("samba"); assert_eq!(r.to_string(), "samba"); } #[test] fn test_remove_first_entry() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)"# .parse() .unwrap(); rels.remove(0); assert_eq!(rels.to_string(), "python3-dulwich (<< 0.21)"); } #[test] fn test_remove_last_entry() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)"# .parse() .unwrap(); rels.remove(1); assert_eq!(rels.to_string(), "python3-dulwich (>= 0.20.21)"); } #[test] fn test_remove_middle() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21), python3-dulwich (<< 0.22)"# .parse() .unwrap(); rels.remove(1); assert_eq!( rels.to_string(), "python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.22)" ); } #[test] fn test_remove_added() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21)"#.parse().unwrap(); let entry = Entry::from(vec![Relation::simple("python3-dulwich")]); rels.push(entry); rels.remove(1); assert_eq!(rels.to_string(), "python3-dulwich (>= 0.20.21)"); } #[test] fn test_push() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21)"#.parse().unwrap(); let entry = Entry::from(vec![Relation::simple("python3-dulwich")]); rels.push(entry); assert_eq!( rels.to_string(), "python3-dulwich (>= 0.20.21), python3-dulwich" ); } #[test] fn test_push_from_empty() { let mut rels: Relations = "".parse().unwrap(); let entry = Entry::from(vec![Relation::simple("python3-dulwich")]); rels.push(entry); assert_eq!(rels.to_string(), "python3-dulwich"); } #[test] fn test_insert() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)"# .parse() .unwrap(); let entry = Entry::from(vec![Relation::simple("python3-dulwich")]); rels.insert(1, entry); assert_eq!( rels.to_string(), "python3-dulwich (>= 0.20.21), python3-dulwich, python3-dulwich (<< 0.21)" ); } #[test] fn test_insert_at_start() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)"# .parse() .unwrap(); let entry = Entry::from(vec![Relation::simple("python3-dulwich")]); rels.insert(0, entry); assert_eq!( rels.to_string(), "python3-dulwich, python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)" ); } #[test] fn test_insert_after_error() { let (mut rels, errors) = Relations::parse_relaxed("@foo@, debhelper (>= 1.0)", false); assert_eq!( errors, vec![ "expected $ or identifier but got ERROR", "expected comma or end of file but got Some(IDENT)", "expected $ or identifier but got ERROR" ] ); let entry = Entry::from(vec![Relation::simple("bar")]); rels.push(entry); assert_eq!(rels.to_string(), "@foo@, debhelper (>= 1.0), bar"); } #[test] fn test_insert_before_error() { let (mut rels, errors) = Relations::parse_relaxed("debhelper (>= 1.0), @foo@, bla", false); assert_eq!( errors, vec![ "expected $ or identifier but got ERROR", "expected comma or end of file but got Some(IDENT)", "expected $ or identifier but got ERROR" ] ); let entry = Entry::from(vec![Relation::simple("bar")]); rels.insert(0, entry); assert_eq!(rels.to_string(), "bar, debhelper (>= 1.0), @foo@, bla"); } #[test] fn test_replace() { let mut rels: Relations = r#"python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)"# .parse() .unwrap(); let entry = Entry::from(vec![Relation::simple("python3-dulwich")]); rels.replace(1, entry); assert_eq!( rels.to_string(), "python3-dulwich (>= 0.20.21), python3-dulwich" ); } #[test] fn test_relation_from_entries() { let entries = vec![ Entry::from(vec![Relation::simple("python3-dulwich")]), Entry::from(vec![Relation::simple("python3-breezy")]), ]; let rels: Relations = entries.into(); assert_eq!(rels.entries().count(), 2); assert_eq!(rels.to_string(), "python3-dulwich, python3-breezy"); } #[test] fn test_entry_from_relations() { let relations = vec![ Relation::simple("python3-dulwich"), Relation::simple("python3-breezy"), ]; let entry: Entry = relations.into(); assert_eq!(entry.relations().count(), 2); assert_eq!(entry.to_string(), "python3-dulwich | python3-breezy"); } #[test] fn test_parse_entry() { let parsed: Entry = "python3-dulwich (>= 0.20.21) | bar".parse().unwrap(); assert_eq!(parsed.to_string(), "python3-dulwich (>= 0.20.21) | bar"); assert_eq!(parsed.relations().count(), 2); assert_eq!( "foo, bar".parse::().unwrap_err(), "Multiple entries found" ); assert_eq!("".parse::().unwrap_err(), "No entry found"); } #[test] fn test_parse_relation() { let parsed: Relation = "python3-dulwich (>= 0.20.21)".parse().unwrap(); assert_eq!(parsed.to_string(), "python3-dulwich (>= 0.20.21)"); assert_eq!( parsed.version(), Some(( VersionConstraint::GreaterThanEqual, "0.20.21".parse().unwrap() )) ); assert_eq!( "foo | bar".parse::().unwrap_err(), "Multiple relations found" ); assert_eq!("".parse::().unwrap_err(), "No entry found"); } #[test] fn test_special() { let parsed: Relation = "librust-breezyshim+dirty-tracker-dev:amd64 (>= 0.1.138-~~)" .parse() .unwrap(); assert_eq!( parsed.to_string(), "librust-breezyshim+dirty-tracker-dev:amd64 (>= 0.1.138-~~)" ); assert_eq!( parsed.version(), Some(( VersionConstraint::GreaterThanEqual, "0.1.138-~~".parse().unwrap() )) ); assert_eq!(parsed.archqual(), Some("amd64".to_string())); assert_eq!(parsed.name(), "librust-breezyshim+dirty-tracker-dev"); } #[test] fn test_satisfied_by() { let rels: Relations = "python3-dulwich (>= 0.20.21), python3-dulwich (<< 0.21)" .parse() .unwrap(); let mut satisfied = |name: &str| match name { "python3-dulwich" => Some("0.20.21".parse().unwrap()), _ => None, }; assert!(rels.satisfied_by(&mut satisfied)); let mut satisfied = |name: &str| match name { "python3-dulwich" => Some("0.21".parse().unwrap()), _ => None, }; assert!(!rels.satisfied_by(&mut satisfied)); let mut satisfied = |name: &str| match name { "python3-dulwich" => Some("0.20.20".parse().unwrap()), _ => None, }; assert!(!rels.satisfied_by(&mut satisfied)); } } debian-control-0.1.28/src/testdata/InRelease000064400000000000000000000041671046102023000170160ustar 00000000000000-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Origin: Debian Label: Debian Suite: experimental Codename: rc-buggy Changelogs: https://metadata.ftp-master.debian.org/changelogs/@CHANGEPATH@_changelog Date: Sat, 24 Aug 2024 14:13:49 UTC Valid-Until: Sat, 31 Aug 2024 14:13:49 UTC NotAutomatic: yes Acquire-By-Hash: yes No-Support-for-Architecture-all: Packages Architectures: all amd64 arm64 armel armhf i386 mips64el ppc64el riscv64 s390x Components: main contrib non-free-firmware non-free Description: Experimental packages - not released; use at your own risk. -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEpyNohvPMyq0Uiif4DphATThvodkFAmbJ6swACgkQDphATThv odkUiw//VDVOwHGRVxpvyIjSvH0AMQmANOvolJ5EoCu1I5UG2x98UPiMV5oTNv1r B79A3nb+FL2toeuHUJBN3G1WNg6xeH0vD43hGcxhCgVn6NADogv8pBEpyynn1qC0 iketp6kEiHvGMpEj4JqOUEcq2Mafq2TTf9zEqYuTr8NqL9hC/pG8YqPKT3rhPdc3 /D4/0dTT7L+wqLgVTjjNFNcmKU1ywvaWLF5b0VktZ1W6xIqnZYfHyP0iMqolrGqF +NG+igpsMuLI6JtoqoE+yKtWlaQi7pY7VB+OFroywNxEobzPgwdqz0r8pdJq8S4V CMXJqoY18KHdVd4qbU9yGr6qkqopHdMMcpvV9X1UG5xDKUb2OrdbBYttKFGuIuuM S6ZzM+26bztVXLzSra/w7gn7Qm1GluT+EncYrleAAgUvruCRrLFptDpHMAuKWKs5 OyNLh1ZUe/TrkmYGhehsVEBNmG+/HnzS7VKzLfpANHLAXthoEF9Lzqe0lPETa9NZ rSF/EfQwh8omsaBDfighU46fZJwKGSWOIz69jXrQ6YV9hBI/frUDHQUkMLBwjnVo 8hvr0s6/8hHRwNlLRW3XQuwL+wiz0qyk6u6RRudglqSyN1FwIAtTsGkERWN82au2 DY6KLpnfN7/0bIueDUWCP40Dib+eW5Y0/Z536WhNbp8C/OIKeVyJAjMEAQEIAB0W IQRMtQGQIHtHWKP3Onlu0Oe4JkPhMQUCZsnq6QAKCRBu0Oe4JkPhMUJsD/0ZTGIM oI9bzhP6NadhiNNruxLQfq/+fVx/oJbyOJy4IaYPOE0JVeqzZv/wFL/XOVXw6Gg2 V/SHe0cT+iuwdKd+8oMEYaOHQUeU8RhAguypeTdizZef3YjIL+2n4v0mLeq/jMHO a6Hyd09eUQrHedmcgViwQYOX/9/oqls0j3OGtyx1gmpIsmCxJtqsWNsXEcBLaNlm xSAp5YYa5USenFAph4VlR2sG+VdJrG/wtCj8TuDtJCA4tOML3JB5zwgnzfpLMVU6 l+WFKkSzl0f/dlMUYRtRoU9ccpWpyajMs968QsOp0lKLZ5Kq98fSXqOzKriDimpv 4WSmlLRptRgKL0J/Nc1eYRVEPnu+tBsitLdip52SLrqYcbCOErtxOLMIIbbC2HiR Q0lYYgky2TwO8bbCWhTyQIznldnSRhNE1STf5bctphNeWQE6zRFmMGyHh9pQYVNF KkmCbzHcv6EbUOp7Q7c5D/mijN8On/h9TEYU6EbbrQ1AEc+IulXukzlaLCMKJ0Tx XqsogWqW/nbOxTdudMn+qjd7gVsLtNIDKA42Csyac5Hwl9YDqgicyOMGBY88gocV 8fDXnyUhX5Es35AgO25Sh8CbISC29479o4/MdZXCGMIJEocjPx46Dy+hP1sIcFyp KYQwHDLf3TLHWF9z0lvGFYSAq1H8gOwchDISGA== =olY7 -----END PGP SIGNATURE----- debian-control-0.1.28/src/testdata/Release000064400000000000000000002406771046102023000165370ustar 00000000000000Origin: Debian Label: Debian Suite: testing Codename: trixie Changelogs: https://metadata.ftp-master.debian.org/changelogs/@CHANGEPATH@_changelog Date: Sat, 24 Aug 2024 14:13:49 UTC Valid-Until: Sat, 31 Aug 2024 14:13:49 UTC Acquire-By-Hash: yes No-Support-for-Architecture-all: Packages Architectures: all amd64 arm64 armel armhf Components: main contrib non-free-firmware non-free Description: Debian x.y Testing distribution - Not Released MD5Sum: b0b85eb959fdabeddfbf4fc52ce4da61 2080465 contrib/Contents-all d23c658438dea75e65bbf4a42085915c 27796 contrib/Contents-all.diff/Index fcbef407bbd6c89c9a0412ab0cd25d20 141476 contrib/Contents-all.gz d27c91a7d13ce624f5ddcbdebe5e7a6e 1948483 contrib/Contents-amd64 2fb841238891e0159aaa50c6abeffaab 27796 contrib/Contents-amd64.diff/Index a77d3091d8a29f53e98145c1b459eff8 115711 contrib/Contents-amd64.gz 4dee9181f0c9dfe945c7b43b184993f7 526340 contrib/Contents-arm64 dae4d446b4e8410fbe685728a83c8bfd 27796 contrib/Contents-arm64.diff/Index 9af9d1508a36aff28ac534569a943a01 42154 contrib/Contents-arm64.gz 36da1e4b619068dbe4d61a07229695a3 442301 contrib/Contents-armel 4a7f299080196b7359cbc22de53a3212 27796 contrib/Contents-armel.diff/Index 1014af277e0beb788bfc0724f8535960 34910 contrib/Contents-armel.gz 29646c4ec3ae516f58e246f0fe671d0d 452469 contrib/Contents-armhf 7ffe75d5b53f5d69c0e5a1d7809d8d6d 27796 contrib/Contents-armhf.diff/Index 1e7424a9c5d09fbe1f3d4e4e7c0e1298 36681 contrib/Contents-armhf.gz 2b83c1b0f589c4be30fc55d9a322597b 8742457 contrib/Contents-source 113c3d904cec530023ff3a3bcd9d0a19 27796 contrib/Contents-source.diff/Index b3758eda2055740c7c68e603d97a6f7e 622471 contrib/Contents-source.gz d41d8cd98f00b204e9800998ecf8427e 0 contrib/Contents-udeb-all 4a4dd3598707603b3f76a2378a4504aa 20 contrib/Contents-udeb-all.gz 03caf2691b7e177ac494199b3f080d09 93 contrib/Contents-udeb-amd64 444dfae8750010e40628e9f369bbeaed 68 contrib/Contents-udeb-amd64.gz 03caf2691b7e177ac494199b3f080d09 93 contrib/Contents-udeb-arm64 444dfae8750010e40628e9f369bbeaed 68 contrib/Contents-udeb-arm64.gz 03caf2691b7e177ac494199b3f080d09 93 contrib/Contents-udeb-armel 444dfae8750010e40628e9f369bbeaed 68 contrib/Contents-udeb-armel.gz 03caf2691b7e177ac494199b3f080d09 93 contrib/Contents-udeb-armhf 444dfae8750010e40628e9f369bbeaed 68 contrib/Contents-udeb-armhf.gz 6d6e2b279637538314f1d808e679e4a6 93642 contrib/binary-all/Packages afbc3b9908000f739ad498934edf7cc6 27796 contrib/binary-all/Packages.diff/Index 00d14f6d7ce7ee79d3328d46d13f9e95 27671 contrib/binary-all/Packages.gz 9edf4c3bb6fad01521093d30dade9cf8 24232 contrib/binary-all/Packages.xz 32dbe4e5d48f3b2a39ad5c1278fcb2ca 104 contrib/binary-all/Release 4bfe7a334e16b328cfb8cdf31b335cb8 222946 contrib/binary-amd64/Packages 72d1b39534af110fbbe72e7f2ed8dc1b 27796 contrib/binary-amd64/Packages.diff/Index bcd1074dcd0184d92ca839d480d021fd 61963 contrib/binary-amd64/Packages.gz 171d08776f4d169bf94f9019aba35fce 51560 contrib/binary-amd64/Packages.xz d4e4d726264e766566682aebe40ed5c8 106 contrib/binary-amd64/Release ecd619aeea278284e9c79f94866261ea 192951 contrib/binary-arm64/Packages 3d475e0756245db9ac8ac18897ddb90a 27796 contrib/binary-arm64/Packages.diff/Index 74c90521ea2485b8a74ae7f146746831 54362 contrib/binary-arm64/Packages.gz 857fb92192bf1cab24b24324c2359a6b 45580 contrib/binary-arm64/Packages.xz 934d88ee7bb19fd4ec69140722bffca9 106 contrib/binary-arm64/Release 029be45bd7ab824189adf082645bbd32 155543 contrib/binary-armel/Packages dfd8833f398bd710174e437eaae62a20 27796 contrib/binary-armel/Packages.diff/Index 1e19f476f2383eaa421501849652ebcd 44789 contrib/binary-armel/Packages.gz ba825783810f2e369012e6c5f2665992 37928 contrib/binary-armel/Packages.xz 701829e43e173aeaf907ebaa47b6262d 106 contrib/binary-armel/Release ba53d6d2df8fd9d8f253d92f3cca9dde 171104 contrib/binary-armhf/Packages af4fbb7bca0316b281d1a792da4164a9 27796 contrib/binary-armhf/Packages.diff/Index aaf1a2cfb07259f2fd3ef7483c9935b9 48612 contrib/binary-armhf/Packages.gz 51a6f75e78df5357300576f196221afc 41108 contrib/binary-armhf/Packages.xz 4a983008704063e5bb24cb5ae9a10750 106 contrib/binary-armhf/Release d2e27860ac9a025e3ea525d737fad986 107 contrib/source/Release 691460f93780d1387168ddad9d3ffb85 202905 contrib/source/Sources 7ffe1a75815308e22829c26e89104cdd 27796 contrib/source/Sources.diff/Index 636fd4f26d042cd827691097fecec495 58475 contrib/source/Sources.gz da8de87927682e9471c8e32a30f5689b 49324 contrib/source/Sources.xz 71971cdbbfdcd1167c6b8a18437f696d 551603921 main/Contents-all ad7d5077b5473798233344fa4cb3edfb 28026 main/Contents-all.diff/Index 898822ecf5a2aea1529f1e84516ec18d 35441693 main/Contents-all.gz a0b29faf7dfa63ad565e497765e87285 154336934 main/Contents-amd64 09cde7066117c4e5fa58a8150f3e9ecd 28024 main/Contents-amd64.diff/Index 96f374b73d9b14ad582867ff31aa4467 11504796 main/Contents-amd64.gz 34cb636c52f0dcf840ee2fb9cd92f3fd 150173808 main/Contents-arm64 3d04ea69010ea110180d6c771cb416c2 28024 main/Contents-arm64.diff/Index 9f1f935f05259db67b2d13c56b883197 11239982 main/Contents-arm64.gz 132e25963c571bdf206af841c6186d6d 114932206 main/Contents-armel 328522319be40dd3101b8d8e87cc8294 28024 main/Contents-armel.diff/Index 01fbd45e20ca3719bd34270a9aedef9e 9291435 main/Contents-armel.gz 902bd16af8192bc174917c5cf3e689e7 121561633 main/Contents-armhf 65fb288dc0ab6e568e9ad64839bea7a0 28024 main/Contents-armhf.diff/Index ffcad2692fcae0687fdbbb3f9a70de97 9743390 main/Contents-armhf.gz 2254c58718c24b2b6698d5fe90949a3f 832318686 main/Contents-source 40377baf42f144fc2c1c344f9610b449 28062 main/Contents-source.diff/Index c3e3df12f60ece88858ba1e6a3150b61 85139645 main/Contents-source.gz 0718e4cb0e188574e28136cf68bedf3b 155710 main/Contents-udeb-all ea69b878ac03672d9b226f5f751e3104 13562 main/Contents-udeb-all.gz 86a2686d48e014ab67654f7a7a8facdb 399316 main/Contents-udeb-amd64 f4d3451c915ac28b5090e82bd99ff6e7 30359 main/Contents-udeb-amd64.gz c02f594eb22ded127c60ccb7ec00d15b 532859 main/Contents-udeb-arm64 b0b9edd3f30f987e512d64402e95f1a4 39721 main/Contents-udeb-arm64.gz 36fd248f9dee6581749a6599ee4d4cb0 257183 main/Contents-udeb-armel 10c8dc86829e251cf464bd789664e65e 20322 main/Contents-udeb-armel.gz 541e3610c52ce16c8c26c83af5126eca 486749 main/Contents-udeb-armhf 2046dd581129f7cd7731618eda232d1c 36801 main/Contents-udeb-armhf.gz feaa82cbaa9a18ea06dec4d4818427d4 23411580 main/binary-all/Packages 20a09bf8c632b613a2defe06f021c1e3 27910 main/binary-all/Packages.diff/Index 8b92fe9489b3f9234b36603c162cc75d 5884441 main/binary-all/Packages.gz b5fc0ebbefff85a3ece69de30ff83556 4369564 main/binary-all/Packages.xz c8bfdb5a00c15cbbf7e8e413bee667fb 101 main/binary-all/Release 703fb0977dd7a5b28b174854f8194727 53593082 main/binary-amd64/Packages ae7ed5236ac5ca904ce25819f4a0fd98 27910 main/binary-amd64/Packages.diff/Index 50aa5607ab8e2e3b54a068c2f82f570b 12583046 main/binary-amd64/Packages.gz 3021114c55b13945ecdba956ee158f66 9183000 main/binary-amd64/Packages.xz 74ccfb2ce9d4955e4cff92dede081800 103 main/binary-amd64/Release 988aa1d5c14be74168d437fdef54bb58 52966151 main/binary-arm64/Packages d5d9239447e1679b85eedd32f7a458c7 27910 main/binary-arm64/Packages.diff/Index 6bc325969ae0e529cef7720f475f564b 12468227 main/binary-arm64/Packages.gz f04e8179e9c395db27c10294037095d0 9094512 main/binary-arm64/Packages.xz bc92927f1da7b92a0785a9f8e389bea6 103 main/binary-arm64/Release 1e8835ae29ce23115cb2532675c44c06 50171040 main/binary-armel/Packages ceed65e5463b31edf0e4c618714d0df7 27910 main/binary-armel/Packages.diff/Index f75605e8935c798692cc923784e57cd8 11990954 main/binary-armel/Packages.gz b762f833c192ce9ff93a80cf6f5ffc13 8714948 main/binary-armel/Packages.xz 0e79663d207a38384ddaf12b9beae94a 103 main/binary-armel/Release 183d87521ddbc5aff77cc2cacabf1007 50538157 main/binary-armhf/Packages 3b19c8c28f84c6b5a0d9cd45d398d61b 27910 main/binary-armhf/Packages.diff/Index 509e023d9650689eff5ef29371f1e39c 12066777 main/binary-armhf/Packages.gz d7784436dbafec6a53368b5f7d43ec11 8776908 main/binary-armhf/Packages.xz ce2c73c4733777c72eb7d4665e475392 103 main/binary-armhf/Release af46311522d80111fad434006158c514 58561 main/installer-amd64/20230607/images/MD5SUMS 0e1cad0ea39fd6c7be1a690d129bc2ae 78509 main/installer-amd64/20230607/images/SHA256SUMS af46311522d80111fad434006158c514 58561 main/installer-amd64/current/images/MD5SUMS 0e1cad0ea39fd6c7be1a690d129bc2ae 78509 main/installer-amd64/current/images/SHA256SUMS 3cee35c49b3e7cbb2e3d55102a1bb3ed 92659 main/installer-arm64/20230607/images/MD5SUMS c78be9d5ad82fceae09de129e49c9ec1 126815 main/installer-arm64/20230607/images/SHA256SUMS 3cee35c49b3e7cbb2e3d55102a1bb3ed 92659 main/installer-arm64/current/images/MD5SUMS c78be9d5ad82fceae09de129e49c9ec1 126815 main/installer-arm64/current/images/SHA256SUMS 15a5f3eec9d6cd2810ae28ae0e2acf7f 20336 main/installer-armel/20230607/images/MD5SUMS 53fcb32c4daff97231a17e1207713525 28412 main/installer-armel/20230607/images/SHA256SUMS 15a5f3eec9d6cd2810ae28ae0e2acf7f 20336 main/installer-armel/current/images/MD5SUMS 53fcb32c4daff97231a17e1207713525 28412 main/installer-armel/current/images/SHA256SUMS 1af6f21e61b4ff2ce7e2d7c18485b8b8 76534 main/installer-armhf/20230607/images/MD5SUMS d50a94e3a83c64c2bdded0aa73edd5b9 110082 main/installer-armhf/20230607/images/SHA256SUMS 1af6f21e61b4ff2ce7e2d7c18485b8b8 76534 main/installer-armhf/current/images/MD5SUMS d50a94e3a83c64c2bdded0aa73edd5b9 110082 main/installer-armhf/current/images/SHA256SUMS 65792a893ced0c1a566d984477351ad9 104 main/source/Release b5587eb663a0825a036c46f1ee910fa2 54636355 main/source/Sources 7f6755adc63953f46fa4fd0ebe14a11e 27910 main/source/Sources.diff/Index db1a8f1fbbd749ea473fdf5dacc26151 13382715 main/source/Sources.gz 4ad81df41b24b3f2bde26d43115b692d 9973020 main/source/Sources.xz 9194ae35cc2a6faf08014f9386ca1c4a 424664 non-free-firmware/Contents-all 3867d2cce75131d4c0f2eedf3c90abf7 10084 non-free-firmware/Contents-all.diff/Index baf9571676af5fc3146b941172114f9d 23291 non-free-firmware/Contents-all.gz 0ad1f8d555bed69e998c0700398c04ec 15889 non-free-firmware/Contents-amd64 339ddbcc351c9ba548b3d65b3288f7da 9100 non-free-firmware/Contents-amd64.diff/Index 22ab6747a3315048e127057811475758 1093 non-free-firmware/Contents-amd64.gz cbe2fc21f271a7fd14bd10d3ea45546d 1769 non-free-firmware/Contents-arm64 13ae7afe6c8bcc6ae096090a3dbf209d 5164 non-free-firmware/Contents-arm64.diff/Index 4540231021109d7d9cd23a202c303ed5 290 non-free-firmware/Contents-arm64.gz d41d8cd98f00b204e9800998ecf8427e 0 non-free-firmware/Contents-armel 4a4dd3598707603b3f76a2378a4504aa 20 non-free-firmware/Contents-armel.gz d41d8cd98f00b204e9800998ecf8427e 0 non-free-firmware/Contents-armhf 4a4dd3598707603b3f76a2378a4504aa 20 non-free-firmware/Contents-armhf.gz e390b76350fa9728d9e0562201bbdd64 221869 non-free-firmware/Contents-source f179efc96d9fc4b141ea99f2a4128356 19432 non-free-firmware/Contents-source.diff/Index f11c550f5caf63e694dd55f805660529 24074 non-free-firmware/Contents-source.gz 7b5784fff5eddb6cbb72a37c300ed5b8 29021 non-free-firmware/binary-all/Packages 20c693f7d60df0dd49a893b7c5e568f9 12052 non-free-firmware/binary-all/Packages.diff/Index 93be2e954e17c8526c7963dd239c22b0 7060 non-free-firmware/binary-all/Packages.gz 63be38ea1280bcab5769caeb55aceb60 6316 non-free-firmware/binary-all/Packages.xz bf9e4dd084f3474a59918da941bee054 114 non-free-firmware/binary-all/Release 565e6e1db4e615ef271077b171d769c1 31865 non-free-firmware/binary-amd64/Packages b48af2b96b4a25390794f53841a622ec 27796 non-free-firmware/binary-amd64/Packages.diff/Index 06d94fa809897693c43372402ec7b47c 7903 non-free-firmware/binary-amd64/Packages.gz 6eddf506b8b008028606b2ec3f43e653 7036 non-free-firmware/binary-amd64/Packages.xz dd9f569c11cbf63d072cdc576aa138b8 116 non-free-firmware/binary-amd64/Release 7058b83aa78391ca980b93055eb79656 30519 non-free-firmware/binary-arm64/Packages ab47a07e0ca186d6895f93978c57b7a4 22384 non-free-firmware/binary-arm64/Packages.diff/Index 67e8904fe75afd6446995198cfa4ac38 7429 non-free-firmware/binary-arm64/Packages.gz a6ed0ac98bb0ab93980b9545c779cc0f 6644 non-free-firmware/binary-arm64/Packages.xz ad03005cd870d2862c1e9e6fa474aa00 116 non-free-firmware/binary-arm64/Release 7b5784fff5eddb6cbb72a37c300ed5b8 29021 non-free-firmware/binary-armel/Packages 20c693f7d60df0dd49a893b7c5e568f9 12052 non-free-firmware/binary-armel/Packages.diff/Index 93be2e954e17c8526c7963dd239c22b0 7060 non-free-firmware/binary-armel/Packages.gz 63be38ea1280bcab5769caeb55aceb60 6316 non-free-firmware/binary-armel/Packages.xz 1df8ad56c60b9c3cc1ac4c896304f92a 116 non-free-firmware/binary-armel/Release 7b5784fff5eddb6cbb72a37c300ed5b8 29021 non-free-firmware/binary-armhf/Packages 20c693f7d60df0dd49a893b7c5e568f9 12052 non-free-firmware/binary-armhf/Packages.diff/Index 93be2e954e17c8526c7963dd239c22b0 7060 non-free-firmware/binary-armhf/Packages.gz 63be38ea1280bcab5769caeb55aceb60 6316 non-free-firmware/binary-armhf/Packages.xz 7d0c10c39c65de664d0e1d71c6abddf6 116 non-free-firmware/binary-armhf/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free-firmware/debian-installer/binary-all/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free-firmware/debian-installer/binary-all/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free-firmware/debian-installer/binary-all/Packages.xz bf9e4dd084f3474a59918da941bee054 114 non-free-firmware/debian-installer/binary-all/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free-firmware/debian-installer/binary-amd64/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free-firmware/debian-installer/binary-amd64/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free-firmware/debian-installer/binary-amd64/Packages.xz dd9f569c11cbf63d072cdc576aa138b8 116 non-free-firmware/debian-installer/binary-amd64/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free-firmware/debian-installer/binary-arm64/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free-firmware/debian-installer/binary-arm64/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free-firmware/debian-installer/binary-arm64/Packages.xz ad03005cd870d2862c1e9e6fa474aa00 116 non-free-firmware/debian-installer/binary-arm64/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free-firmware/debian-installer/binary-armel/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free-firmware/debian-installer/binary-armel/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free-firmware/debian-installer/binary-armel/Packages.xz 1df8ad56c60b9c3cc1ac4c896304f92a 116 non-free-firmware/debian-installer/binary-armel/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free-firmware/debian-installer/binary-armhf/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free-firmware/debian-installer/binary-armhf/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free-firmware/debian-installer/binary-armhf/Packages.xz 7d0c10c39c65de664d0e1d71c6abddf6 116 non-free-firmware/debian-installer/binary-armhf/Release eace55fa4ef2ee63ca7f4bff2ac308f9 378149 non-free-firmware/dep11/Components-amd64.yml 64f49bef8f400ffcc4253ed2e464cf6e 34379 non-free-firmware/dep11/Components-amd64.yml.gz 49c8424385788c400da3e18d4ae85c16 20616 non-free-firmware/dep11/Components-amd64.yml.xz 6bf760751071c509db8511713249727b 378149 non-free-firmware/dep11/Components-arm64.yml 3832bd91318c06d7d4f639e0a0b12ad0 34357 non-free-firmware/dep11/Components-arm64.yml.gz 3141a4fee4a54dbb851d29492dbdcbce 20796 non-free-firmware/dep11/Components-arm64.yml.xz 36b0033fc8c088461236cc7fc764c9a5 378149 non-free-firmware/dep11/Components-armel.yml 8a6032e7ec43561089a6ff5301605aab 34377 non-free-firmware/dep11/Components-armel.yml.gz f67641654b2911e2f9954f1db4deffdb 20944 non-free-firmware/dep11/Components-armel.yml.xz 6f4fb51eb636b6b724734ab34a124eb1 378149 non-free-firmware/dep11/Components-armhf.yml cb62aab07ae41d073970f284fed36a48 34513 non-free-firmware/dep11/Components-armhf.yml.gz 0ee6769a04c36174e889bd3f531e6538 20888 non-free-firmware/dep11/Components-armhf.yml.xz 0f343b0931126a20f133d67c2b018a3b 1024 non-free-firmware/dep11/icons-128x128.tar 31f6566d35ccd604be46ed5b1f813cdf 29 non-free-firmware/dep11/icons-128x128.tar.gz 0f343b0931126a20f133d67c2b018a3b 1024 non-free-firmware/dep11/icons-48x48.tar 31f6566d35ccd604be46ed5b1f813cdf 29 non-free-firmware/dep11/icons-48x48.tar.gz 0f343b0931126a20f133d67c2b018a3b 1024 non-free-firmware/dep11/icons-64x64.tar 31f6566d35ccd604be46ed5b1f813cdf 29 non-free-firmware/dep11/icons-64x64.tar.gz 42c33c4447b52487eddad5f5a4132ce6 15168 non-free-firmware/i18n/Translation-en de86d61a1193eea7695bee850e7dd0b4 5656 non-free-firmware/i18n/Translation-en.diff/Index cac34d82abed4c60c037176a3fc99cfc 4796 non-free-firmware/i18n/Translation-en.xz fab8478e9f9133fcc852ea9291e1390e 117 non-free-firmware/source/Release 32eafdfd99ac12f7c8339206bce7305e 31740 non-free-firmware/source/Sources 810518504c9ce60ddf061b86d2d6a672 27796 non-free-firmware/source/Sources.diff/Index f83099b550293dba07f40ab1ae424380 7539 non-free-firmware/source/Sources.gz d86c21d19fb2af08cb186b59e30fdff2 6948 non-free-firmware/source/Sources.xz 0c7a1f7fd5dbdbab8923e9788c1a0797 14898506 non-free/Contents-all fb51881b5113a213adffe71d1f61e91a 27910 non-free/Contents-all.diff/Index b50780b56fb7afef6a46d0e398fd04d9 785223 non-free/Contents-all.gz b7a61d8d3de75fb7ff17d6cdd9707ac4 985673 non-free/Contents-amd64 8d3b69d9b94e8eb71e4108e05523fcd9 27796 non-free/Contents-amd64.diff/Index 6542bd23232023810aaebf4f20f34186 75457 non-free/Contents-amd64.gz 51cce61c4e99d0dcbbf048cd1b7ba056 567043 non-free/Contents-arm64 67cc6012300f8d07e73dd5d2a1408a62 27796 non-free/Contents-arm64.diff/Index 7f6dfb55dd0988846c5c39f1826b7e83 44801 non-free/Contents-arm64.gz 76a2d1c13219689e32173a9979af007f 149034 non-free/Contents-armel b0bccdd7d349284b63829c0f44147c84 15988 non-free/Contents-armel.diff/Index a9890d541dbf10dc4d7403580e12ab50 14071 non-free/Contents-armel.gz 8c594023568f447990d0211b350480fe 158838 non-free/Contents-armhf c62b1b514aaf37de06b658673c257cd6 17956 non-free/Contents-armhf.diff/Index 060715b01b41bbcfbb6eaca6675f4b13 15250 non-free/Contents-armhf.gz 98390144abf7171985526e40ae949aa1 9738587 non-free/Contents-source d122eb5cfdd23978aaf9f3ee3511e38d 27796 non-free/Contents-source.diff/Index 9aea42426b4e661696a9800be725a3b5 979973 non-free/Contents-source.gz d41d8cd98f00b204e9800998ecf8427e 0 non-free/Contents-udeb-all 4a4dd3598707603b3f76a2378a4504aa 20 non-free/Contents-udeb-all.gz 13ae2f90a0b256587e69711ac552df4b 480 non-free/Contents-udeb-amd64 8ab034f4f486119a4e67766ff31caff9 114 non-free/Contents-udeb-amd64.gz 13ae2f90a0b256587e69711ac552df4b 480 non-free/Contents-udeb-arm64 8ab034f4f486119a4e67766ff31caff9 114 non-free/Contents-udeb-arm64.gz 13ae2f90a0b256587e69711ac552df4b 480 non-free/Contents-udeb-armel 8ab034f4f486119a4e67766ff31caff9 114 non-free/Contents-udeb-armel.gz 13ae2f90a0b256587e69711ac552df4b 480 non-free/Contents-udeb-armhf 8ab034f4f486119a4e67766ff31caff9 114 non-free/Contents-udeb-armhf.gz 5381d1928d7a47c9a651aac0f935aac1 220739 non-free/binary-all/Packages a83d9ad4e5c1e8a7fe1675ca84e80d29 27796 non-free/binary-all/Packages.diff/Index 7d2dad370feaad46debd2f64011983a8 52221 non-free/binary-all/Packages.gz 956a4265400bc2e7103ce82693c16919 43344 non-free/binary-all/Packages.xz 9fa14c811434e4228f7ef9efbbc6988e 105 non-free/binary-all/Release 016016d73fd38021b41018fa44deaf64 597497 non-free/binary-amd64/Packages bee087e1e21b940da7258ebf06a4bb9e 27796 non-free/binary-amd64/Packages.diff/Index 39833d498e9c80bfaaf444eba0e7d829 122578 non-free/binary-amd64/Packages.gz 050790746859a3241f6c45db66072b9c 98068 non-free/binary-amd64/Packages.xz ea5134d6f572ea57607f020ae67c1976 107 non-free/binary-amd64/Release fcb634483d3ff0e934e47fd0319e4c94 410729 non-free/binary-arm64/Packages 1d9fe04a9355e1e5f0bfb8c27d68647f 27796 non-free/binary-arm64/Packages.diff/Index dd54d77b57b97dc97826e97af8298f85 93016 non-free/binary-arm64/Packages.gz fbe21d693dc95c645ec6877b74c73038 75384 non-free/binary-arm64/Packages.xz b9d6c5c210379f7e7904e009ce1c28a8 107 non-free/binary-arm64/Release 621de080530f0f45c8d4f1e8cb72d583 270311 non-free/binary-armel/Packages f033ae6ea0c17fc5dc21dfe52996b5ff 27796 non-free/binary-armel/Packages.diff/Index 4641fb223b8aa28694b8a4d3724c186f 66160 non-free/binary-armel/Packages.gz 8691a1ee9be4c61bcff261d0aad4f684 54356 non-free/binary-armel/Packages.xz 36e00cdfe67c582bd447ccfca0a38c95 107 non-free/binary-armel/Release bdfe1332e129dab24173a4c18ff34e8b 278052 non-free/binary-armhf/Packages 5379ecc9963f43f11507754f01f1b8a5 27796 non-free/binary-armhf/Packages.diff/Index 82e4fc7d85e118b8571f3a8e91637f17 67863 non-free/binary-armhf/Packages.gz 6d5a70cb7a5e59874dcba62f5f3f07db 55888 non-free/binary-armhf/Packages.xz 1b5ddc7fd9b1bdf839046c4bad8e8093 107 non-free/binary-armhf/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-all/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-all/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-all/Packages.xz 9fa14c811434e4228f7ef9efbbc6988e 105 non-free/debian-installer/binary-all/Release 17dacb3319bd2f218eb5b6a127555b07 607 non-free/debian-installer/binary-amd64/Packages ee33ccab888693948dda49bfa9a0aa9d 413 non-free/debian-installer/binary-amd64/Packages.gz 627490e1f8e42eb77a5e7b39329a94f7 492 non-free/debian-installer/binary-amd64/Packages.xz ea5134d6f572ea57607f020ae67c1976 107 non-free/debian-installer/binary-amd64/Release 8299d446d16cc444c9ca372afe967304 607 non-free/debian-installer/binary-arm64/Packages 5b718942489a9b79b94a3c4cd1556d80 412 non-free/debian-installer/binary-arm64/Packages.gz aaa3eb73bd884cb7069d3c3da6b55049 488 non-free/debian-installer/binary-arm64/Packages.xz b9d6c5c210379f7e7904e009ce1c28a8 107 non-free/debian-installer/binary-arm64/Release ce4029302c4e0b3318a3948839286c94 607 non-free/debian-installer/binary-armel/Packages 4d4422d4f1c8e29b77e9bfc9b9ca04a4 411 non-free/debian-installer/binary-armel/Packages.gz 88b8d2e8c31683fec8042856bd6d67e1 492 non-free/debian-installer/binary-armel/Packages.xz 36e00cdfe67c582bd447ccfca0a38c95 107 non-free/debian-installer/binary-armel/Release 47d3f9d9edd558f520adaf9ae9f13794 607 non-free/debian-installer/binary-armhf/Packages 49718d429ae8180c30fcdd5d52de088e 412 non-free/debian-installer/binary-armhf/Packages.gz 466ba67dbc928098e38fd0f3f645261b 492 non-free/debian-installer/binary-armhf/Packages.xz 1b5ddc7fd9b1bdf839046c4bad8e8093 107 non-free/debian-installer/binary-armhf/Release 780772dbdf224f83bd47d5b5cf512fc2 11715 non-free/dep11/Components-amd64.yml b968d2b7a1f8effb609f4337a57888ce 3610 non-free/dep11/Components-amd64.yml.gz ded115094818816848824557e55c5c28 3492 non-free/dep11/Components-amd64.yml.xz 5533021347d4ae918fbb52ccdb3847b0 5893 non-free/dep11/Components-arm64.yml ec7f1f9487a9f657b3a67f00b08734b2 1786 non-free/dep11/Components-arm64.yml.gz fb9f2bccb176eb1cea6ec9cb2f2a363d 1844 non-free/dep11/Components-arm64.yml.xz 56797f6b44f0c4b16ded71e3672748dd 5893 non-free/dep11/Components-armel.yml 2623ddddb2d10a980b476e63090a7888 1785 non-free/dep11/Components-armel.yml.gz 176cd435d531a2559ebf2c55247c0edb 1852 non-free/dep11/Components-armel.yml.xz 1c8d1417aad04386714eadf1195654d6 5893 non-free/dep11/Components-armhf.yml 3d383d2b409bee40e760d7be4acfb1df 1785 non-free/dep11/Components-armhf.yml.gz 654f2781c7f898a5d07fa24ef4087cd2 1856 non-free/dep11/Components-armhf.yml.xz 8566e95d97a49bac96c80d3dbdac3933 7168 non-free/dep11/icons-128x128.tar 73abee5384891168658eeced4a858a50 2167 non-free/dep11/icons-128x128.tar.gz 7ba249df54febd7ff941a127b4a2460b 3072 non-free/dep11/icons-48x48.tar ed228b786f9cb3606d65b4db8d907142 578 non-free/dep11/icons-48x48.tar.gz 5bb8a5c8362b808dd96014cfb9432691 17920 non-free/dep11/icons-64x64.tar d2e2f78fa5a0c4e2c91012a21ad30506 12030 non-free/dep11/icons-64x64.tar.gz 395ead6c28cd3dccd666b852279538ca 420788 non-free/i18n/Translation-en e9c97e2e1137793ba3904f1641fc0aee 27796 non-free/i18n/Translation-en.diff/Index 22facf077dc33c6169391c5021ed4f75 67232 non-free/i18n/Translation-en.xz dfef19158c8765956e1f2c612b661e03 108 non-free/source/Release cdb1f251d9ef073b8ce9340e4cd38ba9 336581 non-free/source/Sources 2c26891786dc414788f368712690710b 27796 non-free/source/Sources.diff/Index b91f4298c4d4ef1787b6f62329159b8e 90508 non-free/source/Sources.gz 625b4e89c677374fbeb983e53e28bfef 74912 non-free/source/Sources.xz SHA256: 5d16e0c307216f55ed79ba479d6ae724131093a64834cf22992877e911b99a04 2080465 contrib/Contents-all 58cd1b5ae2df58dd55992bd8ab137b066ac423229e7471a2f981546e2b2411da 27796 contrib/Contents-all.diff/Index 5c3e40d4fa29cbc2a9e717e4a3c02e5bc6fb7b01e91c6330ca33f217075d4778 141476 contrib/Contents-all.gz e78714c19e33b69a5d6d8f3df7d3d60f2a506ea5b5c5cf94beadb3b2bf99ebcd 1948483 contrib/Contents-amd64 dae8f0998246e1aa983dcf9c539187fb9bd0f318304f309eda9970af1f0d4678 27796 contrib/Contents-amd64.diff/Index 1ed6166c0507c8c9b480ae828fdc795e5baa9fbf5bec625f7b10cbf3d92c4dc1 115711 contrib/Contents-amd64.gz 4f71a18b95d112e448bc7476e3e2fa8bd7c9338e8233019f1213b5bc336d16db 526340 contrib/Contents-arm64 f7a9d0c9c265990e81890f0671de5ad2bff73f25060f0bf86ffcaf51ede383c9 27796 contrib/Contents-arm64.diff/Index 47d37fcbe570e18276200e78c1c8d16f8d791d1cd4fbae368bca97f3e9f7b839 42154 contrib/Contents-arm64.gz f63d6b2b52d0059b8ebb0f11b3b0fb6f012d90d011068bfdfb0b0e46e297bea8 442301 contrib/Contents-armel f9c3977609cbe2a9cc6fe40154b8996f6ed18c0d76b4c34dc8c57cea07167a54 27796 contrib/Contents-armel.diff/Index c538e15f8052037e3ca5b849fe7deb6798b65aaa2972b054d7766d23148f621e 34910 contrib/Contents-armel.gz 20061c547f1f987e475235644b3aef09f176b50c9e8e29c560ac759c28c78e7f 452469 contrib/Contents-armhf 877c042908bfac2fcf8be9c42dc22f47a5a7390511d048b882e9c4a8e3f745b6 27796 contrib/Contents-armhf.diff/Index 971face04d23a57b2665d495ead9c2db55606db0e7abce05d699523ed9bee4b6 36681 contrib/Contents-armhf.gz b20649282476b8c8abbb9fda4335092391baf81025f96a1ebbd272d700e538a4 8742457 contrib/Contents-source cc0279dd8204c32ba62bd7aad4444d5621f5421807600face5917b9bd9badedb 27796 contrib/Contents-source.diff/Index 89e1b441e8528862e5a69607da3b4e9ce67615725f675e71af87fe2b9c2d9c89 622471 contrib/Contents-source.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/Contents-udeb-all f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/Contents-udeb-all.gz 7e37c13b45e8502eeb61994430a03aa4d1dc1da9330a2fafbd35ce5a480a2d54 93 contrib/Contents-udeb-amd64 ee4e2117297557383a81e9f37e0083632e182172fd1131005163a4b31af3c9ef 68 contrib/Contents-udeb-amd64.gz 7e37c13b45e8502eeb61994430a03aa4d1dc1da9330a2fafbd35ce5a480a2d54 93 contrib/Contents-udeb-arm64 ee4e2117297557383a81e9f37e0083632e182172fd1131005163a4b31af3c9ef 68 contrib/Contents-udeb-arm64.gz 7e37c13b45e8502eeb61994430a03aa4d1dc1da9330a2fafbd35ce5a480a2d54 93 contrib/Contents-udeb-armel ee4e2117297557383a81e9f37e0083632e182172fd1131005163a4b31af3c9ef 68 contrib/Contents-udeb-armel.gz 7e37c13b45e8502eeb61994430a03aa4d1dc1da9330a2fafbd35ce5a480a2d54 93 contrib/Contents-udeb-armhf ee4e2117297557383a81e9f37e0083632e182172fd1131005163a4b31af3c9ef 68 contrib/Contents-udeb-armhf.gz 5a6775a423d494fdf1df6ed1caa266a148e20417bf828a1d5ca61e031d1c0964 93642 contrib/binary-all/Packages 5340bc5d83c9103d6a7044b83d166df6983865b0893a2b68197b4b1bb9c94d66 27796 contrib/binary-all/Packages.diff/Index 08611fbac77aa09237320cb13f174fd6b1aa9ae06298fc2e287ccaceb43d033f 27671 contrib/binary-all/Packages.gz 6664844e872bc3f69c19727a29f138c7d13fe945294f89c087407bdf36172361 24232 contrib/binary-all/Packages.xz 0e971b6961e1dc1143f096c8bef874e122e2463839e17a38b6636dbff99d4f37 104 contrib/binary-all/Release 69b3ad9e04abb03a1054d994a35667941172a9d77e58249cc0e66a719436dc65 222946 contrib/binary-amd64/Packages 677be89198aceb5796530f748b4e6580df999c57fa65eb07cf34fa5480f675b7 27796 contrib/binary-amd64/Packages.diff/Index a608b3d490c1108d3f980384fe9c4a6507c33b8de4da11c9ad6fda43fa810820 61963 contrib/binary-amd64/Packages.gz 2202aa8e73e33b3eca391d107b139022a93afcdc20c802a15e150a8ac04ad327 51560 contrib/binary-amd64/Packages.xz 7e9be4d2fff8226af72974921fd846c814e2c745b8a4ef2c2d39b75b4a2a0ff6 106 contrib/binary-amd64/Release 58385364db9b55090160b4f21d18475f5456506f399d6783888eb50774c446c6 192951 contrib/binary-arm64/Packages b9b12490828b7486239ad22c4ce9cee0862043221126ad92df5599b9161715b7 27796 contrib/binary-arm64/Packages.diff/Index b84be1e7b2be3c36b89c4f291e68ede9b59c521f53e706cdf78f39ce826a6f5b 54362 contrib/binary-arm64/Packages.gz 97f91101755ad3f436fb38ce6d6a13a5e1a4109fb327722dac80677b5f1e2ce9 45580 contrib/binary-arm64/Packages.xz 24ede283b92c2211aeff8251b8b436907d6a1d21b92e167973c13c86e14d654b 106 contrib/binary-arm64/Release e997723d130588a42c23654314c4ab8a3a0b7f9dfba2da0a3e6e54e464501ca5 155543 contrib/binary-armel/Packages 9616421ac1492066723f95f54c2086fb5dca173770b97d9478250be5b4f8a6fe 27796 contrib/binary-armel/Packages.diff/Index 3d7d7e58f11265728ca2e152d00dc7d2b07f150ec7acac9b254d05b5b9404cfc 44789 contrib/binary-armel/Packages.gz 844a32c2914a2dfaec2d2090869277f6d7219f2961ea104448a0e8e8f84917dd 37928 contrib/binary-armel/Packages.xz ba25dae7a686bf5a5c76ccf849b22ca6edc40a991919cb56e6bc3534a7d44890 106 contrib/binary-armel/Release d134e181578a22fc3922b944e79477ea5291180cf47b2d333f4585ac9dbe1f9d 171104 contrib/binary-armhf/Packages 06795f5b53cc6aa4a20994f7cf3e16b0ebb9eedad2934b8e10cb84e95ba791b7 27796 contrib/binary-armhf/Packages.diff/Index ca85896afe82be7f3c7ca2d082446d32c5163656fa17bfca64a9b201c7f30218 48612 contrib/binary-armhf/Packages.gz 907310e0d119644db8625fef0a77a50a2b5fc301c64f65316e8e20c842166a1a 41108 contrib/binary-armhf/Packages.xz 1ffbc272438b15074afaaf2a44e0a5ecbfe1fdfbdc4a0eb06c9ac08f0fd6f229 106 contrib/binary-armhf/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-all/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-all/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-all/Packages.xz 0e971b6961e1dc1143f096c8bef874e122e2463839e17a38b6636dbff99d4f37 104 contrib/debian-installer/binary-all/Release 8a0cf75b847f5d616b9d8c8070d0c2e23ef41baa91747a4d17d9435451959e10 526 contrib/debian-installer/binary-amd64/Packages a31a153aca13f370d40f00f08583fe87915272d962eccdd80780cced4bec543f 373 contrib/debian-installer/binary-amd64/Packages.gz 70fcd0ee50d8ae68b17c1b6972ba43e3b80ea8df06141fadd73043035faba3af 448 contrib/debian-installer/binary-amd64/Packages.xz 7e9be4d2fff8226af72974921fd846c814e2c745b8a4ef2c2d39b75b4a2a0ff6 106 contrib/debian-installer/binary-amd64/Release e3125ef6890d722ac5917c161b17a940d509a2ddb33fc6e4016f48202b766674 526 contrib/debian-installer/binary-arm64/Packages 7d7e9366418daf48575a28d92ce02e91bae8b16e4a1ba731c443f54eb806585c 374 contrib/debian-installer/binary-arm64/Packages.gz 9446b92a9714b3032f2e445ded1f0b9cd85f3b3b24b11a766452af6afe928a98 448 contrib/debian-installer/binary-arm64/Packages.xz 24ede283b92c2211aeff8251b8b436907d6a1d21b92e167973c13c86e14d654b 106 contrib/debian-installer/binary-arm64/Release cb2131dd12592444e2019c920df6d0f257484890a108515eb4c7f4987cb82f83 526 contrib/debian-installer/binary-armel/Packages a68ad99d2ad71629e4f9b1311c260e29abe48bf8a5688f4818b70ed97e5081f2 376 contrib/debian-installer/binary-armel/Packages.gz c7d2a5c574d60a5e7712cba0ec7695269b0d599b4cc2f7518b3c0372c9b1e370 448 contrib/debian-installer/binary-armel/Packages.xz ba25dae7a686bf5a5c76ccf849b22ca6edc40a991919cb56e6bc3534a7d44890 106 contrib/debian-installer/binary-armel/Release a3a9c672e4626d35430999ffdabc95edee92e51f51432f6375746468bd948090 526 contrib/debian-installer/binary-armhf/Packages 038e7fb6f0c00f8aac289dea82df082eb56bd8f7ea89a02124bdaeb4e8261464 377 contrib/debian-installer/binary-armhf/Packages.gz 44b15144afd09ed42750dc8582316b5d9c4f003fe77c7721d5ddee19613bccca 452 contrib/debian-installer/binary-armhf/Packages.xz 1ffbc272438b15074afaaf2a44e0a5ecbfe1fdfbdc4a0eb06c9ac08f0fd6f229 106 contrib/debian-installer/binary-armhf/Release e2f78a7dadff9be609a0a66b1cb742fd474a6af97a102bd325499b6cad0fed2d 142026 contrib/dep11/Components-amd64.yml fed86dd3f7ea8e20645aca2fb946ac3d323add50d72f1dcd6a212374bf062c1b 29361 contrib/dep11/Components-amd64.yml.gz 65c528df08c0ec429d6981936911aee017fd262066480dfa1dfc192a65b55f4f 25012 contrib/dep11/Components-amd64.yml.xz 562b826647570b87872e161d79d2d4c678d9452160f722d504ffc0775a7bfc74 131904 contrib/dep11/Components-arm64.yml 3a94e6f226a0c124c691d9f3477bfa5f52c0da388f4ccfd7feace8555c3cb5f7 27115 contrib/dep11/Components-arm64.yml.gz bc00b59fcecb5f6c42d711179d2d592b14245928e0011b549e94bfefad4b4464 23256 contrib/dep11/Components-arm64.yml.xz 5a9622610483bbc9c8703849c9f84f63050563b4badac4c6e9625a72f2d9c631 131904 contrib/dep11/Components-armel.yml 93675fb6e8750d8d03d3d1e00fb42561bfede53a25d77274780b2f44c66e920b 26993 contrib/dep11/Components-armel.yml.gz c314f24874bd4e7fadab6e3ba42a16c07cb46b9a62e1d7dd736525a5d5232580 23212 contrib/dep11/Components-armel.yml.xz 60016e8f68ffd1fbac02ccab5b8515ef491e4a5f6dedbed286e7300f1e3840fb 131904 contrib/dep11/Components-armhf.yml cd9aa9cb0673973c06258e5598535229d2d9a77c53043124dfc55ce06e36ec25 26938 contrib/dep11/Components-armhf.yml.gz 133fad96d623e6778446c830871337716fb238140b183d74668bff4edbff1bce 23264 contrib/dep11/Components-armhf.yml.xz 80823bc610dd120a38fb33742d392053f280a9ce0bc008bd7920aa71eb43a501 305664 contrib/dep11/icons-128x128.tar 5d8123673f055e6f6b237da103fb37691129eeeaae9f3e209482e4eb944a9957 241186 contrib/dep11/icons-128x128.tar.gz b3c123dbc67d795108ae87af609a9d30d28c1694ff65ca21ae07569b017b05e7 93696 contrib/dep11/icons-48x48.tar 1b605ebe7da7025ffe82a18c612a4ed9236da721005281d7f849c366ee7a55fd 57124 contrib/dep11/icons-48x48.tar.gz 7c6be9a76f88b84211c55f62a471055fa6a67b7eca1dc9e3531aa44f16892a0b 164864 contrib/dep11/icons-64x64.tar 904592c0900befbaa03ea8e192ca5551d49960f0a9b3b4dc1d825fa613db1df9 120322 contrib/dep11/icons-64x64.tar.gz 0a7b25068eadecf95a7d68902c7abb1855958a8c092905bb237ea5550d011fa5 185090 contrib/i18n/Translation-en e40a7a43b9084eedf7313c6ae4b5c8fe7bf6deacb27479fbd2c8055b0ed2844d 27796 contrib/i18n/Translation-en.diff/Index 9d80d821ae877cfd7326efe09d8a832a4ee0e93d0fb9b23efb45818c6ead2b30 47604 contrib/i18n/Translation-en.xz 877dd77e1c38444346a1279efbb0dd5c8b86299ef9a8b4401de0216f66788444 107 contrib/source/Release d14267011636ac5b2e673f24d82e3e944ca1385441c796fcdebeb3391d7bfc6c 202905 contrib/source/Sources 357eb3a6c0f239f7b0abd243aa9678caddc60f4720a445223955b13e35c5f596 27796 contrib/source/Sources.diff/Index 81cc3aede3d3b3fc833e03073eaea2a0a95e7486eb31a0c982aff5c2e60a314a 58475 contrib/source/Sources.gz 630becee17e0fca72ea54365a092c9c188db692ab39f8c08d458fb91b43c7ec4 49324 contrib/source/Sources.xz fff22684d2404b1a9d379afb715893adec748a6aa9085a4e9f57bd0256cf004a 551603921 main/Contents-all e4b49b43795e0bd1d1873de639bb743c690556c49268c3844620572560339e14 28026 main/Contents-all.diff/Index e0367ce91bd17710c975d3720badd005a63c9380189dd08685328f1174a6caaa 35441693 main/Contents-all.gz 307f1713a24ba97f67e3e1615c4394cf499d93d9881ce616928d45a6ada46615 154336934 main/Contents-amd64 82f2452031582817a08603892d342e3c921ff512c712260471c62fd2f30dab3b 28024 main/Contents-amd64.diff/Index 29324633d64c5d9ea3bb86438d60038e49f255ae330acbe67161f164720c66fe 11504796 main/Contents-amd64.gz cfe533491a6c2a698b4a451420fa529074239caacc6c9f9b6713eea6b6d1ecd7 150173808 main/Contents-arm64 1433af0ce8d52c0ade336159ebb91b17594ec6acece17196af362322ae90fbda 28024 main/Contents-arm64.diff/Index 181f22a3355ec1e156a23c162aa759763dc3a77684532ef672da8b49c4cf44ad 11239982 main/Contents-arm64.gz 9bd256f26bccd1b40d095716ddc5b5c74aec7ad9ff747cf26c0d4c1375b6f94f 114932206 main/Contents-armel 123589ecaad7f87ba511962fdef7b9e6cac99f198cad219c9e2139755bd4fbf2 28024 main/Contents-armel.diff/Index 16c303b012e10c05c80d567e7b30fc6a6191700c4adfaa8e445e0d6ec6df729b 9291435 main/Contents-armel.gz 2debd526bf8d9df011905815c92a63502eac7840da64a0c84632fc05dfea8d1f 121561633 main/Contents-armhf 81ad94e265737d03c037f63fdb260ff5da8f869dfe1ccd86223324b27936d801 28024 main/Contents-armhf.diff/Index 74c5a3f64c077d09e6e80722a363c6a69fca771a9450212774fe0ccb51da48bc 9743390 main/Contents-armhf.gz 7350c903c753b8d1375d892d9e59dcaa2109c2f4ffddb4b6297678a73b221ee6 28062 main/Contents-source.diff/Index ce3b5eb095e01749ba339061c66f0da4fa5fadc65c4ae9aa2fc5b7e4834de9d3 85139645 main/Contents-source.gz e35e0caa6b4c100956a988ed9ad329b2d58c7e914eecdcf8b8bab22a35732048 155710 main/Contents-udeb-all e302456361961fc38beeb74082a80d7ec815cc16d45033f1f1c08fc60d777487 13562 main/Contents-udeb-all.gz f918d7d96329322180ec1a1bbbffa1e3ebd6a03bfc63eb3e2cd129fd7f7333f7 399316 main/Contents-udeb-amd64 b59d5ed83c99af81335501b19b2c828207ed3e1993e12906932ca4f65234c248 30359 main/Contents-udeb-amd64.gz 21cf822c136108bf8b09174b70833b16b99b96b1ad38da10e28dd5af11b8d52e 532859 main/Contents-udeb-arm64 1bdcffccaa62903e33fe255ec808c094b41451734a5c97a60c1e66b931265179 39721 main/Contents-udeb-arm64.gz dea5c77665c4392189977d087ce31de3acd4e74f1ae571eb024a44a2c98d97eb 257183 main/Contents-udeb-armel 31634fcc731712c59da9c6828ab9d8c99bebc22497897d14517bbdffbf413ddb 20322 main/Contents-udeb-armel.gz 257814382555189f798ee99bddd0a93d69642e841d82dde6b96528b0653acd42 486749 main/Contents-udeb-armhf d57bfe801be75374ce6816e01a6f4864b8fa2fbaaa69548b8b2d0c59039e79dd 36801 main/Contents-udeb-armhf.gz e18b9f5374b3ed4db1685f08622f1f5f1d604b299bd4ec6da84c26236da3a618 23411580 main/binary-all/Packages 7bd33b25868e8f0a8cdedc335a76d87067676e64ac808351d4521783f7d56646 27910 main/binary-all/Packages.diff/Index efd145f3a9eb666919169d7436b614e0eebdbafb4489ddda7d2954a7d61eacd8 5884441 main/binary-all/Packages.gz 1ad9520a5d7809a75ebaf777a0699b3d636eb0b410d9ee8272743c7981029875 4369564 main/binary-all/Packages.xz 72d0382efbdf0aaf86a59cf49e56a0e74eb1a9b6c840755c43d6346d9e6956ae 101 main/binary-all/Release b128f5378971205e918cffb50cc0a4b1b3f5fe10d159426507e6d4b2dde48b63 53593082 main/binary-amd64/Packages efb2df8b84f00d999383568c870ee8f3ba964d9162e0d4180c08d869946c28ef 27910 main/binary-amd64/Packages.diff/Index 7d75862c17a364e4d6cebae445cc3b381c7cce224952dd5b1ffc7a025d75f077 12583046 main/binary-amd64/Packages.gz 4bb18a56653c9fb2c98a83d3937ce8f19dd3c42504403b37ca610597cdc21c2b 9183000 main/binary-amd64/Packages.xz 440e6f0db6250a47bbb7d38357cdf8a1775084c2cd05acec6a4dd66488ceee3e 103 main/binary-amd64/Release 0ac5f71e343a38c7255a69cd6af5b75bc58c11582e33b08f4f0553132a50f870 52966151 main/binary-arm64/Packages eef031e57b0334073b218166c8d869ccef26129b02bb707809304d18fbdd084a 27910 main/binary-arm64/Packages.diff/Index bb12fe40ba28f183cbe17e6d354b0995d01bbc3e4f0edec6d743ae0af27f2965 12468227 main/binary-arm64/Packages.gz f6c786df9e0feb6cf9a5237ab75fa8044eab59a58de6776cac3476a2cba4a223 9094512 main/binary-arm64/Packages.xz b6d6f4b091589152e43700244b399d9ffed70c1b504d7f8a3bd6bd080769909c 103 main/binary-arm64/Release fd9c72af849b47a595ced0480f0ee34714f24cc72da1b00dc16d0f1acc637edd 50171040 main/binary-armel/Packages 460fc2fba52c17f1f5537588d33f57d3028034f7d83c609f654411aa44f30827 27910 main/binary-armel/Packages.diff/Index a3323e182a9a2f7bd9111bec87f69ff0c8429631f0bd74e20a0b687163d8f1e7 11990954 main/binary-armel/Packages.gz 99cc99593c31a79502b820e97a0018994f37127b004c44bba6517d9b1f097864 8714948 main/binary-armel/Packages.xz 587089c52210058730739708b6426cffaf7a5ffd60b62238ab559704620b1c08 103 main/binary-armel/Release 056667abc16ab72415045ad6a3ca1b90bb5252bc945a18454dc9bea713a6ece4 50538157 main/binary-armhf/Packages 6adb991eeb392cef1e19afe1ab661f33c82ee5e827143c542e7030a9c1bb2bee 27910 main/binary-armhf/Packages.diff/Index 6976d391def59937a3c5dc2257257c31ac38aeb8d3797c8a5f7fb70f86920e84 12066777 main/binary-armhf/Packages.gz 35aa727076c251dee0b8a2601074a0c114f8af021ba481c93e70d1fd3ad6a152 8776908 main/binary-armhf/Packages.xz e9b747c8856b1737731d70a4ec5212a3b1a7f7d762085448b297c51e47ce84f9 103 main/binary-armhf/Release 142597d1a7ce2b5a0979be547c5b9716963e086fbbef65aa5ea7d701f4312ca2 60289 main/debian-installer/binary-all/Packages b1755036e8371f37310d51cdf80647fbe98632695d168a7e91a23bc4d7f1e2ed 16308 main/debian-installer/binary-all/Packages.gz 57ff978d8bdffe83328a97dbacb9a4dfe707f23553413d4cbd76c996707ccc94 14396 main/debian-installer/binary-all/Packages.xz 72d0382efbdf0aaf86a59cf49e56a0e74eb1a9b6c840755c43d6346d9e6956ae 101 main/debian-installer/binary-all/Release 8d504b50d888424c227e42d4b07829e0db6016d72895aff3ac1ca767c34bcba0 229600 main/debian-installer/binary-amd64/Packages 6ab73425252872b827792c81e362504c9c6c9b059cbb123cdd00e7a742599897 61747 main/debian-installer/binary-amd64/Packages.gz ed668e6b883815cc9e8ba7843a7e7bc3727940e82c193984d27d094d9f4814d8 50572 main/debian-installer/binary-amd64/Packages.xz 440e6f0db6250a47bbb7d38357cdf8a1775084c2cd05acec6a4dd66488ceee3e 103 main/debian-installer/binary-amd64/Release 5dad9a5e542b1c6a708cf67049bb3d0d6bc1f99686703c73ee2388e8209a28be 223211 main/debian-installer/binary-arm64/Packages 9ccce599971d75edf3e96c68c227d2fdef2369b529de28300ef884de89ef5eed 59827 main/debian-installer/binary-arm64/Packages.gz 9c5e743795d46925224b06511c40879c0d2dd6bdebabefc7b20aab7bcb731da0 49580 main/debian-installer/binary-arm64/Packages.xz b6d6f4b091589152e43700244b399d9ffed70c1b504d7f8a3bd6bd080769909c 103 main/debian-installer/binary-arm64/Release 27f8faf6764b90e7bd2b5e1b7cfe7d15996f4171b3310dfcb3a944aa3ee42b35 192908 main/debian-installer/binary-armel/Packages 4552bdde5fec7731cf00dfcc89d3a0888e3a639782ea5ca6ac1a7b4a8662532b 54107 main/debian-installer/binary-armel/Packages.gz 525acee5dadee74d5da6fc1d6f9f0ba2bd567e871e09d9f3421a25dca57e0e22 44772 main/debian-installer/binary-armel/Packages.xz 587089c52210058730739708b6426cffaf7a5ffd60b62238ab559704620b1c08 103 main/debian-installer/binary-armel/Release 11a568c3800246c7a6999d6c836416b0c7ecee321a4549bfa557bfec6f5333b1 222069 main/debian-installer/binary-armhf/Packages 11046f6ab8d8bb81171035d241c070079dd3339af1ba226dba017bd27053c54b 60236 main/debian-installer/binary-armhf/Packages.gz 7fb306248962cb0201451d939a28c41f885b69eac873c470cde8e0642060d732 49724 main/debian-installer/binary-armhf/Packages.xz e9b747c8856b1737731d70a4ec5212a3b1a7f7d762085448b297c51e47ce84f9 103 main/debian-installer/binary-armhf/Release 937776b97fd17ad438d60191b7da132f4e64f551713f0f3ca17d8334f8c1f012 20502391 main/dep11/Components-amd64.yml d7643cb3c769b1a3696228ca6bf9c0e002b1ce8ec9f83cd373c4ac23b7297dfe 7023567 main/dep11/Components-amd64.yml.gz 462226509b4292e2497461dd064927d0fb994b47b8d12e8bd9e8ec470fc61080 4551520 main/dep11/Components-amd64.yml.xz eccc6ee2405873c3d4d18f2414531edaa36bbc2d8f15508da75d99ff06aa4b17 20458415 main/dep11/Components-arm64.yml f66906e4ce63eb8e899c2499170e8ed04687a1c0498a1072277eedf19872ad48 7006947 main/dep11/Components-arm64.yml.gz 6fdf023e9a46a83e3ce86cb34c54dcdb500f26007108ddea11831c86a28b0c7b 4546080 main/dep11/Components-arm64.yml.xz e25594a6c5be7164c5b4529713a3936415fcc2bcb2b65cde3dea9e218c96bd23 19647206 main/dep11/Components-armel.yml cf6194ec0417eb34de4674d9253fb3692ba60dd5a33b2d3c2c131c936b266f0c 6730949 main/dep11/Components-armel.yml.gz d19e1c20f7c5714d159ecee8207ae74c440f6037d1d75723884cab69a84f0a54 4368956 main/dep11/Components-armel.yml.xz 55d9a276203bea7ff27ada88cdb2ba8f9d27a4e4782d0a8f88a9ce18730f30e8 20193770 main/dep11/Components-armhf.yml 216e9d2a4f7a51d5580438f003bf20799b3021c34fc0fbabed22a1067c409973 6926970 main/dep11/Components-armhf.yml.gz 4c0cd71b721a00ddc69a44dd37eff40deb06cbff5a6a2cdd828056c7eda3a4aa 4487052 main/dep11/Components-armhf.yml.xz d1fa05147bf392a1645751aaab92b12bf5cdb5ce70afed6583db5513261d1940 12782592 main/dep11/icons-128x128.tar e28ee60357c6f274a28bd76c36c59875acd73e8918d7029bafd0561c1d3d82d9 11041869 main/dep11/icons-128x128.tar.gz a667b00658a42cbe5f61f9f2671543bc33678bcf9a0f01393d46fa65b1911c72 4970496 main/dep11/icons-48x48.tar 9f35d22243adc9ed8bb04f81e083904cffcb00d1649b651aec0b07d9cb289794 3501105 main/dep11/icons-48x48.tar.gz 1f2de15819d1b2ad8e86100a25fb5d6e1dc09357be7bb23cd7d26e735465abf0 9037312 main/dep11/icons-64x64.tar ec71519c23c89a1725ab6e03590a73bd0a5df304d8350bce0f0b8efdf23f6fdf 6917055 main/dep11/icons-64x64.tar.gz 292129c83602fa69c2b7e079c6db299bfd9ca0a9c17ae5923b88575d51d115ac 3005 main/i18n/Translation-ar cd3bfa11589dbe5e61b0a56d6dbd8e30007844fafd3c0023b9d4802e32850da5 1176 main/i18n/Translation-ar.bz2 f7473d4f6f29dca7f018faf5143900fc9b9afe23a459487c7d1ea19b85d47979 1228 main/i18n/Translation-ar.diff/Index e061ee16e4478c39875bc3d977fdd5f880a71a3ea97c9f5119ac127a4305579a 6191 main/i18n/Translation-ca ed06627194c667d774188bcf0d9b859625ec60d2098238ee3c1cd5e1c147c4f7 2673 main/i18n/Translation-ca.bz2 a6386dcfcc78287b90b6a543a7870f873ff2e2a09420b5cf55cd87e2ac615b42 997160 main/i18n/Translation-cs 6ee311f9da92580cdc1c9d87577bf71c7ff25ed324d5518ff3f6693e6d18bb7d 265164 main/i18n/Translation-cs.bz2 2aacf87b1f4357c2b7d40b04b96c77ff66057b88ad726932b62d9e9e7c682358 27796 main/i18n/Translation-cs.diff/Index c69b583d4eeb8dc7ae5f1e7bf2258b551c5a2eb1cd958c238b4850f39bd6bfdd 25724198 main/i18n/Translation-da 411ded53b0bc9d1dca40479530ccbd4829d7408ecf45d4b5f22c0f46a752d026 5379154 main/i18n/Translation-da.bz2 9737ae1b9ad54d9b49943e3d2a752c3178dfd962cf1bb6ee32562dfe31c81935 27910 main/i18n/Translation-da.diff/Index cde2e938600f2d374fd03ce83335206b970ed42f1724f780d15b1ed3f163ccea 7857864 main/i18n/Translation-de ba6d8ca4f56cefc3ef6cc44563b363523921746d06b9b797eb433bb80cdfcc0e 1689555 main/i18n/Translation-de.bz2 731f225ad5a1b0a2a224ce12c50c1d7e35a669a9f5cb23e1673a51c15907f0ba 27796 main/i18n/Translation-de.diff/Index 284169348b8bd4e0de4cc5641eeb05577e80d2bd736452e454976c052cf3cbe2 1347 main/i18n/Translation-de_DE 481a435ad350105b74c4972859c44f447b7a8b5edea0d42f6dd635792e00a461 830 main/i18n/Translation-de_DE.bz2 9f3b3bc0da0653f0ac8484024a7f77aeda681474907f3a94b8a0a0933775d14d 6257 main/i18n/Translation-el 807de361285151534654b83681415016d443e4abd1a7ba36e1e78b4ac337b973 1835 main/i18n/Translation-el.bz2 6d629004fc613dc045bf232a4f6c91529771fcf0c612c14f9aed167d3d4e7fc5 33221551 main/i18n/Translation-en 29aefe8d2faba84e030c88ca4081360cb254947598737f26f471c3a44d52170b 27910 main/i18n/Translation-en.diff/Index 78242ab2b4a28b7d053edba1e4b77bf789198fc6fa6b95f89033c4405dc67960 6119904 main/i18n/Translation-en.xz abccaeb24d409c21b94883b74785053d0f8fad3e94449078ebe92af38861bc5a 2261 main/i18n/Translation-eo 747ab457a83de3b107e25b9cc5536aea2f19e0fe1f08d5357475acea0d788fae 1196 main/i18n/Translation-eo.bz2 4bfff883e83853ddeef6f0e0dd8223d63c029a87db5ff05609cd66c4bb07e996 1188528 main/i18n/Translation-es 9da765fc60e25b76868e4263b8d4a8df0a65f4a89d98740c19d05b1ccdb13a86 274837 main/i18n/Translation-es.bz2 46a8b19753259ae083d55e2d2b528f1de30e54ba638c271894c28b9e6139501f 27796 main/i18n/Translation-es.diff/Index f78cb04d9dfe8f72e820d30b8eb2e83dac64ef26ba57e84ebf99f67eeba7397e 7582 main/i18n/Translation-eu 7c0540c325065b216de4710d3176c2011da9723732c77d3ae5af8c1254145ed0 3118 main/i18n/Translation-eu.bz2 b34ef48841bdda9281fe2f19d30f8528ac226e1e138cc200f5102d33b25b8623 1228 main/i18n/Translation-eu.diff/Index 1624cd51b51a780eaaf3b9ed2562f900e5315dd7d9ee786280397a84c08322b9 255516 main/i18n/Translation-fi c6630bfd3f85a7b49daf8cfdb80ef2a22241c5a4be7e98a6baa16f047f5a2815 67831 main/i18n/Translation-fi.bz2 9822547daf06842991fe891054b2617a861efff84c602dd052f0a5569fb1c611 27796 main/i18n/Translation-fi.diff/Index a7f00d2f4470bd47e46c2d8f52bc40a07dd5ddc67504f8098cd4987e55339be5 14321629 main/i18n/Translation-fr d92feff84af8f4bff0f736079a6974baadc2f83e04d1997365ab928794909b88 2881213 main/i18n/Translation-fr.bz2 8f5b1af077e3149f2b5d1950d5a9b07799747a2f17acec1dabc568a829e0b419 27910 main/i18n/Translation-fr.diff/Index ce1a70b1000909a09166e30d574c717f3d60ba173bb65ad65e768374dc73232d 1427 main/i18n/Translation-gl fa1eb924fc1473b81f7790ccd909de1dc274f4f266df8af544261f03e1d21079 824 main/i18n/Translation-gl.bz2 f19a00e1b60dc704794da231599c0996daf308174755d58d9d4297c39066563a 34093 main/i18n/Translation-hr 2335f30d9d91a626ce1aa388392003e89530bde116ba126b90f88b710274b5c1 4341 main/i18n/Translation-hr.bz2 3cb2ef619e7d875161d3591ad463725376fa298ba14d34c14a2696eb2afb2d2f 5656 main/i18n/Translation-hr.diff/Index c7d77b32543e3a15dcc0b2cd3ff97be494df858483db7076261100f3b6479c8b 55713 main/i18n/Translation-hu 5e0d60580a33f9203fc93a921d33d464aa7fbfadd6a8c851fa48ed076177990a 19261 main/i18n/Translation-hu.bz2 b17749ec1639238ddf781dd304f11990cdcfcb6899d25015b4ad625123b86cca 10576 main/i18n/Translation-hu.diff/Index c3e3d51b1aca0489b91f204afca10830b8d58e571c10a80202243b5b93eb4f66 3352 main/i18n/Translation-id 210703f8aed2e5878063be79391ae413e91d24a0acd45684d7652a5130a8fe41 1517 main/i18n/Translation-id.bz2 e9020ba1ade9e7f33ee7402e4f749f8540557b1773c5991f094f54aa2c609ccf 1228 main/i18n/Translation-id.diff/Index a90cccc008a62166f1825e074b784730fe245607630b54b37b89e398bac28285 27210140 main/i18n/Translation-it a929066e08d12ab7affa5cf9aee3901f423b21653ca50d8da1d46aa8afb82d24 5233545 main/i18n/Translation-it.bz2 2c54e3d97acd11f4e63cef7bc5d0a575cba8b438e8e4b0e637c15a8719ed6e52 27910 main/i18n/Translation-it.diff/Index 609e48c2f00b5c821d1a3dd61d588bbf718c1ba6d5978242bd3861c03af8d2be 4061723 main/i18n/Translation-ja d2c5bca604a0a6d6daaa0135c16ea2971e3d5036cc057a6fd656b1d9df9e40c5 696024 main/i18n/Translation-ja.bz2 c82a8352e6545421c70d27d9e60d8681fd0a5a07134a49a9da1c8b2e64809a0f 27796 main/i18n/Translation-ja.diff/Index b4d899c568ccb1a4ed95220cb16ea71a871db1d12f2a3f65f431af8738d07fca 10499 main/i18n/Translation-km 046506424d849db2b7ec9832f9cedb204b82c068da9c924b9ed33e4b736ddf8f 2153 main/i18n/Translation-km.bz2 9cc010bc7a17e3470147489077f2bd79401bb199680094164c74e05d6f42a0ae 1228 main/i18n/Translation-km.diff/Index e26e450281f2123f1e9f244611a3b00dd96dea57b7cece027e0958d67c9ec550 2762844 main/i18n/Translation-ko f45fb20d866af71e14dbfba84c383d408fd539cfcc8aefab38ad4c7af569b6bf 612492 main/i18n/Translation-ko.bz2 64037bd5ea0392864df6b2aacf6c4c5b204941780d66d6cc769617cebb99edc5 27796 main/i18n/Translation-ko.diff/Index e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/i18n/Translation-ml d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 main/i18n/Translation-ml.bz2 16be336bba03786450a43321709eca2fce7fa7b50a135a97da71e16eb5e7d60b 1193 main/i18n/Translation-nb fdec5fc00fe2d0e3c7730462f95273492d278eb8a6957c1b437969833366c217 738 main/i18n/Translation-nb.bz2 16881132cf5f20a4254f1936ed5ee1a64675d381b53ebb945790b3d7d577e976 164194 main/i18n/Translation-nl 9846d686ee3a56b63c6517c48c2ee15f106839f0d6b4c90aa87b481fc184628b 41037 main/i18n/Translation-nl.bz2 4c7ea76b3f8f4c3237b78cfe3f56a629bbc822d5b1cc0ba7a7b0d2ee6d09a5b3 27796 main/i18n/Translation-nl.diff/Index 4c29f863edc8cf2cb2a32fd0ef48577ae821b2acbe0c295cb66edd7566e02493 2788050 main/i18n/Translation-pl fc9f8ff0821db67ace529174dd4a80d2f26f3ee4588e63eabf21f4afeac19120 643116 main/i18n/Translation-pl.bz2 1e9c742afd33e3110bb32b9f9bb76dfb1b0b1f61f75f9c1d0087fe1c11519aa7 27796 main/i18n/Translation-pl.diff/Index 9d771ca0eee97779dca4e523e085eb3957a9dd7db9fed96e655129ba6f73f100 946075 main/i18n/Translation-pt 40600a6494777baadf28860b93c1f284c451a7ec29a67b5ef65a13239d230c1c 232288 main/i18n/Translation-pt.bz2 80296015448f66ee729bab18c364fd919594c65b82480b4f3f40c046d1086dc2 27796 main/i18n/Translation-pt.diff/Index 23c3b2559ec6de2697088e24485714a2039ba998f6e4499f00761b81de06837f 336 main/i18n/Translation-pt_AO a2a19c81386819c63f502f9b9778fbfd1dcd4938efd6a17660b3d9aeffc92ece 272 main/i18n/Translation-pt_AO.bz2 5a5023744e9bdae5a2a2c1bc8d2b6ff6eea1af4baae6db683d29ad8458edc587 4080960 main/i18n/Translation-pt_BR 0925038e2449998e7a64235044df17d7d47a041160c68f0c43a1de7750ebfb5d 970585 main/i18n/Translation-pt_BR.bz2 8cc74f28d5c01f85048e7f8bb9160c9d5e2b603bd4a4a202f246c5a141d74017 27796 main/i18n/Translation-pt_BR.diff/Index c90708ca8975ced4acf4be98a4ac1f5c8092fd826b4d928e35c3650e705553d4 1717 main/i18n/Translation-ro 35f2449dba7bd93e0aece908f4c4de53cc864a48c8f7aeaa5a64f67384e1bcda 982 main/i18n/Translation-ro.bz2 32afdd77edcd67097fe6b50974067d6220be991a02beb3d2a37e9ad691fb0686 2953988 main/i18n/Translation-ru 103ffd37259456fcfeaca5013a31a3a690b93a4c280273dc72c7288bdc902aa4 474345 main/i18n/Translation-ru.bz2 6f5b1d3322c579b31f3646af6bc3851903ceafdbfd38ddcc531c0578d772b3e3 27796 main/i18n/Translation-ru.diff/Index 1dc7b4579ba6db1a5baf442ebf56127f66b9b38d570aa60ba54ff62030366d5e 5441319 main/i18n/Translation-sk f4543ebd5ee07ddc415ef6c278a82d6a6537e0fe8e3a607dd40eb9d66a3eab37 1150783 main/i18n/Translation-sk.bz2 f8f80b6986a659fbbec96936326b7686aa89b3a2864882f1bc4ce28da5a1814a 27796 main/i18n/Translation-sk.diff/Index 0b3dfcf4bd2fa3e676c48101f18f9f66332c9c8d98b65e1f86b2c739801b8033 297825 main/i18n/Translation-sr 9febec44c9637de7d1edb402f09984b41a249a6cfc3f41a4e33f7ecfcbd873e8 49802 main/i18n/Translation-sr.bz2 e8f0ffdf768e9765f8e36699533c034f3fb3314ed58e7b875f0e663d853ece21 27796 main/i18n/Translation-sr.diff/Index 340be8a51255b7eefc3cc86199d8c909fafb0d4d1e7ec34f6eb8bb7ecbd4a73f 78017 main/i18n/Translation-sv 52823b82a756e0709afe0348c2716089bc14e273efd982bec02165290aacff4b 25030 main/i18n/Translation-sv.bz2 2bb77b70019e801312627e857e572f289f89adf02941e87cb5104c9000e03aba 14512 main/i18n/Translation-sv.diff/Index aa7e2de78da8eeaad9a260fbbc17a5b92d30317809933fc4e13cf7130c12c723 14884 main/i18n/Translation-tr a618b4efa21e5d7f35b0d093a3dcce47772a37c92a76d97cb02aa00cb8ef3ec9 5520 main/i18n/Translation-tr.bz2 4ff546643cf2b48048d6d218f38dcc28212e6a4e8586fa2e72c5f2e4ce4a8593 4180 main/i18n/Translation-tr.diff/Index 951cee68c692643e45dac742f0ec8c47222afc47a2d2c2de8cdc74db0c703efa 3392641 main/i18n/Translation-uk b0e68152ac06301bd4742a44af288a8e8de16515e8658b4ca4a931858c3e4ac1 505704 main/i18n/Translation-uk.bz2 885f3fd62596c978fd0d9b8d33b8691cf167764c396a752f2edf35c9493ebe02 27796 main/i18n/Translation-uk.diff/Index 66e6907338988b2b3dae532b80297580e418b8f91276cdab148b58904f94125d 18784 main/i18n/Translation-vi 5552b1e64d0441872553ce5092c2a425dc60b0abbef6b0ca4bd4f980994d8775 5759 main/i18n/Translation-vi.bz2 339a108a94a27094c5efb98d8a303eae4676cf6fffa098c3227bec1124320ddc 736 main/i18n/Translation-vi.diff/Index 7133134d1b1b6c869b4b700fed9778e93a0b774391402ad3399e9ff46984efff 2007 main/i18n/Translation-zh 8cbeadbbcec613b8476f8e2aa40b15772909109e10a83317c111fcf7c28d0219 1215 main/i18n/Translation-zh.bz2 45ace25e50416def3f19678e1a25241f969f3e5d33df6a4dfa0dc19effcd3082 523044 main/i18n/Translation-zh_CN 58219ecb58e4f00ee9508ef12bcbfc5a0caaf037a1cf1e244c8f1364480fd995 123328 main/i18n/Translation-zh_CN.bz2 ff3ab388427bc38babde07ef82c60b21190bef5e21d603cceb13cb4a3b0e3b85 27796 main/i18n/Translation-zh_CN.diff/Index 5c72d7d612156780cdd4438162bb1ab01d5e6c324f90f62c22cc33aa275a2f14 33003 main/i18n/Translation-zh_TW d1d86ecf354a67a5cf7bd1945b763eb7d279f73d7988805edb80a504c1bd86bc 12432 main/i18n/Translation-zh_TW.bz2 f1e7b8308de71a4a68b685360762bbab14b3d68df70f31b872f9e017bd8c9f9d 6148 main/i18n/Translation-zh_TW.diff/Index 143ad35e650711c8ba02f2b645eab4ae6eddec0f807b375b65702ac77daaafeb 58561 main/installer-amd64/20230607/images/MD5SUMS fbf9b5a60c8315abbfdf94935bdfce3b16089639f0c2c2a3aca5e1e94d8b8503 78509 main/installer-amd64/20230607/images/SHA256SUMS 143ad35e650711c8ba02f2b645eab4ae6eddec0f807b375b65702ac77daaafeb 58561 main/installer-amd64/current/images/MD5SUMS fbf9b5a60c8315abbfdf94935bdfce3b16089639f0c2c2a3aca5e1e94d8b8503 78509 main/installer-amd64/current/images/SHA256SUMS 75cde65e6a7597ac52e76eaf8ec95bb1f70628c841ebe33877d979530ed54a87 92659 main/installer-arm64/20230607/images/MD5SUMS 4b0884bd001ca61df06cee22fd49fd20a998443dd5ff4c728a9ae5e3725c1989 126815 main/installer-arm64/20230607/images/SHA256SUMS 75cde65e6a7597ac52e76eaf8ec95bb1f70628c841ebe33877d979530ed54a87 92659 main/installer-arm64/current/images/MD5SUMS 4b0884bd001ca61df06cee22fd49fd20a998443dd5ff4c728a9ae5e3725c1989 126815 main/installer-arm64/current/images/SHA256SUMS 67620ff3d7a2b7e29e55e414013087308a79eba1818a4e8f2321792a2e4f3329 20336 main/installer-armel/20230607/images/MD5SUMS 4029ae03d65bbd9ccffdcfa4d8669afe8fe99a22a666aafd3670aa2e0673264f 28412 main/installer-armel/20230607/images/SHA256SUMS 67620ff3d7a2b7e29e55e414013087308a79eba1818a4e8f2321792a2e4f3329 20336 main/installer-armel/current/images/MD5SUMS 4029ae03d65bbd9ccffdcfa4d8669afe8fe99a22a666aafd3670aa2e0673264f 28412 main/installer-armel/current/images/SHA256SUMS 1211a06e2ac07005b31aaac92ebb3d3a54781980bd61ed061e9746f226668ad7 76534 main/installer-armhf/20230607/images/MD5SUMS 35d878d792be7b149c14454603c00053697f928c795d2bc4ed133d4159eb8bc9 110082 main/installer-armhf/20230607/images/SHA256SUMS 1211a06e2ac07005b31aaac92ebb3d3a54781980bd61ed061e9746f226668ad7 76534 main/installer-armhf/current/images/MD5SUMS 35d878d792be7b149c14454603c00053697f928c795d2bc4ed133d4159eb8bc9 110082 main/installer-armhf/current/images/SHA256SUMS 4c1cf3f297d9fdf0ab6f833a3d0ab68cf4c9c6115cc548c4978fc03302026327 104 main/source/Release feef53b7356da17401a3df531137754eeec105a7f23c4dcebd70f85f9479f35e 54636355 main/source/Sources 459a0ddfef32df8ddb9b898f4d5c78dff668ac2776579edbd25ec83024fbbf52 27910 main/source/Sources.diff/Index 0009ddfbbd21f5e9683d141a88675685cf95f27ea5c61d2bff5933f8c012abf9 13382715 main/source/Sources.gz 2e21e136912c227138135facb49b979125c94f0b34a2c91130fdb2a670280418 9973020 main/source/Sources.xz 5d4071730617ee6a26218a52c8d442be32f9bab67b39d52a36806c293cb237cf 424664 non-free-firmware/Contents-all 9418af052fd887b0b78787734bbc0ad3c1b81b9da957f6aa3ac3225b0422b0a6 10084 non-free-firmware/Contents-all.diff/Index 224e319501f863fe8b09289fba5881fdaeacaf57fa92acac80d00827a89b4c14 23291 non-free-firmware/Contents-all.gz a8c79e619795bd48b4b146cba06990bd870f85e46c4ccfd4ba927c919d670d8b 15889 non-free-firmware/Contents-amd64 053274f1ccaed1517ed55e0fd8f9270ed785bc6239e0bcf9b2684260b90d3abd 9100 non-free-firmware/Contents-amd64.diff/Index d1c2cb071de53e31cde8ab309c03f450bab769a34f64d6d7141fe27abfd3a97e 1093 non-free-firmware/Contents-amd64.gz 6b80614b68a8b6b808ebd95735e0dcc6f17cc8e21cad33051ee7b3cbc03f3ede 1769 non-free-firmware/Contents-arm64 a1378bea1f88b18483f9450a36b3418a4805287d438e21cc6be38d3aede99fa3 5164 non-free-firmware/Contents-arm64.diff/Index c8a9404ee2f6e362e703070337e8418a9bdde35fbba6f0203bacd789bfc043d7 290 non-free-firmware/Contents-arm64.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/Contents-armel f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/Contents-armel.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/Contents-armhf f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/Contents-armhf.gz 60da67bc32f5b3d2fab9b4e1aacde5149f153588e32bd934338f3e0d5c719681 221869 non-free-firmware/Contents-source 575032fc00107ce1355fe60112a34eefd048b83f51b1c2bd6a87f13b0fe25c36 19432 non-free-firmware/Contents-source.diff/Index da210e3af8a951bc40619ec88a2a54e34f4dc1bfb9356e8de2ca8809c7e56f55 24074 non-free-firmware/Contents-source.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/Contents-udeb-all f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/Contents-udeb-all.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/Contents-udeb-amd64 f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/Contents-udeb-amd64.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/Contents-udeb-arm64 f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/Contents-udeb-arm64.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/Contents-udeb-armel f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/Contents-udeb-armel.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/Contents-udeb-armhf f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/Contents-udeb-armhf.gz 97e3a95a41f4935dca3599b7ec18981106dda1d77bb347dd0f7559cff94d2ea5 29021 non-free-firmware/binary-all/Packages 386ec8a3c43dcf86d67647a10196aca896b33d6ebaa3a73babcfdbc512f0d410 12052 non-free-firmware/binary-all/Packages.diff/Index 00a31b363da5bd10eed786f6f543ee016ba5658e112b07c7a047e423b2972286 7060 non-free-firmware/binary-all/Packages.gz 3942406c130ab1dbc5cbf9025dea87347855bb20ec3b625021307209ea5815bd 6316 non-free-firmware/binary-all/Packages.xz a8e28440f28ff05df7b33c792f11fa96a3fb9582d520d453bfe3f89281efe5a9 114 non-free-firmware/binary-all/Release 28ce1615d0b130d7f741a63e683cad51faba5c59c70144bfeb4a038ec754855e 31865 non-free-firmware/binary-amd64/Packages d025dc33d9333e614aae49997f3b1c76731cd5de7294eee821000edc9f70ab85 27796 non-free-firmware/binary-amd64/Packages.diff/Index 0c49aad41caa0a4a5497fe191321032c9860da4f25259baaf118b9be87757729 7903 non-free-firmware/binary-amd64/Packages.gz 4d8ed598695f83efba704c91dda0d88cfc9a6a4eab41b68fff85b43084b2567d 7036 non-free-firmware/binary-amd64/Packages.xz 9ae2322ebb93ccb5f042a9f12ac522275da0842ca29f38335520f9e3fc6d8c02 116 non-free-firmware/binary-amd64/Release b1f49e6eb1e4764878d29da8b6ff4fae03ee0ea9f991de27caddf9e023dcd072 30519 non-free-firmware/binary-arm64/Packages a39e24285d2ef74c1487a64848d02b0348100502e47fe11cb501d3a29a75cac1 22384 non-free-firmware/binary-arm64/Packages.diff/Index 553b7e3fb8dbb7188e6c93b0f6640b8c1a70ce4fcaba9b2e40f2602e170044de 7429 non-free-firmware/binary-arm64/Packages.gz 7929124377b079abb7ee8de1274a6dc188682ede86989b8962298a051cb723aa 6644 non-free-firmware/binary-arm64/Packages.xz 5d0478bbd0a2e311360a35551900cbfc8aeee2a62e3422224a22fc3f8bd2f07a 116 non-free-firmware/binary-arm64/Release 97e3a95a41f4935dca3599b7ec18981106dda1d77bb347dd0f7559cff94d2ea5 29021 non-free-firmware/binary-armel/Packages 386ec8a3c43dcf86d67647a10196aca896b33d6ebaa3a73babcfdbc512f0d410 12052 non-free-firmware/binary-armel/Packages.diff/Index 00a31b363da5bd10eed786f6f543ee016ba5658e112b07c7a047e423b2972286 7060 non-free-firmware/binary-armel/Packages.gz 3942406c130ab1dbc5cbf9025dea87347855bb20ec3b625021307209ea5815bd 6316 non-free-firmware/binary-armel/Packages.xz 1fb3bee08bb47f5afa62ed7fcaaffe46c15e74bc02070673f7d0037a70a7d61c 116 non-free-firmware/binary-armel/Release 97e3a95a41f4935dca3599b7ec18981106dda1d77bb347dd0f7559cff94d2ea5 29021 non-free-firmware/binary-armhf/Packages 386ec8a3c43dcf86d67647a10196aca896b33d6ebaa3a73babcfdbc512f0d410 12052 non-free-firmware/binary-armhf/Packages.diff/Index 00a31b363da5bd10eed786f6f543ee016ba5658e112b07c7a047e423b2972286 7060 non-free-firmware/binary-armhf/Packages.gz 3942406c130ab1dbc5cbf9025dea87347855bb20ec3b625021307209ea5815bd 6316 non-free-firmware/binary-armhf/Packages.xz a7964a32acad4d5be8eb82d559bfb760768888fff495bc02cd0ee61a91ac8fa5 116 non-free-firmware/binary-armhf/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/debian-installer/binary-all/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/debian-installer/binary-all/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free-firmware/debian-installer/binary-all/Packages.xz a8e28440f28ff05df7b33c792f11fa96a3fb9582d520d453bfe3f89281efe5a9 114 non-free-firmware/debian-installer/binary-all/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/debian-installer/binary-amd64/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/debian-installer/binary-amd64/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free-firmware/debian-installer/binary-amd64/Packages.xz 9ae2322ebb93ccb5f042a9f12ac522275da0842ca29f38335520f9e3fc6d8c02 116 non-free-firmware/debian-installer/binary-amd64/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/debian-installer/binary-arm64/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/debian-installer/binary-arm64/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free-firmware/debian-installer/binary-arm64/Packages.xz 5d0478bbd0a2e311360a35551900cbfc8aeee2a62e3422224a22fc3f8bd2f07a 116 non-free-firmware/debian-installer/binary-arm64/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/debian-installer/binary-armel/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/debian-installer/binary-armel/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free-firmware/debian-installer/binary-armel/Packages.xz 1fb3bee08bb47f5afa62ed7fcaaffe46c15e74bc02070673f7d0037a70a7d61c 116 non-free-firmware/debian-installer/binary-armel/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free-firmware/debian-installer/binary-armhf/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free-firmware/debian-installer/binary-armhf/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free-firmware/debian-installer/binary-armhf/Packages.xz a7964a32acad4d5be8eb82d559bfb760768888fff495bc02cd0ee61a91ac8fa5 116 non-free-firmware/debian-installer/binary-armhf/Release 9f1af6ba9c84a38a6f224dedc4262de98fada2a567395c755636444c196f2425 378149 non-free-firmware/dep11/Components-amd64.yml eeb5fc70bcff5564e64656c5295fd3fee6548d1cfad9010b1f4f2cce24187085 34379 non-free-firmware/dep11/Components-amd64.yml.gz 5da2635e92f20cb0bdd2bd4aaab4e280473c3d6c3a7bc06855a809ce3422c346 20616 non-free-firmware/dep11/Components-amd64.yml.xz f39605fb004c4fceeb4b5107f8884bfc3d0b965f0ea1541bac8ca3c734d79c53 378149 non-free-firmware/dep11/Components-arm64.yml 216ff50681e72a2d6a9342f9c0f26bd941863a33b412030c4471cb52efd71287 34357 non-free-firmware/dep11/Components-arm64.yml.gz 1e99427c5f6463222bdcbff7ad71b2b30773f730b844baf1db0a4443cbfadd17 20796 non-free-firmware/dep11/Components-arm64.yml.xz 734c85d71c3284a05bb305a3147be1ae813b649b072bb8d13b9f30abeace27fe 378149 non-free-firmware/dep11/Components-armel.yml df5c1127084edb7c5fbeede373e86ee66970a1219df12febd37880eddbd2b544 34377 non-free-firmware/dep11/Components-armel.yml.gz b70e285cf07a52b0d2bf1b8395a7d27e4335fb7e6362ccebeeae926fe3e0e78c 20944 non-free-firmware/dep11/Components-armel.yml.xz 1c9e79c126ec5b0a9eae9d5ae0f5dde7a5dd1ca510116d8049e1852d907d4459 378149 non-free-firmware/dep11/Components-armhf.yml d6c8c8d2c2017611f92c66ecbe83de043aa63cfec0160cfe3086135ad7acba06 34513 non-free-firmware/dep11/Components-armhf.yml.gz 0e3de38992594155a27193311e025df4d836732bdf0510aa6340be626acacfe6 20888 non-free-firmware/dep11/Components-armhf.yml.xz 5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef 1024 non-free-firmware/dep11/icons-128x128.tar 7989bb311baa38ef545250282aa065d23281c46dfb8faabe4c653487bdbded5c 29 non-free-firmware/dep11/icons-128x128.tar.gz 5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef 1024 non-free-firmware/dep11/icons-48x48.tar 7989bb311baa38ef545250282aa065d23281c46dfb8faabe4c653487bdbded5c 29 non-free-firmware/dep11/icons-48x48.tar.gz 5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef 1024 non-free-firmware/dep11/icons-64x64.tar 7989bb311baa38ef545250282aa065d23281c46dfb8faabe4c653487bdbded5c 29 non-free-firmware/dep11/icons-64x64.tar.gz c2faf83556c688649c4e155c7b0bee75499063310f98a974f98b43804c511ea5 15168 non-free-firmware/i18n/Translation-en c8d4bc91102533dcbaa659cba0a210ad20c9096ad8a20f4c246e37dc27141a31 5656 non-free-firmware/i18n/Translation-en.diff/Index d530bbb84930e13ae46e347955d575afe5b776c8180d5a4285c0a71fee618247 4796 non-free-firmware/i18n/Translation-en.xz 7338e3808e4fee29ef2b70e1e65604d6d6513b6b000d6e80b2d656e8047a59f6 117 non-free-firmware/source/Release ebf754e90a1c0474321798f98222c0b00c258b962e7a47bc317729f66815820c 31740 non-free-firmware/source/Sources c0e363f63ef242b21a79b81e68579bdb949c5f192574cec9dc3609f5134edeba 27796 non-free-firmware/source/Sources.diff/Index 09c89008e7a471e8969ce5763b9f12a8bc358d24a54d17837ff6fafd9b23745d 7539 non-free-firmware/source/Sources.gz 78f8e0386cc392213ae5377ee446a723634efe50ec3c3e9f33d0c22cd8bd1c45 6948 non-free-firmware/source/Sources.xz 91c63857b46ace7720d0895e60a65ab74fbcf585f0d5171b9ce36b2ec2aceaee 14898506 non-free/Contents-all 22f8bba1ddf807ca4e1ee67c0326645461c63add2d7d6ad9d93b6d53817569d0 27910 non-free/Contents-all.diff/Index 142d80e58d13b9d6e2ec7279e8970b5ad97d778e2fd464bdc688725780f85ad6 785223 non-free/Contents-all.gz 99a4219387827e8e4a6ac30c92b52a10aee675957ac9f0e9cf8796de35050d1d 985673 non-free/Contents-amd64 51a0cc1458b71fbc50fd9b1586890bec7c76bb6eefe31447f85aac7ce34ce949 27796 non-free/Contents-amd64.diff/Index d3f806d9fdce18954051c0897740e251260f24d9428f432a2523addb8812b16c 75457 non-free/Contents-amd64.gz a20d44e8cc8cfcf8c5476bbd13c596ee776343a20e639bd5b451023a46a6cb3e 567043 non-free/Contents-arm64 031af7d9dd7c51b034a62acb510e9571ff80ceb91bdd31754cc05ebb13cf3f6e 27796 non-free/Contents-arm64.diff/Index e22b22f453947a1cd1bd2ce08ea0d431a6b104fdf97df7cd2b95bc0ed9ca2746 44801 non-free/Contents-arm64.gz 19971fabb1d37dc42f3b3dcb2cc2cde63487dbf6217c476f488552fe5a20bbd1 149034 non-free/Contents-armel 885ac7be1c9fd314a3de288bf8bbe6e9a709890bdff31b41d566f590185131d4 15988 non-free/Contents-armel.diff/Index c1060eb5af8b3f219a96ddb901c72360cd09263576e4e7bc56eec65ac793545d 14071 non-free/Contents-armel.gz 5a14c05698b8589d90f9bbe9887101eaf581cc67a28ef1ce057cec73afb3c854 158838 non-free/Contents-armhf 7ce1de92ad28a9d6c19012717aaab6b032237d4e9fc60ea93dd2066ca3289447 17956 non-free/Contents-armhf.diff/Index 1cc45d3572b112784a297839bc50bda97a8e3db66a053d0387f75fdfa68eee9a 15250 non-free/Contents-armhf.gz 7c4f9850a14d372a4343d93f93433eb89a31371ba6ba40af9ef0230ed31b1593 9738587 non-free/Contents-source bbf19ab32a6747147aaca2d3ea74a4a4343b3bbe856fac5e32c419464d5ff12b 27796 non-free/Contents-source.diff/Index 240b3fb4570ea908d5f852eb1a0d45aa7069661a871e0c8908c96da68c1b3872 979973 non-free/Contents-source.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/Contents-udeb-all f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/Contents-udeb-all.gz 53e97ea5da70d8e815d9bf8ca8a61a437bd6ff88f4651b6c255df04295b422a3 480 non-free/Contents-udeb-amd64 b7f7488fee92b44e9cf035a9118d9bd4a6ea63e6d340ba673b4a8fea49c1bed0 114 non-free/Contents-udeb-amd64.gz 53e97ea5da70d8e815d9bf8ca8a61a437bd6ff88f4651b6c255df04295b422a3 480 non-free/Contents-udeb-arm64 b7f7488fee92b44e9cf035a9118d9bd4a6ea63e6d340ba673b4a8fea49c1bed0 114 non-free/Contents-udeb-arm64.gz 53e97ea5da70d8e815d9bf8ca8a61a437bd6ff88f4651b6c255df04295b422a3 480 non-free/Contents-udeb-armel b7f7488fee92b44e9cf035a9118d9bd4a6ea63e6d340ba673b4a8fea49c1bed0 114 non-free/Contents-udeb-armel.gz 53e97ea5da70d8e815d9bf8ca8a61a437bd6ff88f4651b6c255df04295b422a3 480 non-free/Contents-udeb-armhf b7f7488fee92b44e9cf035a9118d9bd4a6ea63e6d340ba673b4a8fea49c1bed0 114 non-free/Contents-udeb-armhf.gz b92ea40c0d23157e1834fefb038a4f3d5e208148a9c5d1d32aa7683097dbaff3 220739 non-free/binary-all/Packages 33221085c59ae874a8d999f5358472a0c6421ed55fe14707fbae54fb572513ac 27796 non-free/binary-all/Packages.diff/Index 3c36ebafb0f0b283973a756bcb8cee7b17e7a97cdf41489ea555b14ab714ee11 52221 non-free/binary-all/Packages.gz 2ce35f11a6bd7c79d412d8072ff5d96b66b849aee7eb17f01891d5735c18574a 43344 non-free/binary-all/Packages.xz 99c9bba8428e4c59a626a2ff61b8061ceb448d7a59658d92e906425c4206e849 105 non-free/binary-all/Release c653c773fd498e40488c7670f3364f52ae535312a8bb1657324d78b3841f6631 597497 non-free/binary-amd64/Packages a954a81bd80c97bb71496c73f4bd21556a85a22b801d2b7e4e3eb8b53d8becda 27796 non-free/binary-amd64/Packages.diff/Index cc0bad244dadad77d970bdace6529b94b50ddc1e1dfd1786b80a6490494b0fd9 122578 non-free/binary-amd64/Packages.gz 7b2d4702cd5f47108644481974f84ea3c0f28d32f7b29dd00fba8b5d84ff8064 98068 non-free/binary-amd64/Packages.xz bdab55d88a0b0acd7ee89a668a1044b69d1b57313834d8e6767b815e39900d54 107 non-free/binary-amd64/Release bd1ce9769625118b282db8aa22f03453a9ec195789d19d46f089f6c128917442 410729 non-free/binary-arm64/Packages d9882c43cf2daeb57b7cb3b30d9f06c805a778d1ffa4db9ac08c961a535f82f0 27796 non-free/binary-arm64/Packages.diff/Index 939b97acc1edede52667e6cb674ca4c1f1e59cfbaec860b0bc6ff844f07338e3 93016 non-free/binary-arm64/Packages.gz 926b6f1e2e2cd757cf6546785443acde32f73cc7fe3eaabc82b3fb6fcc082ae4 75384 non-free/binary-arm64/Packages.xz d2f86895e67badf476812567224994c1736e4d895a299c5c6c794a6f8f6afad2 107 non-free/binary-arm64/Release 745403b4004bab1011822418c5f0fe6f32a3a5629395dc004bb68ed521c9682b 270311 non-free/binary-armel/Packages 9085a833bb5c7ee97d7fe81c184d7f4f6303570f4e18701eb0c1408092d8ea6e 27796 non-free/binary-armel/Packages.diff/Index b84d270c62a66eab7a488338c4e6664ab91ee0962649fdce82389ca92634f30c 66160 non-free/binary-armel/Packages.gz 225335d8082721ac63458619a8576c4fad7a1e5e01aecf8190fc74dc0ba6a312 54356 non-free/binary-armel/Packages.xz 870250d2289eefb55c5d6742c2bfbf35c8049819f18cccfb547ae930154ac422 107 non-free/binary-armel/Release 8ebc1a931a0f4d918c665d172f9f76b4a93f6d392b07ece14974b069cdafdab7 278052 non-free/binary-armhf/Packages 802e35ac2a14fc428def634a23133ff6ce8175e514f988f83c48fce93ee23fb1 27796 non-free/binary-armhf/Packages.diff/Index 7000f17d9fa0d205a50e1e9fd20d78aef52ca6766c756e223f3e3fd5a7b8015c 67863 non-free/binary-armhf/Packages.gz 9347685a23ccaf548bf2e50f1909dea49084a2b8e295aa5aafc24323bbf0de0e 55888 non-free/binary-armhf/Packages.xz adf1dde66d1c282ef8d22cdfe5915ed3b255c5747347dd99171ef5133cb56ad9 107 non-free/binary-armhf/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-all/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-all/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-all/Packages.xz 99c9bba8428e4c59a626a2ff61b8061ceb448d7a59658d92e906425c4206e849 105 non-free/debian-installer/binary-all/Release e15f9550a04f337aaca0db2295ec8dae7b333bd6d9fe85e818d933ff6f8acd27 607 non-free/debian-installer/binary-amd64/Packages 87eb4085fa1e71ef4f53c9ed3b5a415dc37395141d888ee4e8848a63cc94e4a5 413 non-free/debian-installer/binary-amd64/Packages.gz 0efa00fc748e86d01c0b52a88defc7584886c6818072a7e0c5e598206f2fc1fd 492 non-free/debian-installer/binary-amd64/Packages.xz bdab55d88a0b0acd7ee89a668a1044b69d1b57313834d8e6767b815e39900d54 107 non-free/debian-installer/binary-amd64/Release ed5c887687bb4929955f7b93c47cf4e7d6caff2c9b765a48cc3002ce3faccb11 607 non-free/debian-installer/binary-arm64/Packages 1999c2cdfcc520fe3af7aec93defc2d02b62832df40e798731be0f5ea3f9a894 412 non-free/debian-installer/binary-arm64/Packages.gz 94dfd6b6edb70f510be11f1748c2bbdf11840d45fa25c2bfeafb2e058f402b44 488 non-free/debian-installer/binary-arm64/Packages.xz d2f86895e67badf476812567224994c1736e4d895a299c5c6c794a6f8f6afad2 107 non-free/debian-installer/binary-arm64/Release 9a4f9dedeccc422cbac74e875b27e9db029378a1d03c9a5e953bdb55e84fa9bd 607 non-free/debian-installer/binary-armel/Packages c8239018ed5d50d881bd3b5d6a879e53d2620ca59a68a3aac141e7159c794e15 411 non-free/debian-installer/binary-armel/Packages.gz 387962963c407195614eda41d610a61176224c97ee96368ce58bf611090d6f85 492 non-free/debian-installer/binary-armel/Packages.xz 870250d2289eefb55c5d6742c2bfbf35c8049819f18cccfb547ae930154ac422 107 non-free/debian-installer/binary-armel/Release 4111491a78e2be778ee86cba9542d7382ee522013247ffca3ade4e56b38bafe5 607 non-free/debian-installer/binary-armhf/Packages 2de9422d927494fa486943539b7ed1fd41678cbd385ae3a4383d2f089d7da57d 412 non-free/debian-installer/binary-armhf/Packages.gz d1cb0e08fa424389ecd207c419619f6b3d8e8f834e5b7147b99290a18d1f1a2a 492 non-free/debian-installer/binary-armhf/Packages.xz adf1dde66d1c282ef8d22cdfe5915ed3b255c5747347dd99171ef5133cb56ad9 107 non-free/debian-installer/binary-armhf/Release 96da9bcf2c06bbfab310500a1c476ce444f8a318441fb127c15343b553911608 11715 non-free/dep11/Components-amd64.yml ef5058416560ae2f5984963735d16563fe2f0d7ab1e1aaf19e64ce703a0224ee 3610 non-free/dep11/Components-amd64.yml.gz 17086dfd821cadf471851484705aca8f5c0653ed5ca988e5d01acde96adfea94 3492 non-free/dep11/Components-amd64.yml.xz c69f4bbfc4b1ace4034894e0e9f90a36e4e02e599b5be6414bf1a98f565d4e66 5893 non-free/dep11/Components-arm64.yml 298297d9e178a5467984ddd1a8e425b59d98b3c9274135f4c9cd332751e6d787 1786 non-free/dep11/Components-arm64.yml.gz 3248095356555a16336d774367bfadfdf969230a6062efa581e8195a595cd640 1844 non-free/dep11/Components-arm64.yml.xz ee8c7d3af7ac3fd110449d2dbb75ef04fe2a4efae034fbb5b5762a3e784a8339 5893 non-free/dep11/Components-armel.yml c82b21c9f91d8537bb66b72495a16e9d05ca44b1a71f2925bd885427ce556c3b 1785 non-free/dep11/Components-armel.yml.gz abc790ab0899a56b11aeba4c84639b4c3be52a06353c86cfa57082582a08e726 1852 non-free/dep11/Components-armel.yml.xz 0a7327a21bfc19534ba47103033c8a6e5f81f467fc03b878c5cc59223c199244 5893 non-free/dep11/Components-armhf.yml 626ee28366d36be0e88ddfe46420832736b4920a41df04763406f1eefc9605bd 1785 non-free/dep11/Components-armhf.yml.gz 8708ee62012cc8e4b3d969ed66bfce1e5f5dc3768fe2dc86fc13b2df7703502b 1856 non-free/dep11/Components-armhf.yml.xz d38600d75d6cdf282e37f9acdade6cba278f583fbc32a6ac994d6e8bfe4a751e 7168 non-free/dep11/icons-128x128.tar 2f1c57c68df2bd2c31a6c86c61b857e3ed367efc7a419e62a7e6e5fe60f1b039 2167 non-free/dep11/icons-128x128.tar.gz 925885b4612bc30eeec0c37fe8f99ffdcb19e4a8af35a64436da074c7306d130 3072 non-free/dep11/icons-48x48.tar 3a9aa93874c7df26641c8e6b879fa54e2dcea90bdbc922f8fe38cd7b6b26b1df 578 non-free/dep11/icons-48x48.tar.gz 2228c3a53742503986e6e7435b4357970094e019a691d6f3d027ff7267f22bdd 17920 non-free/dep11/icons-64x64.tar 2cd7f6a2e9e53a4d3121d00c8d98a815148d300bbb4a1887c0a52d3c935aa618 12030 non-free/dep11/icons-64x64.tar.gz 1fa87cb885789abb60f5505628b2bc129637c193ba406332939ffe4bc450d5c8 420788 non-free/i18n/Translation-en 4a48748a5c2532e2e7ab8ceb287f74de4b404f8e6f677157f3c1071ae195a8fe 27796 non-free/i18n/Translation-en.diff/Index 52ead5815ba59be68a8b4312dd14b2959e704298e68bc0a4687a3ffecb8fb0ca 67232 non-free/i18n/Translation-en.xz 5817d1b66355cca8704653e473eab6c4e0eec884914abd452a801787789d5509 108 non-free/source/Release f17cd43097b8a101b6354ad4896ecca478167e83e20cf57bdff159b174bcc2dd 336581 non-free/source/Sources 1e24b7b092ab916227f73a40585f4af18de40ecac802588b44bb484921beb710 27796 non-free/source/Sources.diff/Index ba1490e724a764ee6fa3b3c701331571608facfdea15252846b4e7e8f9878d4e 90508 non-free/source/Sources.gz 22ca387b16b8b54c9fbec0c0ea5b03fa0b5e9b52811f63aca89b07d6d6ce4b5a 74912 non-free/source/Sources.xz debian-control-0.1.28/src/vcs.rs000064400000000000000000000072621046102023000145530ustar 00000000000000use regex::Regex; use std::borrow::Cow; use std::str::FromStr; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ParsedVcs { pub repo_url: String, pub branch: Option, pub subpath: Option, } impl FromStr for ParsedVcs { type Err = &'static str; fn from_str(s: &str) -> Result { let mut s: Cow = s.trim().into(); let mut subpath: Option = None; let branch: Option; let repo_url: String; let re = Regex::new(r" \[([^] ]+)\]").unwrap(); if let Some(ref m) = re.find(s.as_ref()) { subpath = Some(m.as_str()[2..m.as_str().len() - 1].to_string()); s = Cow::Owned([s[..m.start()].to_string(), s[m.end()..].to_string()].concat()); } if let Some(index) = s.find(" -b ") { let (url, branch_str) = s.split_at(index); branch = Some(branch_str[4..].to_string()); repo_url = url.to_string(); } else { branch = None; repo_url = s.to_string(); } Ok(ParsedVcs { repo_url, branch, subpath, }) } } impl std::fmt::Display for ParsedVcs { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.repo_url)?; if let Some(branch) = &self.branch { write!(f, " -b {}", branch)?; } if let Some(subpath) = &self.subpath { write!(f, " [{}]", subpath)?; } Ok(()) } } #[derive(Debug, Clone)] pub enum Vcs { Git { repo_url: String, branch: Option, subpath: Option, }, Bzr { repo_url: String, subpath: String, }, Hg { repo_url: String, }, Svn { url: String, }, } #[cfg(test)] mod test { use super::*; #[test] fn test_vcs_info() { let vcs_info = ParsedVcs::from_str("https://github.com/jelmer/example").unwrap(); assert_eq!(vcs_info.repo_url, "https://github.com/jelmer/example"); assert_eq!(vcs_info.branch, None); assert_eq!(vcs_info.subpath, None); } #[test] fn test_vcs_info_with_branch() { let vcs_info = ParsedVcs::from_str("https://github.com/jelmer/example -b branch").unwrap(); assert_eq!(vcs_info.repo_url, "https://github.com/jelmer/example"); assert_eq!(vcs_info.branch, Some("branch".to_string())); assert_eq!(vcs_info.subpath, None); } #[test] fn test_vcs_info_with_subpath() { let vcs_info = ParsedVcs::from_str("https://github.com/jelmer/example [subpath]").unwrap(); assert_eq!(vcs_info.repo_url, "https://github.com/jelmer/example"); assert_eq!(vcs_info.branch, None); assert_eq!(vcs_info.subpath, Some("subpath".to_string())); } #[test] fn test_vcs_info_with_branch_and_subpath() { let vcs_info = ParsedVcs::from_str("https://github.com/jelmer/example -b branch [subpath]").unwrap(); assert_eq!(vcs_info.repo_url, "https://github.com/jelmer/example"); assert_eq!(vcs_info.branch, Some("branch".to_string())); assert_eq!(vcs_info.subpath, Some("subpath".to_string())); } #[test] fn test_eq() { let vcs_info1 = ParsedVcs::from_str("https://github.com/jelmer/example -b branch [subpath]").unwrap(); let vcs_info2 = ParsedVcs::from_str("https://github.com/jelmer/example -b branch [subpath]").unwrap(); let vcs_info3 = ParsedVcs::from_str("https://example.com/jelmer/example -b branch [subpath]").unwrap(); assert_eq!(vcs_info1, vcs_info2); assert_ne!(vcs_info1, vcs_info3); } }