dep3-0.2.2/.cargo_vcs_info.json0000644000000001421046102023000117070ustar { "git": { "sha1": "5c8df6644a4fe72b6b25474420fdb02594f4d968" }, "path_in_vcs": "dep3" }dep3-0.2.2/.gitignore000064400000000000000000000000101046102023000124370ustar 00000000000000/target dep3-0.2.2/Cargo.lock0000644000000451771046102023000077030ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "aho-corasick" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[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.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bumpalo" version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "cc" version = "1.2.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" dependencies = [ "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-link", ] [[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.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83ef29a094bcb2b7dd0f609ace7f5a34ef9a62e0731ebd350637640320a3b15" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "deb822-fast" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "114c474fa4cd5d6d24bb5e68b36fa4ef70f5b830e3cc14a9b66a12e71a15aeb9" dependencies = [ "deb822-derive", ] [[package]] name = "deb822-lossless" version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3010ab21b879670c60b013a500a9afe82094921707b151a4dac4a17f5676134f" dependencies = [ "regex", "rowan", "serde", ] [[package]] name = "dep3" version = "0.2.2" dependencies = [ "chrono", "deb822-fast", "deb822-lossless", "url", ] [[package]] name = "displaydoc" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "futures-core" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-task" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-task", "pin-project-lite", "slab", ] [[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.65" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "log", "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 = "icu_collections" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", "utf8_iter", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_normalizer" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", "writeable", "yoke", "zerofrom", "zerotrie", "zerovec", ] [[package]] name = "idna" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", "utf8_iter", ] [[package]] name = "idna_adapter" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", ] [[package]] name = "js-sys" version = "0.3.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf" dependencies = [ "cfg-if", "futures-util", "once_cell", "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "litemap" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[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.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "potential_utf" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] [[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rowan" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" 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 = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 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 = "slab" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "text-size" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233" [[package]] name = "tinystr" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "url" version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", ] [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "wasm-bindgen" version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41" dependencies = [ "bumpalo", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.120" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea" dependencies = [ "unicode-ident", ] [[package]] name = "windows-core" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-interface" version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] [[package]] name = "writeable" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yoke" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] [[package]] name = "zerotrie" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", "zerofrom", ] [[package]] name = "zerovec" version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", "syn", ] dep3-0.2.2/Cargo.toml0000644000000026221046102023000077120ustar # 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.2.2" 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" [badges.maintenance] status = "actively-maintained" [features] default = ["lossless"] lossless = ["dep:deb822-lossless"] [lib] name = "dep3" path = "src/lib.rs" [[example]] name = "read-dep3" path = "examples/read-dep3.rs" [dependencies.chrono] version = ">=0.4, <0.5" [dependencies.deb822-fast] version = ">=0.1, <0.3" features = ["derive"] [dependencies.deb822-lossless] version = ">=0.2, <0.6" optional = true [dependencies.url] version = ">=2, <3" dep3-0.2.2/Cargo.toml.orig000064400000000000000000000013171046102023000133510ustar 00000000000000[package] name = "dep3" edition = "2021" license = "Apache-2.0" version = "0.2.2" 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, <0.5" deb822-lossless = { path = "../deb822-lossless", version = ">=0.2, <0.6", optional = true } deb822-fast = { path = "../deb822-fast", version = ">=0.1, <0.3", features = ["derive"] } url = ">=2, <3" [features] default = ["lossless"] lossless = ["dep:deb822-lossless"] [badges] maintenance = { status = "actively-maintained" } dep3-0.2.2/README.md000064400000000000000000000013071046102023000117400ustar 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.2.2/disperse.conf000064400000000000000000000000461046102023000131450ustar 00000000000000timeout_days: 5 tag_name: "v$VERSION" dep3-0.2.2/examples/read-dep3.rs000064400000000000000000000014021046102023000144050ustar 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 = match PatchHeader::from_str(TEXT) { Ok(header) => header, Err(e) => { eprintln!("Failed to parse patch header: {}", e); std::process::exit(1); } }; if let Some(description) = &patch_header.description { println!("Description: {}", description); } if let Some(bug_debian) = &patch_header.bug_debian { println!("Debian Bugs: {}", bug_debian); } } dep3-0.2.2/src/fields.rs000064400000000000000000000133071046102023000130670ustar 00000000000000use std::borrow::Cow; /// 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(Cow<'static, str>), } 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(Cow::Owned(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(Cow<'static, str>), /// Some other origin Other(Cow<'static, str>), } 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), } } } 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(Cow::Owned(rest.to_string()))) } else { Ok(Origin::Other(Cow::Owned(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(Cow<'static, str>), /// The patch has been applied in the upstream project, in the specified reference. Other(Cow<'static, str>), } 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), } } } 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(Cow::Owned(rest.to_string()))) } else { Ok(AppliedUpstream::Other(Cow::Owned(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(Cow::Owned(rest.to_string()))) } else { (category, Origin::Other(Cow::Owned(s.to_string()))) } } pub(crate) fn format_origin(category: &Option, origin: &Origin) -> String { format!( "{}{}", category.map(|c| c.to_string() + ", ").unwrap_or_default(), origin ) } #[cfg(test)] mod tests { use super::*; #[test] fn test_forwarded_display() { assert_eq!(Forwarded::No.to_string(), "no"); assert_eq!(Forwarded::Yes(Cow::Borrowed("url")).to_string(), "url"); assert_eq!(Forwarded::NotNeeded.to_string(), "not-needed"); } #[test] fn test_applied_upstream_display() { let commit = AppliedUpstream::Commit(Cow::Borrowed("abc123")); assert_eq!(commit.to_string(), "commit:abc123"); let other = AppliedUpstream::Other(Cow::Borrowed("merged")); assert_eq!(other.to_string(), "merged"); } } dep3-0.2.2/src/lib.rs000064400000000000000000000014441046102023000123660ustar 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"), Some("https://bugs.debian.org/123456")); //! ``` mod fields; pub use fields::*; #[cfg(feature = "lossless")] pub mod lossless; pub mod lossy; pub use lossy::PatchHeader; dep3-0.2.2/src/lossless.rs000064400000000000000000000435221046102023000134720ustar 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 + 'a { 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)?)) } } /// Find the byte offset where the DEP-3 header in `content` ends, i.e. /// the start of the first `---` / `diff ` / `Index:` line. Returns /// `content.len()` if the file is header-only (no diff body). /// /// This lets callers split a complete patch file into its header (a /// deb822 paragraph) and its unified diff (which DEP-3 leaves /// unspecified). Both [`parse_relaxed`](PatchHeader::parse_relaxed) and /// the lossy [`crate::lossy::PatchHeader`] use this internally; it's /// exposed for callers that need to map source ranges back into the /// original file. pub fn header_end(content: &str) -> usize { let mut offset = 0; for line in content.split_inclusive('\n') { let trimmed = line.trim_end_matches(['\r', '\n']); if trimmed.starts_with("---") || trimmed.starts_with("diff ") || trimmed.starts_with("Index:") { return offset; } offset += line.len(); } content.len() } impl PatchHeader { /// Parse a patch file's DEP-3 header, tolerating a trailing unified /// diff body. Splits `content` at the first `---` / `diff ` / /// `Index:` line and parses only the header portion. /// /// Returns the parsed header and the byte offset where the diff /// body starts (equal to `content.len()` if there is no diff body). /// Use this for files like `debian/patches/foo.patch` where the /// caller has the whole file in hand and wants just the header. /// /// `from_str` parses the input as deb822 in its entirety and will /// fail (or, with malformed continuations, misparse) when handed a /// patch with diff content; `parse_relaxed` is the appropriate /// entry point for that case. pub fn parse_relaxed(content: &str) -> Result<(Self, usize), deb822_lossless::ParseError> { use std::str::FromStr; let end = header_end(content); let header = PatchHeader::from_str(&content[..end])?; Ok((header, end)) } } #[cfg(test)] mod tests { use super::PatchHeader; use std::borrow::Cow; 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(Cow::Borrowed( "http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=bdb56bac" )) )) ); 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(Cow::Borrowed( "http://lists.example.com/oct-2006/1234.html" ))) ); 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(Cow::Borrowed( "http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=80;bug=265678" )) )) ); 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(Cow::Borrowed( "http://lists.example.com/2010/03/1234.html" ))) ); 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(Cow::Borrowed( "1.2, http://bzr.example.com/frobnicator/trunk/revision/123" ))) ); 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()] ); } #[test] fn parse_relaxed_splits_at_dashes() { let text = "Author: alice\nDescription: bla\n---\n@@ -1 +1 @@\n-x\n+y\n"; let (header, end) = PatchHeader::parse_relaxed(text).unwrap(); assert_eq!(end, "Author: alice\nDescription: bla\n".len()); assert_eq!(header.author(), Some("alice".to_string())); assert_eq!(header.description(), Some("bla".to_string())); } #[test] fn parse_relaxed_splits_at_diff_word() { let text = "Author: alice\ndiff --git a/foo b/foo\n"; let (header, end) = PatchHeader::parse_relaxed(text).unwrap(); assert_eq!(end, "Author: alice\n".len()); assert_eq!(header.author(), Some("alice".to_string())); } #[test] fn parse_relaxed_splits_at_index_marker() { let text = "Author: alice\nIndex: foo\n@@ -1 +1 @@\n"; let (header, end) = PatchHeader::parse_relaxed(text).unwrap(); assert_eq!(end, "Author: alice\n".len()); assert_eq!(header.author(), Some("alice".to_string())); } #[test] fn parse_relaxed_handles_header_only() { let text = "Author: alice\nDescription: bla\n"; let (header, end) = PatchHeader::parse_relaxed(text).unwrap(); assert_eq!(end, text.len()); assert_eq!(header.author(), Some("alice".to_string())); } #[test] fn header_end_handles_empty() { assert_eq!(super::header_end(""), 0); } #[test] fn test_set_last_update() { let text = r#"Description: Fix widget frobnication speeds "#; let mut header = PatchHeader::from_str(text).unwrap(); let date = chrono::NaiveDate::from_ymd_opt(2023, 5, 15).unwrap(); header.set_last_update(date); assert_eq!(header.last_update(), Some(date)); } } dep3-0.2.2/src/lossy.rs000064400000000000000000000227171046102023000127770ustar 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_fast::{FromDeb822, FromDeb822Paragraph, Paragraph, 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 PatchHeader { /// Create a new patch header. pub fn vendor_bugs(&self, vendor: &str) -> Option<&str> { match vendor { "Debian" => self.bug_debian.as_ref().map(|u| u.as_str()), _ => None, } } } impl std::fmt::Display for PatchHeader { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let paragraph: deb822_fast::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(ToString::to_string); } if header.description.is_none() { header.description = paragraph.get("Subject").map(ToString::to_string); } Ok(header) } } #[cfg(test)] mod tests { use super::PatchHeader; use std::borrow::Cow; #[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(Cow::Borrowed( "http://sourceware.org/git/?p=glibc.git;a=commitdiff;h=bdb56bac" )) )) ); 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\n* posix/bug-regex17.c: Add testcases.\n* posix/regcomp.c (re_compile_fastmap_iter): Rewrite COMPLEX_BRACKET\nhandling.\n".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(Cow::Borrowed( "http://lists.example.com/oct-2006/1234.html" ))) ); 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(Cow::Borrowed( "http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=80;bug=265678" )) )) ); 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(Cow::Borrowed( "http://lists.example.com/2010/03/1234.html" ))) ); 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(Cow::Borrowed( "1.2, http://bzr.example.com/frobnicator/trunk/revision/123" ))) ); assert_eq!( header.description, Some("Fix widget frobnication speeds\nFrobnicating widgets too quickly tended to cause explosions.".to_string()) ); } }