From 0037bca01749cb9bb0d1077852b2da0b6667e29a Mon Sep 17 00:00:00 2001 From: arcayr Date: Mon, 30 Sep 2024 03:56:26 +1000 Subject: [PATCH] init: first cut. library only. tests provide coverage of path for local file inclusion for a package build. --- .gitignore | 2 + Cargo.lock | 2609 +++++++++++++++++ Cargo.toml | 3 + crates/ia/Cargo.toml | 24 + crates/ia/src/composer/mod.rs | 81 + crates/ia/src/error.rs | 102 + crates/ia/src/hash.rs | 140 + crates/ia/src/lib.rs | 163 + crates/ia/src/manifest/mod.rs | 320 ++ crates/ia/src/phase/fetch/file.rs | 62 + crates/ia/src/phase/fetch/mod.rs | 77 + crates/ia/src/phase/mod.rs | 1 + crates/tests/Cargo.toml | 10 + crates/tests/fixtures/package/manifest.toml | 28 + crates/tests/fixtures/package/source-test.txt | 1 + crates/tests/src/hash.rs | 51 + crates/tests/src/lib.rs | 3 + crates/tests/src/manifest/mod.rs | 31 + crates/tests/src/phase/fetch/mod.rs | 71 + crates/tests/src/phase/mod.rs | 1 + readme.md | 10 +- 21 files changed, 3788 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 crates/ia/Cargo.toml create mode 100644 crates/ia/src/composer/mod.rs create mode 100644 crates/ia/src/error.rs create mode 100644 crates/ia/src/hash.rs create mode 100644 crates/ia/src/lib.rs create mode 100644 crates/ia/src/manifest/mod.rs create mode 100644 crates/ia/src/phase/fetch/file.rs create mode 100644 crates/ia/src/phase/fetch/mod.rs create mode 100644 crates/ia/src/phase/mod.rs create mode 100644 crates/tests/Cargo.toml create mode 100644 crates/tests/fixtures/package/manifest.toml create mode 100644 crates/tests/fixtures/package/source-test.txt create mode 100644 crates/tests/src/hash.rs create mode 100644 crates/tests/src/lib.rs create mode 100644 crates/tests/src/manifest/mod.rs create mode 100644 crates/tests/src/phase/fetch/mod.rs create mode 100644 crates/tests/src/phase/mod.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..81cf465 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/.vscode diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b89a32a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2609 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "ar" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cap-primitives" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff5bcbaf57897c8f14098cc9ad48a78052930a9948119eea01b80ca224070fa6" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix", + "windows-sys 0.52.0", + "winx", +] + +[[package]] +name = "cap-std" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6cf1a22e6eab501e025a9953532b1e95efb8a18d6364bf8a4a7547b30c49186" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix", +] + +[[package]] +name = "cap-tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8563f37bd2d9ec79a08dc6b062b6733adc84f929d23f45388ba52025c7b32e26" +dependencies = [ + "cap-std", + "rand 0.8.5", + "rustix", + "uuid", +] + +[[package]] +name = "cc" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "copy_on_write" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231be9abfd4fd31196f0e2ba13b314391969131530e14d84d2b9e954ff27d509" +dependencies = [ + "env_logger", + "lazy_static", + "log", + "reflink-copy", + "tempfile", + "widestring", + "windows 0.51.1", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "decompress" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67605f4868a37e8a9c50003a866a6896104602d5d7ddf7e8a7f398ec97e44ab3" +dependencies = [ + "ar", + "bzip2", + "derive_builder", + "flate2", + "infer", + "lazy_static", + "regex", + "tar", + "thiserror", + "unrar", + "xz", + "zip", + "zstd 0.12.4", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum_primitive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" +dependencies = [ + "num-traits 0.1.43", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[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 = "fs-set-times" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033b337d725b97690d86893f9de22b67b80dcc4e9ad815f348254c38119db8fb" +dependencies = [ + "io-lifetimes", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "ia" +version = "0.1.0" +dependencies = [ + "base16ct", + "bytes", + "cap-std", + "cap-tempfile", + "copy_on_write", + "decompress", + "digest", + "hex", + "reqwest", + "serde", + "sha2", + "sha3", + "strum", + "tar", + "thiserror", + "toml", + "tracing", + "url", +] + +[[package]] +name = "ia-tests" +version = "0.1.0" +dependencies = [ + "cap-tempfile", + "ia", + "toml", + "url", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[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 = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "infer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a898e4b7951673fce96614ce5751d13c40fc5674bc2d759288e46c3ab62598b3" +dependencies = [ + "cfb", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "io-extras" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9f046b9af244f13b3bd939f55d16830ac3a201e8a9ba9661bfcb03e2be72b9b" +dependencies = [ + "io-lifetimes", + "windows-sys 0.52.0", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a611371471e98973dbcab4e0ec66c31a10bc356eeb4d54a0e05eac8158fe38c" + +[[package]] +name = "ipnet" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[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 = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits 0.2.19", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +dependencies = [ + "num-integer", + "num-traits 0.2.19", + "rand 0.4.6", + "rustc-serialize", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" +dependencies = [ + "num-traits 0.2.19", + "rustc-serialize", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits 0.2.19", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.19", +] + +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits 0.2.19", + "rustc-serialize", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.19", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[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.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "reflink-copy" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc31414597d1cd7fdd2422798b7652a6329dda0fe0219e6335a13d5bcaa9aeb6" +dependencies = [ + "cfg-if", + "rustix", + "windows 0.58.0", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-serialize" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401" + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags 2.6.0", + "errno", + "itoa", + "libc", + "linux-raw-sys", + "once_cell", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[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 2.0.77", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.77", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[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 = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.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 = "unrar" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cea4f0b7bec88d47becb380887b8786a3cfb1c82e1ef9d32a682ba6801814" +dependencies = [ + "bitflags 1.3.2", + "enum_primitive", + "lazy_static", + "num", + "regex", + "unrar_sys", +] + +[[package]] +name = "unrar_sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0009399408dc0bcc5c8910672544fceceeba18b91f741ff943916e917d982c60" +dependencies = [ + "cc", + "libc", + "winapi", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[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", + "serde", +] + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[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 2.0.77", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[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 2.0.77", + "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 = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" +dependencies = [ + "windows-core 0.51.1", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + +[[package]] +name = "winx" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346" +dependencies = [ + "bitflags 2.6.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "xz" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c887690ff2a2e233e8e49633461521f98ec57fbff9d59a884c9a4f04ec1da34" +dependencies = [ + "xz2", +] + +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe 6.0.6", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a848b85 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +resolver = "2" +members = ["crates/*"] diff --git a/crates/ia/Cargo.toml b/crates/ia/Cargo.toml new file mode 100644 index 0000000..5190351 --- /dev/null +++ b/crates/ia/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "ia" +version = "0.1.0" +edition = "2021" + +[dependencies] +base16ct = { version = "0.2.0", features = ["alloc", "std"] } +bytes = "1.7.2" +cap-std = "3.2.0" +cap-tempfile = "3.3.0" +copy_on_write = "0.1.3" +decompress = "0.6.0" +digest = { version = "0.10.7", features = ["alloc", "std"] } +hex = "0.4.3" +reqwest = { version = "0.12.7", features = ["blocking"] } +serde = { version = "1.0.210", features = ["derive"] } +sha2 = "0.10.8" +sha3 = "0.10.8" +strum = { version = "0.26.3", features = ["derive"] } +tar = "0.4.42" +thiserror = "1.0.63" +toml = "0.8.19" +tracing = "0.1.40" +url = "2.5.2" diff --git a/crates/ia/src/composer/mod.rs b/crates/ia/src/composer/mod.rs new file mode 100644 index 0000000..dc7e3d5 --- /dev/null +++ b/crates/ia/src/composer/mod.rs @@ -0,0 +1,81 @@ +use std::{io::Write, path::PathBuf}; + +use cap_std::ambient_authority; +use cap_tempfile::TempDir; +use tracing::info; + +use crate::{error, phase, Dir, File, Manifest}; + +/// a build pipeline manager that handles creation of the build +/// environment, execution of each phase in turn, and production of the final +/// build output in the desired format. +pub struct Composer { + manifest: Manifest, + composition_prefix: Dir, + source_files: Vec, +} + +impl Composer { + /// creates a new composer from a parsed manifest. + /// this function creates a temporary directory backing the composition. + /// when the composer goes out of scope, the temporary direcytory and all + /// of its contents are removed from disk. + pub fn new(manifest: Manifest) -> Result { + info!("creating new composer for package '{0}'…", manifest.name); + let composition_prefix = TempDir::new(ambient_authority()) + .map(|d| { + d.into_dir() + .map_err(|_| error::Composer::IO(error::IO::TempDirCreate)) + }) + .map_err(|_| error::Composer::IO(error::IO::TempDirCreate))??; + + let mut prefix_manifest_file = composition_prefix + .create("manifest.toml") + .map(File) + .map_err(|_| error::Composer::IO(error::IO::TempCreate))?; + + let manifest_content = toml::to_string(&manifest) + .map_err(|_| error::Composer::Fetch(error::Fetch::ManifestParse))?; + + info!("copying manifest file to composition directory…"); + prefix_manifest_file + .write(manifest_content.as_bytes()) + .and_then(|_| prefix_manifest_file.flush()) + .map_err(|_| error::Composer::IO(error::IO::TempWrite))?; + + Ok(Self { + manifest, + source_files: vec![], + composition_prefix: Dir(composition_prefix), + }) + } + + /// executes the fetch phase of the composition. + pub fn fetch_phase(self) -> Result { + info!("executing fetch phase for '{0}'…", self.manifest.name); + let fetch_phase = phase::fetch::Fetch::new( + self.manifest.sources.iter().collect(), + &self.composition_prefix, + ) + .map_err(error::Composer::Fetch)?; + + let source_files = fetch_phase.fetch().map_err(error::Composer::Fetch)?; + + Ok(Self { + manifest: self.manifest, + source_files, + composition_prefix: self.composition_prefix, + }) + } + + /// returns an array of all files fetched in the fetch phase. + pub fn fetched_source_files(&self) -> &[File] { + &self.source_files + } + + /// executes the full composition pipeline and returns the path to the + /// final packaged output. + pub fn compose(&self) -> Result { + todo!() + } +} diff --git a/crates/ia/src/error.rs b/crates/ia/src/error.rs new file mode 100644 index 0000000..1e027a8 --- /dev/null +++ b/crates/ia/src/error.rs @@ -0,0 +1,102 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error> { + #[error("manifest error: {0}")] + Manifest(T), + #[error("hash error: {0}")] + Hash(T), + #[error("source error: {0}")] + Source(T), + #[error("fetch phase error: {0}")] + Fetch(T), +} + +#[derive(Debug, Error)] +pub enum File { + #[error("unsupported file type")] + UnsupportedType(String), + #[error("io error: {0}")] + IO(IO), +} + +#[derive(Debug, Error)] +pub enum Fetch { + #[error("unable to parse manifest file")] + ManifestParse, + #[error("no fetcher implemented for scheme '{0}'")] + UnimplementedScheme(String), + #[error("source url '{0}' invalid")] + InvalidSourceUrl(String), + #[error("io error: {0}")] + IO(IO), + #[error("no local working directory identified")] + NoCwd, +} + +#[derive(Debug, Error)] +pub enum Source { + #[error("source url does not exist: {0}")] + Nonexistent(String), + #[error("source url does not possess a file base name: {0}")] + NoBaseName(String), + #[error("source url is an absolute path: {0}")] + AbsolutePath(String), // due to sandboxing, this error should never occur. + // any function returning this error must panic. + #[error("permission denied attempting to access source url: {0}")] + PermissionDenied(String), + #[error("unable to parse source url: {0}")] + Parse(String), +} + +#[derive(Debug, Error)] +pub enum Manifest { + #[error("unable to parse manifest")] + Parse, +} + +#[derive(Debug, Error)] +pub enum Hash { + #[error("unable to parse hash: {0}")] + Parse(String), + #[error("invalid hash: {0}")] + Invalid(String), + #[error("invalid algorithm: {0}")] + Algorithm(String), + #[error("internal error")] + Internal, +} + +#[derive(Debug, Error)] +pub enum IO { + #[error("could not create file: {0}")] + Create(String), + #[error("could not read file")] + Read, + #[error("could not read file: {0}")] + ReadNamed(String), + #[error("could not write file: {0}")] + WriteNamed(String), + #[error("could not copy file")] + Copy, + #[error("could not create reflink: {0}:{1}")] + Reflink(String, String), + #[error("no unpacker found for archive: {0}")] + NoUnpacker(String), + #[error("could not create temporary file")] + TempCreate, + #[error("could not create temporary directory")] + TempDirCreate, + #[error("could not read temporary file")] + TempRead, + #[error("could not write to temporary file")] + TempWrite, +} + +#[derive(Debug, Error)] +pub enum Composer { + #[error("fetch phase error: {0}")] + Fetch(Fetch), + #[error("io error: {0}")] + IO(IO), +} diff --git a/crates/ia/src/hash.rs b/crates/ia/src/hash.rs new file mode 100644 index 0000000..2b5c006 --- /dev/null +++ b/crates/ia/src/hash.rs @@ -0,0 +1,140 @@ +//! an ia hash is made up of two parts: the hash algorithm and the hash itself. +//! this is simply to allow forward-compatibility. +//! hashes can be deserialised from strings representing the format `algorithm:value`. + +use crate::error; +use digest::{Digest, DynDigest}; +use serde::{ + de::Visitor, + Deserialize, Deserializer, Serialize, Serializer, +}; +use std::{ + fmt::Display, + io::Write, + str::FromStr, +}; + +/// a hash algorithm supported by ia. +#[derive( + strum::Display, strum::EnumString, Clone, Debug, Deserialize, Serialize, PartialEq, Eq, +)] +pub enum HashAlgorithm { + #[strum(to_string = "sha2", ascii_case_insensitive)] + Sha2, + #[strum(to_string = "sha3", ascii_case_insensitive)] + Sha3, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct HashValue(Vec); + +impl HashValue { + pub fn new(val: Box<[u8]>) -> Self { + Self(val.as_ref().to_vec()) + } +} + +impl Display for HashValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", hex::encode(self.0.as_slice())) + } +} + +/// an individual hash for a package, input, or output. +/// hashes of package inputs are used to verify their authenticity. +/// hashes of the package outputs allow the content-addressed storage model to work. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Hash { + pub algorithm: HashAlgorithm, + pub value: HashValue, +} + +impl Display for Hash { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.algorithm, self.value) + } +} + +pub trait Hasher: DynDigest + Write {} + +impl Hasher for sha2::Sha512 {} + +impl Hasher for sha3::Sha3_512 {} + +impl Hash { + pub fn hasher_for(alg: &HashAlgorithm) -> Result, error::Hash> { + match alg { + HashAlgorithm::Sha2 => Ok(Box::new(sha2::Sha512::default())), + HashAlgorithm::Sha3 => Ok(Box::new(sha3::Sha3_512::default())), + } + } + + // creates a new hash with the provided algorithm and value. + pub fn new(alg: HashAlgorithm, val: String) -> Result { + Ok(Self { + algorithm: alg, + value: HashValue(val.as_bytes().to_owned()), + }) + } +} + +impl FromStr for Hash { + type Err = error::Hash; + + fn from_str(s: &str) -> Result { + s.to_lowercase() + .split_once(':') + .ok_or(error::Hash::Parse(s.to_owned())) + .map(|(alg, val)| { + HashAlgorithm::from_str(alg) + .map_err(|_| error::Hash::Algorithm(alg.to_owned())) + .map(|alg| (alg, val)) + })? + .map(|(alg, val)| Hash::new(alg, val.to_owned()))? + } +} + +struct HashVisitor; + +impl<'de> Visitor<'de> for HashVisitor { + type Value = Hash; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a hash string (`algorithm:value`)") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Hash::from_str(v).map_err(|_| E::invalid_type(serde::de::Unexpected::Str(v), &self)) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + // all hashes are represented in lowercase. + // this generally handles unicode, but + // hashes currently used by ia use ascii only. + self.visit_str(&v.to_lowercase()) + } +} + +impl<'de> Deserialize<'de> for Hash { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(HashVisitor) + } +} + +impl Serialize for Hash { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&format!("{}:{}", self.algorithm, self.value)) + } +} diff --git a/crates/ia/src/lib.rs b/crates/ia/src/lib.rs new file mode 100644 index 0000000..e345966 --- /dev/null +++ b/crates/ia/src/lib.rs @@ -0,0 +1,163 @@ +mod error; +mod hash; +use std::{ + io::{self, BufReader, BufWriter, Read, Seek, SeekFrom, Write}, + path::PathBuf, +}; + +use cap_std::{ambient_authority, fs::OpenOptions}; +use hash::HashValue; +pub use hash::{Hash, HashAlgorithm}; +pub mod manifest; +pub use manifest::Manifest; +use tracing::{debug, warn}; +pub mod phase; + +#[derive(strum::Display)] +enum ArchiveType { + #[strum(to_string = "bz2", ascii_case_insensitive)] + Bz2, + #[strum(to_string = "gz", ascii_case_insensitive)] + Gz, + #[strum(to_string = "xz", ascii_case_insensitive)] + Xz, + #[strum(to_string = "zstd", ascii_case_insensitive)] + Zstd, + #[strum(to_string = "tar", ascii_case_insensitive)] + Tar, + #[strum(to_string = "7z", ascii_case_insensitive)] + SevenZip, + #[strum(to_string = "zip", ascii_case_insensitive)] + Zip, + #[strum(to_string = "rar", ascii_case_insensitive)] + Rar, // oh no +} + +#[derive(strum::Display)] +enum FileType { + Archive(ArchiveType), + Other, +} + +pub struct Dir(pub cap_std::fs::Dir); + +impl Dir { + fn open_file(&self, file_name: String) -> Result { + self.0 + .open_with( + file_name.clone(), + OpenOptions::new().create(true).write(true).read(true), + ) + .map_err(|_| error::IO::Create(file_name)) + .map(File) + } + + /// creates a new file named `dst_basename` within `self.prefix`. + /// this function uses capabilities. writing to files outside of + /// `self.prefix` will fail. + pub fn write_file(&self, src_file: &mut File, dst_basename: String) -> Result { + // ensure we are at the start of the file stream. + // in rare cases, the file is written after being otherwise + // at least partially read. + src_file.reset().map_err(|_| error::IO::Read)?; + + let mut dst_file = self.open_file(dst_basename.clone())?; + debug!("writing to file: {0}", dst_basename); + + io::copy(src_file, &mut dst_file) + .and_then(|_| dst_file.flush()) + .map_err(|_| error::IO::Copy) + .and_then(|_| dst_file.reset()) + .map(|_| dst_file) + } +} + +#[derive(Debug)] +pub struct File(cap_std::fs::File); + +impl Read for File { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.0.read(buf) + } +} + +impl Write for File { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.0.flush() + } +} + +impl File { + pub fn hash(&mut self, alg: HashAlgorithm) -> Result { + self.reset().map_err(|_| error::Hash::Internal)?; + + let mut buf = String::new(); + self.read_to_string(&mut buf).unwrap(); + self.reset().unwrap(); + + let mut hasher = Hash::hasher_for(&alg)?; + io::copy(self, &mut hasher).map_err(|_| error::Hash::Internal)?; + let hash_value = hasher.finalize_reset(); + hasher.flush().map_err(|_| error::Hash::Internal)?; + + let hash_value = HashValue::new(hash_value); + + Ok(Hash { + algorithm: alg, + value: hash_value, + }) + } + + fn seek(&mut self, pos: SeekFrom) -> Result { + self.0.seek(pos).map_err(|_| error::IO::Read) + } + + fn reset(&mut self) -> Result<(), error::IO> { + self.seek(SeekFrom::Start(0)).map(|_| ()) + } + + fn read_ambient(path: PathBuf) -> Result, error::IO> { + warn!("ia::File::read_ambient() called! this function is not sandboxed."); + cap_std::fs::File::open_ambient_with( + path.clone(), + OpenOptions::new().read(true), + ambient_authority(), + ) + .map(File) + .map(BufReader::new) + .map_err(|_| error::IO::ReadNamed(path.to_string_lossy().to_string())) + } + + // this truly _should_ never happen, but may be useful in some rare cases. + fn write_ambient(path: PathBuf) -> Result, error::IO> { + warn!("ia::File::write_ambient() called. this function is not sandboxed."); + + cap_std::fs::File::open_ambient_with( + path.clone(), + OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true), + ambient_authority(), + ) + .map(|f| BufWriter::new(File(f))) + .map_err(|_| error::IO::WriteNamed(path.to_string_lossy().to_string())) + } + + /// copies the contents of `self` to `dst`, consuming `self` and returning + /// `dst`. + fn copy_to(self, dst: File) -> Result { + let mut read = BufReader::new(self); + let mut write = BufWriter::new(dst); + + io::copy(&mut read, &mut write) + .and_then(|_| write.flush()) + .map_err(|_| error::IO::Copy) + .and_then(|_| write.into_inner().map_err(|_| error::IO::Copy)) + } +} diff --git a/crates/ia/src/manifest/mod.rs b/crates/ia/src/manifest/mod.rs new file mode 100644 index 0000000..e09b941 --- /dev/null +++ b/crates/ia/src/manifest/mod.rs @@ -0,0 +1,320 @@ +//! a package manifest is the 'recipe' for constructing an [ia::PackageLock]. +//! a full package manifest can be found in the `docs` directory. +use std::fmt::{Debug, Display}; +use std::str::FromStr; + +use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize}; + +use crate::{error, ArchiveType, FileType, Hash}; + +// an architecture supported by ia packages. +// for the sake of easier future expansion, +// the 'other' value allows for architectures +// that may not be completely supported presently. +#[derive(strum::Display, Debug, Deserialize, Serialize)] +pub enum Architecture { + #[strum(to_string = "all")] + #[serde(rename = "all")] + All, + #[strum(to_string = "aarch64")] + #[serde(rename = "aarch64")] + Aarch64, + #[strum(to_string = "amd64")] + #[serde(rename = "amd64")] + Amd64, + #[strum(to_string = "riscv")] + #[serde(rename = "riscv")] + RiscV, + #[strum(to_string = "other:{0}")] + Other(String), +} + +// a license supported by ia packages. these are represented +// as a spdx license expression. +#[derive(strum::Display, Debug, Deserialize, Serialize)] +pub enum License { + #[strum(to_string = "gpl-3.0-only")] + #[serde(rename = "gpl-3.0-only")] + Gpl3Only, + #[strum(to_string = "gpl-3.0-or-later")] + #[serde(rename = "gpl-3.0-or-later")] + Gpl3OrLater, + #[strum(to_string = "gpl-2.0-only")] + #[serde(rename = "gpl-2.0-only")] + Gpl2Only, + #[strum(to_string = "gpl-2.0-or-later")] + #[serde(rename = "gpl-2.0-or-later")] + Gpl2OrLater, + #[strum(to_string = "lgpl-3.0-only")] + #[serde(rename = "lgpl-3.0-only")] + Lgpl3Only, + #[strum(to_string = "lgpl-3.0-or-later")] + #[serde(rename = "lgpl-3.0-or-later")] + Lgpl3OrLater, + #[strum(to_string = "bsd-2-clause")] + #[serde(rename = "bsd-2-clause")] + Bsd2, + #[strum(to_string = "bsd-3-clause")] + #[serde(rename = "bsd-3-clause")] + Bsd3, + #[strum(to_string = "mit")] + #[serde(rename = "mit")] + Mit, + #[strum(to_string = "mpl-2.0")] + #[serde(rename = "mpl-2.0")] + Mozilla2, + #[strum(to_string = "other:{0}")] + #[serde(rename = "other:{0}")] + Other(String), +} + +/// a package's name, usually defined by upstream. +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct Name(String); + +impl Name { + pub fn new>(n: T) -> Self { + Self(n.as_ref().to_owned()) + } +} + +impl Display for Name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +/// a package's description, usually defined by upstream. +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct Description(String); + +#[derive(strum::Display, Debug, Deserialize, PartialEq, Serialize)] +pub enum VersionOper { + #[strum(to_string = "<")] + LessThan, + #[strum(to_string = "<=")] + LessThanOrEqual, + #[strum(to_string = "=")] + Equal, + #[strum(to_string = ">=")] + GreaterThanOrEqual, + #[strum(to_string = ">")] + GreaterThan, +} + +impl FromStr for VersionOper { + type Err = error::Manifest; + + fn from_str(s: &str) -> Result { + match s { + "<=" => Ok(VersionOper::LessThanOrEqual), + ">=" => Ok(VersionOper::GreaterThanOrEqual), + "=" => Ok(VersionOper::Equal), + "<" => Ok(VersionOper::LessThan), + ">" => Ok(VersionOper::GreaterThan), + _ => Err(error::Manifest::Parse), + } + } +} + +// a package revision. +// this is used by maintainers where package updates are required +// that do not include changes from upstream. +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Eq)] +pub struct Revision(u8); + +impl Revision { + pub fn new(rev: u8) -> Self { + Self(rev) + } +} + +/// a package's version. +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct Version(String); + +impl Display for Version { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl Version { + pub fn new>(upstream: T) -> Self { + Version(upstream.as_ref().to_string()) + } +} + +/// a dependency entry. +// these may be represented in two variants: +// a version-free name, which will pull the latest version +// of the package as a dependency, or +// a versioned name, which may use the following operators: +// - `<=`, which indicates a package version of the provided value or below +// - `>=`, which indicates a package version of the provided value or above +// - `=`, which indicates a package version of the provided value exactly +// - `<`, which indicates a package version below the provided value +// - `>`, which indicates a package version above the provided value +// version operators are searched in the following order: +// `<=`, `>=`, `=`, `<`, `>` +#[derive(Debug, PartialEq, Serialize)] +pub struct Dependency(Name, Option<(VersionOper, Version)>); + +impl Dependency { + fn new(name: Name, opped_version: Option<(VersionOper, Version)>) -> Self { + Self(name, opped_version) + } +} + +impl Display for Dependency { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.1 { + None => write!(f, "{}", self.0), + Some((op, version)) => write!(f, "{}{}{}", self.0, op, version), + } + } +} + +struct DependencyVisitor; + +impl<'de> Visitor<'de> for DependencyVisitor { + type Value = Dependency; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a version string (e.g., `package_name=1.0`)") + } + + fn visit_str(self, s: &str) -> Result + where + E: serde::de::Error, + { + ["<=", ">=", "=", "<", ">"] + .into_iter() + .find_map(|oper| { + s.rsplit_once(oper) + .map(|(name, version)| { + ( + Name::new(name), + VersionOper::from_str(oper).unwrap_or(VersionOper::Equal), + Version::new(version), + ) + }) + .map(|(n, o, v)| Dependency::new(n, Some((o, v)))) + }) + .or(Some(Dependency::new(Name::new(s), None))) + .ok_or(E::invalid_value(serde::de::Unexpected::Str(s), &self)) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + // all hashes are represented in lowercase. + // this generally handles unicode, but + // hashes currently used by ia use ascii only. + self.visit_str(&v.to_lowercase()) + } +} + +impl<'de> Deserialize<'de> for Dependency { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_string(DependencyVisitor) + } +} + +/// a configuration phase construct which either uses a helper, +/// or executes a collection of commands. +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct ConfigurePhase { + handler: Option, + exec: Option, +} + +/// a build phase construct which either uses a helper, +/// or executes a collection of commands. +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct BuildPhase { + handler: Option, + exec: Option, +} + +/// a test phase construct which either uses a helper, +/// or executes a collection of commands. +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct TestPhase { + handler: Option, + exec: Option, +} + +/// a source entry, or "input". a url pointing to a source file of some +/// description. +/// the currently-supported scheme handlers are: +/// - `file:`, which is a local file +/// - `http://` and `https://`, which interact over HTTP/HTTPS protocols +/// respectively +/// - `git://`, which interacts over the git DVCS protocol +/// - `sftp://`, which interacts over the SSH File Transfer Protocol +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct Source { + pub name: String, + pub url: String, + pub hash: Hash, +} + +impl Source { + pub fn new(name: String, url: String, hash: Hash) -> Self { + Self { name, url, hash } + } +} + +impl Source { + /// attempts to match the filetype using the extension of the source + /// destination's basename. + /// + /// this isn't a particularly resilient heuristic against naming files + /// with invalid or no extension, but it's reasonable enough to fix in the + /// manifest and increases clarity of the lockfile. + fn dst_file_type(&self) -> Result { + match self + .name + .clone() + .rsplit_once('.') + .ok_or(error::File::UnsupportedType("none".to_owned()))? + .1 + { + "gz" => Ok(FileType::Archive(ArchiveType::Gz)), + "xz" => Ok(FileType::Archive(ArchiveType::Xz)), + "zstd" => Ok(FileType::Archive(ArchiveType::Zstd)), + "bz2" => Ok(FileType::Archive(ArchiveType::Bz2)), + "rar" => Ok(FileType::Archive(ArchiveType::Rar)), + "zip" => Ok(FileType::Archive(ArchiveType::Zip)), + "7z" => Ok(FileType::Archive(ArchiveType::SevenZip)), + _ => Ok(FileType::Other), + } + } +} + +/// a full package manifest. +/// manifests are a representation of the "recipe" used to build the package. +/// a manifest is used to build an ia package and generate its lockfile thereafter. +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct Manifest { + pub name: Name, + pub description: Description, + pub version: Version, + pub revision: Revision, + pub sources: Vec, + pub patches: Option>, + pub dependencies: Vec, + pub build_dependencies: Vec, + #[serde(rename = "configure")] + pub configure_phase: ConfigurePhase, + #[serde(rename = "build")] + pub build_phase: BuildPhase, + #[serde(rename = "test")] + pub test_phase: TestPhase, +} diff --git a/crates/ia/src/phase/fetch/file.rs b/crates/ia/src/phase/fetch/file.rs new file mode 100644 index 0000000..9fecf80 --- /dev/null +++ b/crates/ia/src/phase/fetch/file.rs @@ -0,0 +1,62 @@ +//! the local file implementation of [super::Fetcher], handling the fetching of +//! source files from a local filesystem. + + +use crate::{error, manifest::Source, Dir, File}; +use std::io::{self, BufWriter, Write}; +pub(crate) struct Fetcher {} + +/// the local file implementation of [super::Fetcher]. +/// usage of this fetcher in application code is discouraged, as source file +/// retrieval cannot be sandboxed and therefore can be used to access files +/// outside of the build environment. +impl super::Fetcher for Fetcher { + fn new() -> Result { + Ok(Self {}) + } + + fn name(&self) -> &'static str { + "file" + } + + /// opens an arbitrary file with read-only permissions, creates a file + /// within the provided `dst_dir`, and copies the contents of the source + /// file to the destination file. + /// + /// this function mutates data, and must never be used implicitly in + /// application code. + fn fetch(&self, src: &Source, dst_dir: &Dir) -> Result { + let src_path_string = src + .url + .split_once("file:") + .map(|(_, p)| p.to_string()) + .ok_or(error::Fetch::InvalidSourceUrl(src.url.clone()))?; + + let src_path = std::env::current_dir() + .map_err(|_| error::Fetch::NoCwd)? + .join(src_path_string.clone()); + + let mut src_buf = File::read_ambient(src_path) + .map_err(|_| error::Fetch::IO(error::IO::ReadNamed(src_path_string.clone())))?; + + let dst_file = dst_dir + .open_file(src.name.clone()) + .map_err(error::Fetch::IO)?; + + let mut dst_buf = BufWriter::new(dst_file); + io::copy(&mut src_buf, &mut dst_buf) + // reports of flushing on copy are + // greatly exaggerated. + // enforce this to ensure all data + // is written to disk or explicitly + // fails. + .and_then(|_| dst_buf.flush()) + .map(|_| { + dst_buf + .into_inner() + .map_err(|_| error::Fetch::IO(error::IO::WriteNamed(src_path_string.clone()))) + }) + .map_err(|_| error::Fetch::IO(error::IO::WriteNamed(src_path_string.clone())))? + .map(|mut f| f.reset().map_err(error::Fetch::IO).map(|_| f))? + } +} diff --git a/crates/ia/src/phase/fetch/mod.rs b/crates/ia/src/phase/fetch/mod.rs new file mode 100644 index 0000000..8213e1c --- /dev/null +++ b/crates/ia/src/phase/fetch/mod.rs @@ -0,0 +1,77 @@ +//! the fetch phase is the first stage of the package composition pipeline. +//! it is responsible for fetching the sources of the package from its +//! defined source paths using an automatically determined scheme handler. +//! +//! this phase is transactional: +//! - sources are not linked into the build directory until all sources +//! are successfully obtained. +//! - if the parsing or retrieval of any input fails, +//! the entire phase will return an error and the retrieved sources +//! are removed from disk. +//! +//! fetch handlers generally stream source artifacts in chunks instead +//! of reading the entire artifact into memory, allowing sources of sizes +//! much larger than the available system memory to be used. +mod file; +use crate::{error, manifest::Source, Dir, File, HashAlgorithm}; +use tracing::info; + +pub trait Fetcher { + fn new() -> Result + where + Self: Sized; + fn fetch(&self, src: &Source, dst_dir: &Dir) -> Result; + fn name(&self) -> &'static str; +} + +pub struct Fetch<'a> { + sources: Vec<&'a Source>, + prefix: &'a Dir, +} + +impl<'a> Fetch<'a> { + pub fn new(sources: Vec<&'a Source>, prefix: &'a Dir) -> Result { + Ok(Self { sources, prefix }) + } + + pub fn fetcher_for(source: &Source) -> Result, error::Fetch> { + match source + .url + .split_once(':') + .map(|split| split.0) + .or(Some("")) + .ok_or(error::Fetch::InvalidSourceUrl(source.url.clone()))? + { + "file" => Ok(Box::new(file::Fetcher::new()?)), + "http" | "https" => todo!(), + "ftp" => todo!(), + "git" => todo!(), + "sftp" => todo!(), + _ => Err(error::Fetch::UnimplementedScheme(source.url.clone())), + } + } + + fn _fetch(&self, source: &Source) -> Result { + let fetcher: Box = Fetch::fetcher_for(source)?; + info!( + "executing '{0}' fetcher for source '{1}'…", + fetcher.name(), + source.name + ); + + let mut file = fetcher.fetch(source, self.prefix).unwrap(); + println!("{:?}", file.hash(HashAlgorithm::Sha2).unwrap()); + Ok(file) + } + + pub fn fetch(&self) -> Result, error::Fetch> { + // FIX: this is presently quite inefficient, as it recreates a new + // fetcher for each source even if they are all of the same scheme. + // could cache a fetcher upon its creation and re-use it, but would + // need a 'fetcher pool' for this. + self.sources + .iter() + .map(|source| self._fetch(source)) + .collect::, error::Fetch>>() + } +} diff --git a/crates/ia/src/phase/mod.rs b/crates/ia/src/phase/mod.rs new file mode 100644 index 0000000..0e40308 --- /dev/null +++ b/crates/ia/src/phase/mod.rs @@ -0,0 +1 @@ +pub mod fetch; diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml new file mode 100644 index 0000000..d1a674d --- /dev/null +++ b/crates/tests/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ia-tests" +version = "0.1.0" +edition = "2021" + +[dependencies] +cap-tempfile = "3.3.0" +ia = { path = "../ia" } +toml = "0.8.19" +url = { version = "2.5.2", features = ["serde"] } diff --git a/crates/tests/fixtures/package/manifest.toml b/crates/tests/fixtures/package/manifest.toml new file mode 100644 index 0000000..6675e33 --- /dev/null +++ b/crates/tests/fixtures/package/manifest.toml @@ -0,0 +1,28 @@ +name = "test-package" +description = "a test package for apm testing" +version = "1.2.3-git" +revision = 42 +license = "gpl-3.0-only" +architectures = [ "ppc64" ] +dependencies = [ ] +build_dependencies = [ ] +provides = [ "hello-world" ] +groups = [ "examples" ] + +[[sources]] +name = "source-test.txt" +url = "file:./source-test.txt" +hash = "sha2:4cbf04bd094e2bd2eda36cf3561bfa61cb1a83c29427f0dd01d8b071cd8d002f3f46aa1c8b5eef25e7743f629ad4976f59bf7ee07d345b9bdb89c85703e581c7" + +[configure] +exec = """ +""" + +[build] +exec = """ +make +""" + +[test] +exec = """ +""" diff --git a/crates/tests/fixtures/package/source-test.txt b/crates/tests/fixtures/package/source-test.txt new file mode 100644 index 0000000..092cc4b --- /dev/null +++ b/crates/tests/fixtures/package/source-test.txt @@ -0,0 +1 @@ +test source file diff --git a/crates/tests/src/hash.rs b/crates/tests/src/hash.rs new file mode 100644 index 0000000..5e0793b --- /dev/null +++ b/crates/tests/src/hash.rs @@ -0,0 +1,51 @@ + +use std::str::FromStr; + +use ia::{Hash, HashAlgorithm}; + +const HASH_PLAINTEXT: &str = "example"; + +pub(crate) const SHA2_HASH_STR: &str = "sha2:3bb12eda3c298db5de25597f54d924f2e17e78a26ad8953ed8218ee682f0bbbe9021e2f3009d152c911bf1f25ec683a902714166767afbd8e5bd0fb0124ecb8a"; +pub(crate) const SHA2_HASH_ALG: HashAlgorithm = HashAlgorithm::Sha2; +pub(crate) const SHA2_HASH_VALUE: &str = "3bb12eda3c298db5de25597f54d924f2e17e78a26ad8953ed8218ee682f0bbbe9021e2f3009d152c911bf1f25ec683a902714166767afbd8e5bd0fb0124ecb8a"; +pub(crate) const SHA3_HASH_STR: &str = "sha3:e6da59e7349fb06a3de52ab3a2b383090f80d45ea8489d76b231d580ccf01fb112e509dedd5cc09bead4aa54455ca4c66cd46abe35c061325802d5df12b2a55d"; +pub(crate) const SHA3_HASH_ALG: HashAlgorithm = HashAlgorithm::Sha3; +pub(crate) const SHA3_HASH_VALUE: &str = "e6da59e7349fb06a3de52ab3a2b383090f80d45ea8489d76b231d580ccf01fb112e509dedd5cc09bead4aa54455ca4c66cd46abe35c061325802d5df12b2a55d"; +pub(crate) const INVALIDALG_HASH_STR: &str = "abcd213:3bb12eda3c298db5de25597f54d924f2e17e78a26ad8953ed8218ee682f0bbbe9021e2f3009d152c911bf1f25ec683a902714166767afbd8e5bd0fb0124ecb8a"; +pub(crate) const INVALIDVALUE_HASH_STR: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + +#[test] +fn can_parse_sha2_alg() { + let hash = Hash::from_str(SHA2_HASH_STR).unwrap(); + assert_eq!(hash.algorithm, SHA2_HASH_ALG) +} + +#[test] +fn can_parse_sha2_value() { + let hash = Hash::from_str(SHA2_HASH_STR).unwrap(); + assert_eq!(hash.value.to_string(), SHA2_HASH_VALUE.to_owned()) +} + +#[test] +fn can_parse_sha3_alg() { + let hash = Hash::from_str(SHA3_HASH_STR).unwrap(); + assert_eq!(hash.algorithm, SHA3_HASH_ALG) +} + +#[test] +fn can_parse_sha3_value() { + let hash = Hash::from_str(SHA3_HASH_STR).unwrap(); + assert_eq!(hash.value.to_string(), SHA3_HASH_VALUE.to_owned()) +} + +#[test] +fn rejects_invalid_alg() { + let hash = Hash::from_str(INVALIDALG_HASH_STR); + assert!(hash.is_err()) +} + +#[test] +fn rejects_invalid_hash() { + let hash = Hash::from_str(INVALIDVALUE_HASH_STR); + assert!(hash.is_err()) +} diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs new file mode 100644 index 0000000..c5dfdaa --- /dev/null +++ b/crates/tests/src/lib.rs @@ -0,0 +1,3 @@ +mod hash; +mod manifest; +mod phase; diff --git a/crates/tests/src/manifest/mod.rs b/crates/tests/src/manifest/mod.rs new file mode 100644 index 0000000..576024a --- /dev/null +++ b/crates/tests/src/manifest/mod.rs @@ -0,0 +1,31 @@ +use ia::{manifest::{Revision, Version}, Manifest}; + +pub(crate) const MANIFEST_FILE_STR: &str = include_str!("../../fixtures/package/manifest.toml"); +pub(crate) const MANIFEST_PACKAGE_NAME_STR: &str = "test-package"; +pub(crate) const MANIFEST_VERSION_STR: &str = "1.2.3-git"; +pub(crate) const MANIFEST_REVISION: u8 = 42; + +#[test] +fn can_parse_toml() { + let manifest_toml: toml::Table = toml::from_str(MANIFEST_FILE_STR).unwrap(); + assert_eq!( + manifest_toml["name"].as_str(), + Some(MANIFEST_PACKAGE_NAME_STR) + ); +} + +#[test] +fn can_parse_manifest() { + let manifest: Manifest = toml::from_str(MANIFEST_FILE_STR).unwrap(); + assert_eq!(manifest.name.to_string(), MANIFEST_PACKAGE_NAME_STR); +} + +#[test] +fn can_parse_version() { + let version = Version::new(MANIFEST_VERSION_STR); + let revision = Revision::new(MANIFEST_REVISION); + let manifest: Manifest = toml::from_str(MANIFEST_FILE_STR).unwrap(); + + assert_eq!(manifest.version, version); + assert_eq!(manifest.revision, revision); +} diff --git a/crates/tests/src/phase/fetch/mod.rs b/crates/tests/src/phase/fetch/mod.rs new file mode 100644 index 0000000..f020d91 --- /dev/null +++ b/crates/tests/src/phase/fetch/mod.rs @@ -0,0 +1,71 @@ + +use std::io::Read; + +use cap_tempfile::ambient_authority; +use cap_tempfile::TempDir; +use ia::manifest::Source; +use ia::phase::fetch::Fetch; +use ia::Dir; +use ia::File; +use ia::Hash; +use ia::Manifest; + +const SOURCE_FILE_NAME: &str = "source-test.txt"; +const SOURCE_FILE_CONTENT: &str = "test source file\n"; +const SOURCE_FILE_HASH: &str = "0c984b1b4ebc120d693d33ebda78d26fd91f27614de387c420960cc67a0e32ffef2a7adfaf132acf411c2606a10e0290822b5ac096471342c05b89d62230e486"; + +fn test_source() -> Source { + Source::new( + SOURCE_FILE_NAME.to_string(), + String::from("file:./fixtures/package/source-test.txt"), + Hash::new(ia::HashAlgorithm::Sha2, String::new()).unwrap(), + ) +} + +fn test_source_file() -> File { + Fetch::fetcher_for(&test_source()) + .unwrap() + .fetch(&test_source(), &test_build_prefix()) + .unwrap() +} + +fn test_manifest() -> Manifest { + toml::from_str(crate::manifest::MANIFEST_FILE_STR).unwrap() +} + +fn test_build_prefix() -> Dir { + Dir(TempDir::new(ambient_authority()) + .unwrap() + .into_dir() + .unwrap()) +} + +#[test] +fn can_identify_fetcher_from_url() { + assert_eq!( + Fetch::fetcher_for(test_manifest().sources.first().unwrap()) + .unwrap() + .name(), + "file" + ); +} + +#[test] +fn can_fetch() { + let mut buf = String::new(); + test_source_file().read_to_string(&mut buf).unwrap(); + + assert_eq!(buf, SOURCE_FILE_CONTENT); +} + +#[test] +fn can_hash_source() { + assert_eq!( + test_source_file() + .hash(ia::HashAlgorithm::Sha2) + .unwrap() + .value + .to_string(), + SOURCE_FILE_HASH + ); +} diff --git a/crates/tests/src/phase/mod.rs b/crates/tests/src/phase/mod.rs new file mode 100644 index 0000000..e29e6a3 --- /dev/null +++ b/crates/tests/src/phase/mod.rs @@ -0,0 +1 @@ +mod fetch; diff --git a/readme.md b/readme.md index 6e1b2c2..3bc5aa0 100644 --- a/readme.md +++ b/readme.md @@ -85,11 +85,14 @@ if you really need a longer name to attach to it, i guess 'installation assistan - ia repository server - package definition import from: - apk: apkbuild +- implementation of specific configuration / pre-build handlers + - autoconf - implementation of specific build handlers - cmake - go - - cargo - meson + - cpan + - python (setup.py) - implementation of specific test handlers - cmake - go @@ -103,6 +106,9 @@ if you really need a longer name to attach to it, i guess 'installation assistan - implementation of further download handlers - hg - bzr +- implementation of further build handlers + - cargo + - python (distutils) - package definition import from: - apk: apkbuild - pacman: pkgbuild @@ -117,7 +123,7 @@ if you really need a longer name to attach to it, i guess 'installation assistan * deb: debian control * library package definition import from: * javascript: npm - * ruby: rubygems + * ruby: rubygems (via git) * python: pypi * rust: crates.io * go: pkg.dev