dep3-0.1.28/.cargo_vcs_info.json0000644000000001420000000000100117540ustar { "git": { "sha1": "d8342b74b425b194d90f453694d8754caf5509be" }, "path_in_vcs": "dep3" }dep3-0.1.28/.gitignore000064400000000000000000000000101046102023000125260ustar 00000000000000/target dep3-0.1.28/Cargo.lock0000644000000317230000000000100077400ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[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.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[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.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" 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-derive" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b6e5cafe61e77421a090e2a33b8a2e4e2ff1b106fd906ebade111307064d981" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "deb822-lossless" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "607abd8f5e3d131f03a1f351f5a5c8426ba4bf820ad10a2c59a1d4fd6d8eb1d9" dependencies = [ "deb822-derive", "regex", "rowan", "serde", ] [[package]] name = "dep3" version = "0.1.28" dependencies = [ "chrono", "deb822-lossless", "url", ] [[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 = "iana-time-zone" version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" 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 = "js-sys" version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[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 = "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.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "proc-macro2" version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] [[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.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[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.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" 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.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[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.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[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" dep3-0.1.28/Cargo.toml0000644000000023020000000000100077520ustar # 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 = "dep3" version = "0.1.28" build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "A library for parsing and generating DEP-3 headers." homepage = "https://github.com/jelmer/deb822-lossless" readme = "README.md" keywords = [ "debian", "patch", "dep3", "lossless", ] categories = ["parser-implementations"] license = "Apache-2.0" repository = "https://github.com/jelmer/deb822-lossless" [lib] name = "dep3" path = "src/lib.rs" [[example]] name = "read-dep3" path = "examples/read-dep3.rs" [dependencies.chrono] version = ">=0.4" [dependencies.deb822-lossless] version = ">=0.2" features = ["derive"] [dependencies.url] version = "2" dep3-0.1.28/Cargo.toml.orig000064400000000000000000000007311046102023000134370ustar 00000000000000[package] name = "dep3" edition = "2021" license = "Apache-2.0" version = "0.1.28" description = "A library for parsing and generating DEP-3 headers." homepage = "https://github.com/jelmer/deb822-lossless" repository = "https://github.com/jelmer/deb822-lossless" keywords = ["debian", "patch", "dep3", "lossless"] categories = ["parser-implementations"] [dependencies] chrono = ">=0.4" deb822-lossless = { path = "..", version = ">=0.2", features = ["derive"] } url = "2" dep3-0.1.28/README.md000064400000000000000000000013071046102023000120270ustar 00000000000000Rust parser for Debian DEP-3 patch headers ------------------------------------------ # Examples ```rust use dep3::PatchHeader; use std::str::FromStr; let text = r#"From: John Doe Date: Mon, 1 Jan 2000 00:00:00 +0000 Subject: [PATCH] fix a bug Bug-Debian: https://bugs.debian.org/123456 Bug: https://bugzilla.example.com/bug.cgi?id=123456 Forwarded: not-needed "#; let patch_header = PatchHeader::from_str(text).unwrap(); assert_eq!(patch_header.description(), Some("[PATCH] fix a bug".to_string())); assert_eq!(patch_header.vendor_bugs("Debian").collect::>(), vec!["https://bugs.debian.org/123456".to_string()]); ``` See for details dep3-0.1.28/disperse.conf000064400000000000000000000000461046102023000132340ustar 00000000000000timeout_days: 5 tag_name: "v$VERSION" dep3-0.1.28/examples/read-dep3.rs000064400000000000000000000010031046102023000144710ustar 00000000000000use dep3::lossy::PatchHeader; use std::str::FromStr; pub const TEXT: &str = r#"From: John Doe Date: Mon, 1 Jan 2000 00:00:00 +0000 Subject: [PATCH] fix a bug Bug-Debian: https://bugs.debian.org/123456 Bug: https://bugzilla.example.com/bug.cgi?id=123456 Forwarded: not-needed "#; pub fn main() { let patch_header = PatchHeader::from_str(TEXT).unwrap(); println!("Description: {}", patch_header.description.unwrap()); println!("Debian Bugs: {}", patch_header.bug_debian.unwrap()); } dep3-0.1.28/src/fields.rs000064400000000000000000000117431046102023000131600ustar 00000000000000/// Whether the patch has been forwarded to the upstream project. #[derive(Debug, PartialEq, Eq, Clone)] pub enum Forwarded { /// The patch has not been forwarded to the upstream project. No, /// The patch does not need to be forwarded to the upstream project. NotNeeded, /// The patch has been forwarded to the upstream project, and the value /// provides some reference to the forwarded patch. Yes(String), } impl std::fmt::Display for Forwarded { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Forwarded::No => f.write_str("no"), Forwarded::NotNeeded => f.write_str("not-needed"), Forwarded::Yes(s) => f.write_str(s), } } } impl std::str::FromStr for Forwarded { type Err = &'static str; fn from_str(s: &str) -> Result { match s { "no" => Ok(Forwarded::No), "not-needed" => Ok(Forwarded::NotNeeded), s => Ok(Forwarded::Yes(s.to_string())), } } } /// The category of the origin #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum OriginCategory { /// an upstream patch that had to be modified to apply on the current version Backport, /// a patch created by Debian or another distribution vendor Vendor, /// a patch cherry-picked from the upstream VCS Upstream, /// a patch that does not fit in any of the above categories Other, } impl std::fmt::Display for OriginCategory { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { OriginCategory::Backport => f.write_str("backport"), OriginCategory::Vendor => f.write_str("vendor"), OriginCategory::Upstream => f.write_str("upstream"), OriginCategory::Other => f.write_str("other"), } } } impl std::str::FromStr for OriginCategory { type Err = &'static str; fn from_str(s: &str) -> Result { match s { "backport" => Ok(OriginCategory::Backport), "vendor" => Ok(OriginCategory::Vendor), "upstream" => Ok(OriginCategory::Upstream), "other" => Ok(OriginCategory::Other), _ => Err("invalid origin category"), } } } /// The origin of the patch #[derive(Debug, PartialEq, Eq, Clone)] pub enum Origin { /// The patch was cherry-picked from the upstream VCS Commit(String), /// Some other origin Other(String), } impl std::fmt::Display for Origin { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Origin::Commit(s) => write!(f, "commit:{}", s), Origin::Other(s) => f.write_str(&s.to_string()), } } } impl std::str::FromStr for Origin { type Err = &'static str; fn from_str(s: &str) -> Result { if let Some(rest) = s.strip_prefix("commit:") { Ok(Origin::Commit(rest.to_string())) } else { Ok(Origin::Other(s.to_string())) } } } /// Whether the patch has been applied in the upstream project. #[derive(Debug, PartialEq, Eq, Clone)] pub enum AppliedUpstream { /// The patch has not been applied in the upstream project, in the specified commit. Commit(String), /// The patch has been applied in the upstream project, in the specified reference. Other(String), } impl std::fmt::Display for AppliedUpstream { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AppliedUpstream::Commit(s) => write!(f, "commit:{}", s), AppliedUpstream::Other(s) => f.write_str(&s.to_string()), } } } impl std::str::FromStr for AppliedUpstream { type Err = &'static str; fn from_str(s: &str) -> Result { if let Some(rest) = s.strip_prefix("commit:") { Ok(AppliedUpstream::Commit(rest.to_string())) } else { Ok(AppliedUpstream::Other(s.to_string())) } } } pub(crate) fn parse_origin(s: &str) -> (Option, Origin) { // if origin starts with ", " then it is a category let mut parts = s.splitn(2, ", "); let (category, s) = match parts.next() { Some("backport") => (Some(OriginCategory::Backport), parts.next().unwrap_or("")), Some("vendor") => (Some(OriginCategory::Vendor), parts.next().unwrap_or("")), Some("upstream") => (Some(OriginCategory::Upstream), parts.next().unwrap_or("")), Some("other") => (Some(OriginCategory::Other), parts.next().unwrap_or("")), None | Some(_) => (None, s), }; if let Some(rest) = s.strip_prefix("commit:") { (category, Origin::Commit(rest.to_string())) } else { (category, Origin::Other(s.to_string())) } } pub(crate) fn format_origin(category: &Option, origin: &Origin) -> String { format!( "{}{}", category.map(|c| c.to_string() + ", ").unwrap_or_default(), origin ) } dep3-0.1.28/src/lib.rs000064400000000000000000000014541046102023000124560ustar 00000000000000#![deny(missing_docs)] //! A library for parsing and generating Debian patch headers. //! //! # Examples //! //! ```rust //! use dep3::PatchHeader; //! use std::str::FromStr; //! let text = r#"From: John Doe //! Date: Mon, 1 Jan 2000 00:00:00 +0000 //! Subject: [PATCH] fix a bug //! Bug-Debian: https://bugs.debian.org/123456 //! Bug: https://bugzilla.example.com/bug.cgi?id=123456 //! Forwarded: not-needed //! "#; //! //! let patch_header = PatchHeader::from_str(text).unwrap(); //! assert_eq!(patch_header.description(), Some("[PATCH] fix a bug".to_string())); //! assert_eq!(patch_header.vendor_bugs("Debian").collect::>(), vec!["https://bugs.debian.org/123456".to_string()]); //! ``` mod fields; pub use fields::*; pub mod lossless; pub mod lossy; pub use lossless::PatchHeader; dep3-0.1.28/src/lossless.rs000064400000000000000000000341441046102023000135610ustar 00000000000000//! A library for parsing and generating Debian patch headers. //! //! # Examples //! //! ```rust //! use dep3::lossless::PatchHeader; //! use std::str::FromStr; //! let text = r#"From: John Doe //! Date: Mon, 1 Jan 2000 00:00:00 +0000 //! Subject: [PATCH] fix a bug //! Bug-Debian: https://bugs.debian.org/123456 //! Bug: https://bugzilla.example.com/bug.cgi?id=123456 //! Forwarded: not-needed //! "#; //! //! let patch_header = PatchHeader::from_str(text).unwrap(); //! assert_eq!(patch_header.description(), Some("[PATCH] fix a bug".to_string())); //! assert_eq!(patch_header.vendor_bugs("Debian").collect::>(), vec!["https://bugs.debian.org/123456".to_string()]); //! ``` use deb822_lossless::Paragraph; use crate::fields::*; /// A Debian patch header. pub struct PatchHeader(Paragraph); impl PatchHeader { /// Create a new, empty patch header. pub fn new() -> Self { PatchHeader(Paragraph::new()) } /// Get a reference to the underlying `Paragraph`. pub fn as_deb822(&self) -> &Paragraph { &self.0 } /// Get a mutable reference to the underlying `Paragraph`, mutably. pub fn as_deb822_mut(&mut self) -> &mut Paragraph { &mut self.0 } /// The origin of the patch. pub fn origin(&self) -> Option<(Option, Origin)> { self.0 .get("Origin") .as_deref() .map(crate::fields::parse_origin) } /// Set the origin of the patch. pub fn set_origin(&mut self, category: Option, origin: Origin) { self.0.insert( "Origin", crate::fields::format_origin(&category, &origin).as_str(), ); } /// The `Forwarded` field. pub fn forwarded(&self) -> Option { self.0 .get("Forwarded") .as_deref() .map(|s| s.parse().unwrap()) } /// Set the `Forwarded` field. pub fn set_forwarded(&mut self, forwarded: Forwarded) { self.0.insert("Forwarded", forwarded.to_string().as_str()); } /// The author of the patch. pub fn author(&self) -> Option { self.0.get("Author").or_else(|| self.0.get("From")) } /// Set the author of the patch. pub fn set_author(&mut self, author: &str) { if self.0.contains_key("From") { self.0.insert("From", author); } else { self.0.insert("Author", author); } } /// The `Reviewed-By` field. pub fn reviewed_by(&self) -> Vec { self.0.get_all("Reviewed-By").collect() } /// Get the last update date of the patch. pub fn last_update(&self) -> Option { self.0 .get("Last-Update") .as_deref() .and_then(|s| chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d").ok()) } /// Set the date of the last update pub fn set_last_update(&mut self, date: chrono::NaiveDate) { self.0 .insert("Last-Update", date.format("%Y-%m-%d").to_string().as_str()); } /// The `Applied-Upstream` field. pub fn applied_upstream(&self) -> Option { self.0 .get("Applied-Upstream") .as_deref() .map(|s| s.parse().unwrap()) } /// Set the `Applied-Upstream` field. pub fn set_applied_upstream(&mut self, applied_upstream: AppliedUpstream) { self.0 .insert("Applied-Upstream", applied_upstream.to_string().as_str()); } /// Get the bugs associated with the patch. pub fn bugs(&self) -> impl Iterator, String)> + '_ { self.0.items().filter_map(|(k, v)| { if k.starts_with("Bug-") { Some((Some(k.strip_prefix("Bug-").unwrap().to_string()), v)) } else if k == "Bug" { Some((None, v)) } else { None } }) } /// Get the bugs associated with a specific vendor. pub fn vendor_bugs<'a>(&'a self, vendor: &'a str) -> impl Iterator + '_ { self.bugs().filter_map(|(k, v)| { if k == Some(vendor.to_string()) { Some(v) } else { None } }) } /// Set the upstream bug associated with the patch. pub fn set_upstream_bug(&mut self, bug: &str) { self.0.insert("Bug", bug); } /// Set the bug associated with a specific vendor. pub fn set_vendor_bug(&mut self, vendor: &str, bug: &str) { self.0.insert(format!("Bug-{}", vendor).as_str(), bug); } /// Get the description or subject field. fn description_field(&self) -> Option { self.0.get("Description").or_else(|| self.0.get("Subject")) } /// Get the description of the patch. pub fn description(&self) -> Option { self.description_field() .as_deref() .map(|s| s.split('\n').next().unwrap_or(s).to_string()) } /// Set the description of the patch. pub fn set_description(&mut self, description: &str) { if let Some(subject) = self.0.get("Subject") { // Replace the first line with ours let new = format!( "{}\n{}", description, subject.split_once('\n').map(|x| x.1).unwrap_or("") ); self.0.insert("Subject", new.as_str()); } else if let Some(description) = self.0.get("Description") { // Replace the first line with ours let new = format!( "{}\n{}", description.split_once('\n').map(|x| x.1).unwrap_or(""), description ); self.0.insert("Description", new.as_str()); } else { self.0.insert("Description", description); } } /// Get the long description of the patch. pub fn long_description(&self) -> Option { self.description_field() .as_deref() .map(|s| s.split_once('\n').map(|x| x.1).unwrap_or("").to_string()) } /// Set the long description of the patch. pub fn set_long_description(&mut self, long_description: &str) { if let Some(subject) = self.0.get("Subject") { // Keep the first line, but replace the rest with our text let first_line = subject .split_once('\n') .map(|x| x.0) .unwrap_or(subject.as_str()); let new = format!("{}\n{}", first_line, long_description); self.0.insert("Subject", new.as_str()); } else if let Some(description) = self.0.get("Description") { // Keep the first line, but replace the rest with our text let first_line = description .split_once('\n') .map(|x| x.0) .unwrap_or(description.as_str()); let new = format!("{}\n{}", first_line, long_description); self.0.insert("Description", new.as_str()); } else { self.0.insert("Description", long_description); } } /// Write the patch header pub fn write(&self, writer: &mut W) -> std::io::Result<()> { writer.write_all(self.to_string().as_bytes()) } } impl std::fmt::Display for PatchHeader { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0.to_string()) } } impl Default for PatchHeader { fn default() -> Self { Self::new() } } impl std::str::FromStr for PatchHeader { type Err = deb822_lossless::ParseError; fn from_str(s: &str) -> Result { Ok(PatchHeader(Paragraph::from_str(s)?)) } } #[cfg(test)] mod tests { use super::PatchHeader; use std::str::FromStr; #[test] fn test_upstream() { let text = r#"From: Ulrich Drepper Subject: Fix regex problems with some multi-bytes characters * posix/bug-regex17.c: Add testcases. * posix/regcomp.c (re_compile_fastmap_iter): Rewrite COMPLEX_BRACKET handling. Origin: upstream, http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=bdb56bac Bug: http://sourceware.org/bugzilla/show_bug.cgi?id=9697 Bug-Debian: http://bugs.debian.org/510219 "#; let header = PatchHeader::from_str(text).unwrap(); assert_eq!( header.origin(), Some(( Some(super::OriginCategory::Upstream), super::Origin::Other( "http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=bdb56bac".to_string() ) )) ); assert_eq!(header.forwarded(), None); assert_eq!( header.author(), Some("Ulrich Drepper ".to_string()) ); assert_eq!(header.reviewed_by(), Vec::<&str>::new()); assert_eq!(header.last_update(), None); assert_eq!(header.applied_upstream(), None); assert_eq!( header.bugs().collect::>(), vec![ ( None, "http://sourceware.org/bugzilla/show_bug.cgi?id=9697".to_string() ), ( Some("Debian".to_string()), "http://bugs.debian.org/510219".to_string() ), ] ); assert_eq!( header.description(), Some("Fix regex problems with some multi-bytes characters".to_string()) ); } #[test] fn test_forwarded() { let text = r#"Description: Use FHS compliant paths by default Upstream is not interested in switching to those paths. . But we will continue using them in Debian nevertheless to comply with our policy. Forwarded: http://lists.example.com/oct-2006/1234.html Author: John Doe Last-Update: 2006-12-21 "#; let header = PatchHeader::from_str(text).unwrap(); assert_eq!(header.origin(), None); assert_eq!( header.forwarded(), Some(super::Forwarded::Yes( "http://lists.example.com/oct-2006/1234.html".to_string() )) ); assert_eq!( header.author(), Some("John Doe ".to_string()) ); assert_eq!(header.reviewed_by(), Vec::<&str>::new()); assert_eq!( header.last_update(), Some(chrono::NaiveDate::from_ymd_opt(2006, 12, 21).unwrap()) ); assert_eq!(header.applied_upstream(), None); assert_eq!(header.bugs().collect::>(), vec![]); assert_eq!( header.description(), Some("Use FHS compliant paths by default".to_string()) ); } #[test] fn test_not_forwarded() { let text = r#"Description: Workaround for broken symbol resolving on mips/mipsel The correct fix will be done in etch and it will require toolchain fixes. Forwarded: not-needed Origin: vendor, http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=80;bug=265678 Bug-Debian: http://bugs.debian.org/265678 Author: Thiemo Seufer "#; let header = PatchHeader::from_str(text).unwrap(); assert_eq!( header.origin(), Some(( Some(super::OriginCategory::Vendor), super::Origin::Other( "http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=80;bug=265678".to_string() ) )) ); assert_eq!(header.forwarded(), Some(super::Forwarded::NotNeeded)); assert_eq!( header.author(), Some("Thiemo Seufer ".to_string()) ); assert_eq!(header.reviewed_by(), Vec::<&str>::new()); assert_eq!(header.last_update(), None); assert_eq!(header.applied_upstream(), None); assert_eq!( header.bugs().collect::>(), vec![( Some("Debian".to_string()), "http://bugs.debian.org/265678".to_string() ),] ); assert_eq!( header.description(), Some("Workaround for broken symbol resolving on mips/mipsel".to_string()) ); } #[test] fn test_applied_upstream() { let text = r#"Description: Fix widget frobnication speeds Frobnicating widgets too quickly tended to cause explosions. Forwarded: http://lists.example.com/2010/03/1234.html Author: John Doe Applied-Upstream: 1.2, http://bzr.example.com/frobnicator/trunk/revision/123 Last-Update: 2010-03-29 "#; let header = PatchHeader::from_str(text).unwrap(); assert_eq!(header.origin(), None); assert_eq!( header.forwarded(), Some(super::Forwarded::Yes( "http://lists.example.com/2010/03/1234.html".to_string() )) ); assert_eq!( header.author(), Some("John Doe ".to_string()) ); assert_eq!(header.reviewed_by(), Vec::<&str>::new()); assert_eq!( header.last_update(), Some(chrono::NaiveDate::from_ymd_opt(2010, 3, 29).unwrap()) ); assert_eq!( header.applied_upstream(), Some(super::AppliedUpstream::Other( "1.2, http://bzr.example.com/frobnicator/trunk/revision/123".to_string() )) ); assert_eq!(header.bugs().collect::>(), vec![]); assert_eq!( header.description(), Some("Fix widget frobnication speeds".to_string()) ); } #[test] fn test_vendor_bugs() { let text = r#"Description: Fix widget frobnication speeds Bug: http://bugs.example.com/123 Bug-Debian: http://bugs.debian.org/123 Bug-Ubuntu: http://bugs.launchpad.net/123 "#; let header = PatchHeader::from_str(&text).unwrap(); assert_eq!( header.vendor_bugs("Debian").collect::>(), vec!["http://bugs.debian.org/123".to_string()] ); assert_eq!( header.vendor_bugs("Ubuntu").collect::>(), vec!["http://bugs.launchpad.net/123".to_string()] ); } } dep3-0.1.28/src/lossy.rs000064400000000000000000000223071046102023000130610ustar 00000000000000//! A library for parsing and generating Debian patch headers. //! //! # Examples //! //! ```rust //! use dep3::lossy::PatchHeader; //! use std::str::FromStr; //! let text = r#"From: John Doe //! Date: Mon, 1 Jan 2000 00:00:00 +0000 //! Subject: [PATCH] fix a bug //! Bug-Debian: https://bugs.debian.org/123456 //! Bug: https://bugzilla.example.com/bug.cgi?id=123456 //! Forwarded: not-needed //! "#; //! //! let patch_header = PatchHeader::from_str(text).unwrap(); //! assert_eq!(patch_header.description, Some("[PATCH] fix a bug".to_string())); //! assert_eq!(patch_header.bug_debian, Some("https://bugs.debian.org/123456".parse().unwrap())); //! ``` use crate::fields::*; use deb822_lossless::Paragraph; use deb822_lossless::{FromDeb822, FromDeb822Paragraph, ToDeb822, ToDeb822Paragraph}; fn deserialize_date(s: &str) -> Result { chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d").map_err(|e| e.to_string()) } fn serialize_date(date: &chrono::NaiveDate) -> String { date.format("%Y-%m-%d").to_string() } fn deserialize_origin(s: &str) -> Result<(Option, Origin), String> { Ok(crate::fields::parse_origin(s)) } fn serialize_origin((category, origin): &(Option, Origin)) -> String { crate::fields::format_origin(category, origin) } /// A patch header. #[derive(Debug, Clone, PartialEq, FromDeb822, ToDeb822)] pub struct PatchHeader { #[deb822(field = "Origin", serialize_with = serialize_origin, deserialize_with = deserialize_origin)] /// The origin of the patch. pub origin: Option<(Option, Origin)>, #[deb822(field = "Forwarded")] /// Whether the patch has been forwarded upstream. pub forwarded: Option, #[deb822(field = "Author")] /// The author of the patch. pub author: Option, #[deb822(field = "Reviewed-by")] /// The person who reviewed the patch. pub reviewed_by: Option, #[deb822(field = "Bug-Debian")] /// The URL of the Debian bug report. pub bug_debian: Option, #[deb822(field = "Last-Update", deserialize_with = deserialize_date, serialize_with = serialize_date)] /// The date of the last update. pub last_update: Option, #[deb822(field = "Applied-Upstream")] /// Whether the patch has been applied upstream. pub applied_upstream: Option, #[deb822(field = "Bug")] /// The URL of the upstream bug report. pub bug: Option, #[deb822(field = "Description")] /// The description of the patch. pub description: Option, } impl std::fmt::Display for PatchHeader { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let paragraph: deb822_lossless::lossy::Paragraph = self.to_paragraph(); paragraph.fmt(f) } } impl std::str::FromStr for PatchHeader { type Err = String; fn from_str(s: &str) -> Result { let paragraph = Paragraph::from_str(s).map_err(|e| e.to_string())?; let mut header = PatchHeader::from_paragraph(¶graph)?; if header.author.is_none() { header.author = paragraph.get("From").map(|v| v.to_string()); } if header.description.is_none() { header.description = paragraph.get("Subject").map(|v| v.to_string()); } Ok(header) } } #[cfg(test)] mod tests { use super::PatchHeader; #[test] fn test_upstream() { let text = r#"From: Ulrich Drepper Subject: Fix regex problems with some multi-bytes characters * posix/bug-regex17.c: Add testcases. * posix/regcomp.c (re_compile_fastmap_iter): Rewrite COMPLEX_BRACKET handling. Origin: upstream, http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=bdb56bac Bug: http://sourceware.org/bugzilla/show_bug.cgi?id=9697 Bug-Debian: http://bugs.debian.org/510219 "#; let header: PatchHeader = text.parse().unwrap(); assert_eq!( header.origin, Some(( Some(super::OriginCategory::Upstream), super::Origin::Other( "http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=bdb56bac".to_string() ) )) ); assert_eq!(header.forwarded, None); assert_eq!( header.author, Some("Ulrich Drepper ".to_string()) ); assert_eq!(header.reviewed_by, None); assert_eq!(header.last_update, None); assert_eq!(header.applied_upstream, None); assert_eq!( header.bug, "http://sourceware.org/bugzilla/show_bug.cgi?id=9697" .parse() .ok() ); assert_eq!( header.bug_debian, "http://bugs.debian.org/510219".parse().ok() ); assert_eq!( header.description, Some("Fix regex problems with some multi-bytes characters\n* posix/bug-regex17.c: Add testcases.\n* posix/regcomp.c (re_compile_fastmap_iter): Rewrite COMPLEX_BRACKET\nhandling.".to_string()) ); } #[test] fn test_forwarded() { let text = r#"Description: Use FHS compliant paths by default Upstream is not interested in switching to those paths. . But we will continue using them in Debian nevertheless to comply with our policy. Forwarded: http://lists.example.com/oct-2006/1234.html Author: John Doe Last-Update: 2006-12-21 "#; let header: PatchHeader = text.parse().unwrap(); assert_eq!(header.origin, None); assert_eq!( header.forwarded, Some(super::Forwarded::Yes( "http://lists.example.com/oct-2006/1234.html".to_string() )) ); assert_eq!( header.author, Some("John Doe ".to_string()) ); assert_eq!(header.reviewed_by, None); assert_eq!( header.last_update, Some(chrono::NaiveDate::from_ymd_opt(2006, 12, 21).unwrap()) ); assert_eq!(header.applied_upstream, None); assert_eq!( header.description, Some("Use FHS compliant paths by default\nUpstream is not interested in switching to those paths.\n.\nBut we will continue using them in Debian nevertheless to comply with\nour policy.".to_string()) ); } #[test] fn test_not_forwarded() { let text = r#"Description: Workaround for broken symbol resolving on mips/mipsel The correct fix will be done in etch and it will require toolchain fixes. Forwarded: not-needed Origin: vendor, http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=80;bug=265678 Bug-Debian: http://bugs.debian.org/265678 Author: Thiemo Seufer "#; let header: PatchHeader = text.parse().unwrap(); assert_eq!( header.origin, Some(( Some(super::OriginCategory::Vendor), super::Origin::Other( "http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=80;bug=265678".to_string() ) )) ); assert_eq!(header.forwarded, Some(super::Forwarded::NotNeeded)); assert_eq!( header.author, Some("Thiemo Seufer ".to_string()) ); assert_eq!(header.reviewed_by, None); assert_eq!(header.last_update, None); assert_eq!(header.applied_upstream, None); assert_eq!( header.bug_debian, "http://bugs.debian.org/265678".parse().ok() ); assert_eq!( header.description, Some( "Workaround for broken symbol resolving on mips/mipsel The correct fix will be done in etch and it will require toolchain fixes." .to_string() ) ); } #[test] fn test_applied_upstream() { let text = r#"Description: Fix widget frobnication speeds Frobnicating widgets too quickly tended to cause explosions. Forwarded: http://lists.example.com/2010/03/1234.html Author: John Doe Applied-Upstream: 1.2, http://bzr.example.com/frobnicator/trunk/revision/123 Last-Update: 2010-03-29 "#; let header: PatchHeader = text.parse().unwrap(); assert_eq!(header.origin, None); assert_eq!( header.forwarded, Some(super::Forwarded::Yes( "http://lists.example.com/2010/03/1234.html".to_string() )) ); assert_eq!( header.author, Some("John Doe ".to_string()) ); assert_eq!(header.reviewed_by, None); assert_eq!( header.last_update, Some(chrono::NaiveDate::from_ymd_opt(2010, 3, 29).unwrap()) ); assert_eq!( header.applied_upstream, Some(super::AppliedUpstream::Other( "1.2, http://bzr.example.com/frobnicator/trunk/revision/123".to_string() )) ); assert_eq!( header.description, Some("Fix widget frobnication speeds\nFrobnicating widgets too quickly tended to cause explosions.".to_string()) ); } }