dep3-0.1.13/.cargo_vcs_info.json0000644000000001420000000000100117460ustar { "git": { "sha1": "de8ee9189fd3aaeda9b4d3f41219c2425a79c6e4" }, "path_in_vcs": "dep3" }dep3-0.1.13/.gitignore000064400000000000000000000000101046102023000125200ustar 00000000000000/target dep3-0.1.13/Cargo.lock0000644000000256670000000000100077440ustar # 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.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" [[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.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[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.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9086252eef3fadf8ba2090c0dff8da6ff7bbfd04baf15b094f55cc12f1c9fc5" dependencies = [ "regex", "rowan", "serde", ] [[package]] name = "dep3" version = "0.1.13" dependencies = [ "chrono", "deb822-lossless", ] [[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.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 = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[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 = "proc-macro2" version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 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.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49" dependencies = [ "countme", "hashbrown", "memoffset", "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.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "syn" version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" 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 = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[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.13/Cargo.toml0000644000000015140000000000100077500ustar # 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.13" description = "A library for parsing and generating DEP-3 headers." 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" [dependencies.deb822-lossless] version = ">=0.1.9" dep3-0.1.13/Cargo.toml.orig000064400000000000000000000005531046102023000134330ustar 00000000000000[package] name = "dep3" version = { workspace = true } edition = "2021" license = "Apache-2.0" description = "A library for parsing and generating DEP-3 headers." homepage = "https://github.com/jelmer/deb822-lossless" repository = "https://github.com/jelmer/deb822-lossless" [dependencies] chrono = ">=0.4" deb822-lossless = { path = "..", version = ">=0.1.9" } dep3-0.1.13/README.md000064400000000000000000000013071046102023000120210ustar 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.13/disperse.conf000064400000000000000000000000461046102023000132260ustar 00000000000000timeout_days: 5 tag_name: "v$VERSION" dep3-0.1.13/examples/read-dep3.rs000064400000000000000000000010371046102023000144720ustar 00000000000000use dep3::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.vendor_bugs("Debian").collect::>().join(", ")); } dep3-0.1.13/src/lib.rs000064400000000000000000000404361046102023000124530ustar 00000000000000//! 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()]); //! ``` use deb822_lossless::Paragraph; pub struct PatchHeader(Paragraph); #[derive(Debug, PartialEq, Eq)] pub enum Forwarded { No, NotNeeded, 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())), } } } #[derive(Debug, PartialEq, Eq)] 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, 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"), } } } #[derive(Debug, PartialEq, Eq)] pub enum Origin { Commit(String), 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())) } } } #[derive(Debug, PartialEq, Eq)] pub enum AppliedUpstream { Commit(String), 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 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())) } } impl PatchHeader { pub fn new() -> Self { PatchHeader(Paragraph::new()) } pub fn origin(&self) -> Option<(Option, Origin)> { self.0.get("Origin").as_deref().map(parse_origin) } pub fn set_origin(&mut self, category: Option, origin: Origin) { self.0.insert( "Origin", format!( "{}{}", category.map(|c| c.to_string() + ", ").unwrap_or_default(), origin.to_string() ) .as_str(), ); } pub fn forwarded(&self) -> Option { self.0 .get("Forwarded") .as_deref() .map(|s| s.parse().unwrap()) } pub fn set_forwarded(&mut self, forwarded: Forwarded) { self.0.insert("Forwarded", forwarded.to_string().as_str()); } pub fn author(&self) -> Option { self.0.get("Author").or_else(|| self.0.get("From")) } 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); } } pub fn reviewed_by(&self) -> Vec { self.0.get_all("Reviewed-By").collect() } 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()) } pub fn set_last_update(&mut self, date: chrono::NaiveDate) { self.0 .insert("Last-Update", date.format("%Y-%m-%d").to_string().as_str()); } pub fn applied_upstream(&self) -> Option { self.0 .get("Applied-Upstream") .as_deref() .map(|s| s.parse().unwrap()) } pub fn set_applied_upstream(&mut self, applied_upstream: AppliedUpstream) { self.0 .insert("Applied-Upstream", applied_upstream.to_string().as_str()); } 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 } }) } 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 } }) } pub fn set_upstream_bug(&mut self, bug: &str) { self.0.insert("Bug", bug); } pub fn set_vendor_bug(&mut self, vendor: &str, bug: &str) { self.0.insert(format!("Bug-{}", vendor).as_str(), bug); } fn description_field(&self) -> Option { self.0.get("Description").or_else(|| self.0.get("Subject")) } pub fn description(&self) -> Option { self.description_field() .as_deref() .map(|s| s.split('\n').next().unwrap_or(s).to_string()) } 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); } } 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()) } 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); } } 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(2006, 12, 21)) ); 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(2010, 3, 29)) ); 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()) ); } }