From 0c2b282f19280efc3daedab0e545a0ecaf3e6857 Mon Sep 17 00:00:00 2001 From: Justin Schneck Date: Fri, 15 Aug 2025 18:22:40 -0400 Subject: [PATCH] Add support for ext package [--out-dir] --- Cargo.lock | 1361 ++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- src/commands/ext/mod.rs | 2 + src/commands/ext/package.rs | 736 ++++++++++++++++++ src/main.rs | 47 +- test-arch.toml | 10 + test-explicit-arch.toml | 11 + test-x86.toml | 10 + test_package_functionality.rs | 43 ++ 9 files changed, 2194 insertions(+), 30 deletions(-) create mode 100644 src/commands/ext/package.rs create mode 100644 test-arch.toml create mode 100644 test-explicit-arch.toml create mode 100644 test-x86.toml create mode 100644 test_package_functionality.rs diff --git a/Cargo.lock b/Cargo.lock index 96f77dd..7ba0612 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,32 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[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 = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.20" @@ -92,9 +118,15 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "avocado-cli" version = "0.5.0" @@ -107,6 +139,7 @@ dependencies = [ "indicatif", "libc", "reqwest", + "rpm", "serde", "serde_json", "tar", @@ -116,6 +149,7 @@ dependencies = [ "tokio-test", "toml", "uuid", + "walkdir", ] [[package]] @@ -133,39 +167,166 @@ dependencies = [ "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.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[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 = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "buffer-redux" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8acf87c5b9f5897cd3ebb9a327f420e0cae9dd4e5c1d2e36f2c84c571a58f1" +dependencies = [ + "memchr", +] + [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[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.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "camellia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "cast5" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cfb-mode" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" +dependencies = [ + "cipher", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -178,6 +339,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[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 = "clap" version = "4.5.45" @@ -197,7 +382,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] @@ -209,7 +394,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -237,6 +422,39 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e77cfc4543efb4837662cb7cd53464ae66f0fd5c708d71e0f338b1c11d62d3" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc24" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" + [[package]] name = "crc32fast" version = "1.5.0" @@ -246,6 +464,153 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[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 = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.105", +] + +[[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 0.10.0", + "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 = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[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 = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + [[package]] name = "directories" version = "5.0.1" @@ -275,7 +640,88 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", +] + +[[package]] +name = "dsa" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" +dependencies = [ + "digest", + "num-bigint-dig", + "num-traits", + "pkcs8", + "rfc6979", + "sha2", + "signature", + "zeroize", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", ] [[package]] @@ -284,6 +730,28 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "enum-display-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ef37b2a9b242295d61a154ee91ae884afff6b8b933b486b12481cc58310ca" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "enum-primitive-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba7795da175654fe16979af73f81f26a8ea27638d8d9823d317016888a63dc4c" +dependencies = [ + "num-traits", + "quote", + "syn 2.0.105", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -306,6 +774,22 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "filetime" version = "0.2.25" @@ -372,7 +856,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -404,6 +888,17 @@ dependencies = [ "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", + "zeroize", +] + [[package]] name = "getrandom" version = "0.2.16" @@ -437,6 +932,17 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -449,6 +955,30 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[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.3.1" @@ -531,7 +1061,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -549,6 +1079,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.0.0" @@ -635,6 +1189,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "idea" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" +dependencies = [ + "cipher", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.0.3" @@ -679,6 +1248,15 @@ dependencies = [ "web-time", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "io-uring" version = "0.7.9" @@ -712,12 +1290,37 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "iter-read" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071ed4cc1afd86650602c7b11aa2e1ce30762a1c27193201cb5cee9c6ebb1294" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -728,12 +1331,50 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[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" +dependencies = [ + "spin", +] + [[package]] name = "libc" version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "libredox" version = "0.1.9" @@ -769,12 +1410,39 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[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 = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -795,6 +1463,141 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "serde", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.105", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[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", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.105", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -817,16 +1620,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "once_cell_polyfill" -version = "1.70.1" +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] [[package]] -name = "option-ext" -version = "0.2.0" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] [[package]] name = "percent-encoding" @@ -834,6 +1670,62 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pgp" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031fa1e28c4cb54c90502ef0642a44ef10ec8349349ebe6372089f1b1ef4f297" +dependencies = [ + "aes", + "base64 0.21.7", + "bitfield", + "block-padding", + "blowfish", + "bstr", + "buffer-redux", + "byteorder", + "camellia", + "cast5", + "cfb-mode", + "chrono", + "cipher", + "const-oid", + "crc24", + "curve25519-dalek", + "derive_builder", + "des", + "digest", + "dsa", + "ed25519-dalek", + "elliptic-curve", + "flate2", + "generic-array", + "hex", + "idea", + "iter-read", + "k256", + "log", + "md-5", + "nom", + "num-bigint-dig", + "num-traits", + "num_enum", + "p256", + "p384", + "rand 0.8.5", + "ripemd", + "rsa", + "sha1", + "sha2", + "sha3", + "signature", + "smallvec", + "thiserror 1.0.69", + "twofish", + "x25519-dalek", + "zeroize", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -846,6 +1738,33 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "portable-atomic" version = "1.11.1" @@ -870,6 +1789,24 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.97" @@ -908,7 +1845,7 @@ dependencies = [ "bytes", "getrandom 0.3.3", "lru-slab", - "rand", + "rand 0.9.2", "ring", "rustc-hash", "rustls", @@ -949,14 +1886,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[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]] @@ -966,7 +1924,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -1004,7 +1971,7 @@ version = "0.12.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-core", "futures-util", @@ -1039,6 +2006,16 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.14" @@ -1053,6 +2030,65 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rpm" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68a0d60350e5f4229cd69f08ec8f373e34424701702d1ee51a89aee1e9adcd1" +dependencies = [ + "bitflags", + "bzip2", + "chrono", + "cpio", + "digest", + "enum-display-derive", + "enum-primitive-derive", + "flate2", + "hex", + "itertools", + "log", + "md-5", + "nom", + "num", + "num-derive", + "num-traits", + "pgp", + "sha1", + "sha2", + "thiserror 1.0.69", + "xz2", + "zstd", +] + +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.26" @@ -1065,6 +2101,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "1.0.8" @@ -1125,6 +2170,35 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + [[package]] name = "serde" version = "1.0.219" @@ -1142,7 +2216,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -1178,6 +2252,38 @@ dependencies = [ "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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +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" @@ -1193,6 +2299,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "slab" version = "0.4.11" @@ -1225,12 +2341,34 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" @@ -1243,6 +2381,17 @@ 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.105" @@ -1271,7 +2420,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -1324,7 +2473,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -1335,7 +2484,7 @@ checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -1390,7 +2539,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -1551,6 +2700,21 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "twofish" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" +dependencies = [ + "cipher", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -1603,6 +2767,22 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1649,7 +2829,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.105", "wasm-bindgen-shared", ] @@ -1684,7 +2864,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1740,12 +2920,74 @@ dependencies = [ "rustls-pki-types", ] +[[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 = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.105", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.105", +] + [[package]] name = "windows-link" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1992,6 +3234,18 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + [[package]] name = "xattr" version = "1.5.1" @@ -2002,6 +3256,15 @@ dependencies = [ "rustix", ] +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + [[package]] name = "yoke" version = "0.8.0" @@ -2022,7 +3285,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", "synstructure", ] @@ -2043,7 +3306,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", ] [[package]] @@ -2063,7 +3326,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", "synstructure", ] @@ -2072,6 +3335,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.105", +] [[package]] name = "zerotrie" @@ -2103,5 +3380,33 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.105", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index 33f65f8..c8b2dcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,9 @@ flate2 = "1.0.32" tar = "0.4.41" uuid = { version = "1.0", features = ["v4"] } libc = "0.2" +rpm = "0.14" +walkdir = "2.4" +tempfile = "3.0" [dev-dependencies] -tempfile = "3.0" tokio-test = "0.4" diff --git a/src/commands/ext/mod.rs b/src/commands/ext/mod.rs index 95aab76..fdbcad7 100644 --- a/src/commands/ext/mod.rs +++ b/src/commands/ext/mod.rs @@ -6,6 +6,7 @@ pub mod dnf; pub mod image; pub mod install; pub mod list; +pub mod package; pub use build::ExtBuildCommand; pub use checkout::ExtCheckoutCommand; @@ -15,3 +16,4 @@ pub use dnf::ExtDnfCommand; pub use image::ExtImageCommand; pub use install::ExtInstallCommand; pub use list::ExtListCommand; +pub use package::ExtPackageCommand; diff --git a/src/commands/ext/package.rs b/src/commands/ext/package.rs new file mode 100644 index 0000000..90f2285 --- /dev/null +++ b/src/commands/ext/package.rs @@ -0,0 +1,736 @@ +use anyhow::{Context, Result}; + +use std::fs; +use std::path::PathBuf; + +use crate::utils::config::Config; +use crate::utils::container::SdkContainer; +use crate::utils::output::{print_info, print_success, OutputLevel}; + +/// Command to package an extension sysroot into an RPM +pub struct ExtPackageCommand { + pub config_path: String, + pub extension: String, + pub target: String, + pub output_dir: Option, + pub verbose: bool, + pub container_args: Option>, + #[allow(dead_code)] + pub dnf_args: Option>, +} + +impl ExtPackageCommand { + pub fn new( + config_path: String, + extension: String, + target: String, + output_dir: Option, + verbose: bool, + container_args: Option>, + dnf_args: Option>, + ) -> Self { + Self { + config_path, + extension, + target, + output_dir, + verbose, + container_args, + dnf_args, + } + } + + pub async fn execute(&self) -> Result<()> { + // Load configuration and parse raw TOML + let config = Config::load(&self.config_path)?; + let content = std::fs::read_to_string(&self.config_path)?; + let parsed: toml::Value = toml::from_str(&content)?; + + // Get extension configuration + let ext_config = parsed + .get("ext") + .and_then(|ext| ext.get(&self.extension)) + .ok_or_else(|| { + anyhow::anyhow!("Extension '{}' not found in configuration.", self.extension) + })?; + + // Extract RPM metadata with defaults + let rpm_metadata = self.extract_rpm_metadata(ext_config, &self.target)?; + + if self.verbose { + print_info( + &format!( + "Packaging extension '{}' v{}-{}", + self.extension, rpm_metadata.version, rpm_metadata.release + ), + OutputLevel::Normal, + ); + } + + // Create RPM package in container + let output_path = self + .create_rpm_package_in_container(&rpm_metadata, &config, &parsed) + .await?; + + print_success( + &format!( + "Successfully created RPM package: {}", + output_path.display() + ), + OutputLevel::Normal, + ); + + Ok(()) + } + + /// Extract RPM metadata from extension configuration with defaults + fn extract_rpm_metadata(&self, ext_config: &toml::Value, target: &str) -> Result { + // Version is required + let version = ext_config + .get("version") + .and_then(|v| v.as_str()) + .ok_or_else(|| { + anyhow::anyhow!( + "Extension '{}' is missing required 'version' field for RPM packaging", + self.extension + ) + })? + .to_string(); + + // Generate defaults + let name = self.extension.clone(); + let release = ext_config + .get("release") + .and_then(|v| v.as_str()) + .unwrap_or("1") + .to_string(); + + let summary = ext_config + .get("summary") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + .unwrap_or_else(|| self.generate_summary_from_name(&name)); + + let description = ext_config + .get("description") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + .unwrap_or_else(|| self.generate_description_from_name(&name)); + + let license = ext_config + .get("license") + .and_then(|v| v.as_str()) + .unwrap_or("Unspecified") + .to_string(); + + let arch = ext_config + .get("arch") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + .unwrap_or_else(|| self.generate_arch_from_target(target)); + + let vendor = ext_config + .get("vendor") + .and_then(|v| v.as_str()) + .unwrap_or("Unspecified") + .to_string(); + + let url = ext_config + .get("url") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()); + + Ok(RpmMetadata { + name, + version, + release, + summary, + description, + license, + arch, + vendor, + url, + }) + } + + /// Generate summary from extension name + fn generate_summary_from_name(&self, name: &str) -> String { + // Convert kebab-case to title case + let words: Vec<&str> = name.split('-').collect(); + let title_case: Vec = words + .iter() + .map(|word| { + let mut chars = word.chars(); + match chars.next() { + None => String::new(), + Some(first) => first.to_uppercase().collect::() + chars.as_str(), + } + }) + .collect(); + + format!("{} system extension", title_case.join(" ")) + } + + /// Generate description from extension name + fn generate_description_from_name(&self, name: &str) -> String { + format!("System extension package for {name}") + } + + /// Generate architecture from target by replacing dashes with underscores + fn generate_arch_from_target(&self, target: &str) -> String { + format!("avocado_{}", target.replace('-', "_")) + } + + /// Create the RPM package inside the container at $AVOCADO_PREFIX/output/extensions + async fn create_rpm_package_in_container( + &self, + metadata: &RpmMetadata, + config: &Config, + parsed: &toml::Value, + ) -> Result { + let container_image = parsed + .get("sdk") + .and_then(|sdk| sdk.get("image")) + .and_then(|img| img.as_str()) + .ok_or_else(|| anyhow::anyhow!("No SDK container image specified in configuration."))?; + + let merged_container_args = config.merge_sdk_container_args(self.container_args.as_ref()); + + // Get the volume state + let cwd = std::env::current_dir().context("Failed to get current directory")?; + let volume_manager = + crate::utils::volume::VolumeManager::new("docker".to_string(), self.verbose); + let volume_state = volume_manager.get_or_create_volume(&cwd).await?; + + // Create the RPM filename + let rpm_filename = format!( + "{}-{}-{}.{}.rpm", + metadata.name, metadata.version, metadata.release, metadata.arch + ); + + // Create RPM using rpmbuild in container + let rpm_build_script = format!( + r#" +# Ensure output directory exists +mkdir -p $AVOCADO_PREFIX/output/extensions + +# Check if extension sysroot exists +if [ ! -d "$AVOCADO_EXT_SYSROOTS/{}" ]; then + echo "Extension sysroot not found: $AVOCADO_EXT_SYSROOTS/{}" + exit 1 +fi + +# Count files +FILE_COUNT=$(find "$AVOCADO_EXT_SYSROOTS/{}" -type f | wc -l) +echo "Creating RPM with $FILE_COUNT files..." + +if [ "$FILE_COUNT" -eq 0 ]; then + echo "No files found in sysroot" + exit 1 +fi + +# Create temporary directory for RPM build +TMPDIR=$(mktemp -d) +cd "$TMPDIR" + +# Create directory structure for rpmbuild +mkdir -p BUILD RPMS SOURCES SPECS SRPMS + +# Create spec file +cat > SPECS/package.spec << 'SPEC_EOF' +Name: {} +Version: {} +Release: {} +Summary: {} +License: {} +Vendor: {}{} + +%description +{} + +%files +/* + +%prep +# No prep needed + +%build +# No build needed + +%install +mkdir -p %{{buildroot}} +cp -rp $AVOCADO_EXT_SYSROOTS/{}/* %{{buildroot}}/ + +%clean +# Skip clean section - not needed for our use case + +%changelog +SPEC_EOF + +# Build the RPM with custom architecture target and define the arch macro +rpmbuild --define "_topdir $TMPDIR" --define "_arch {}" --target {} -bb SPECS/package.spec + +# Move RPM to output directory +mv RPMS/{}/*.rpm $AVOCADO_PREFIX/output/extensions/{} || {{ + mv RPMS/*/*.rpm $AVOCADO_PREFIX/output/extensions/{} 2>/dev/null || {{ + echo "Failed to find built RPM" + exit 1 + }} +}} + +echo "RPM created successfully: $AVOCADO_PREFIX/output/extensions/{}" + +# Cleanup +rm -rf "$TMPDIR" +"#, + self.extension, + self.extension, + self.extension, + metadata.name, + metadata.version, + metadata.release, + metadata.summary, + metadata.license, + metadata.vendor, + if let Some(url) = &metadata.url { + format!("\nURL: {url}") + } else { + String::new() + }, + metadata.description, + self.extension, + metadata.arch, + metadata.arch, + metadata.arch, + rpm_filename, + rpm_filename, + rpm_filename, + ); + + // Run the RPM build in the container + let container_helper = SdkContainer::new(); + let run_config = crate::utils::container::RunConfig { + container_image: container_image.to_string(), + target: self.target.clone(), + command: rpm_build_script, + verbose: self.verbose, + source_environment: true, + interactive: false, + repo_url: config.get_sdk_repo_url().cloned(), + repo_release: config.get_sdk_repo_release().cloned(), + container_args: merged_container_args, + dnf_args: self.dnf_args.clone(), + ..Default::default() + }; + + if self.verbose { + print_info("Creating RPM package in container...", OutputLevel::Normal); + } + + let success = container_helper.run_in_container(run_config).await?; + if !success { + return Err(anyhow::anyhow!("Failed to create RPM package in container")); + } + + // RPM is now created in the container at $AVOCADO_PREFIX/output/extensions/{rpm_filename} + let container_rpm_path = format!( + "/opt/_avocado/{}/output/extensions/{rpm_filename}", + self.target + ); + + // If --out is specified, copy the RPM to the host + if let Some(output_dir) = &self.output_dir { + self.copy_rpm_to_host( + &volume_state.volume_name, + &container_rpm_path, + output_dir, + &rpm_filename, + container_image, + ) + .await?; + + // Return the host path (canonicalized for clean display) + let host_output_path = if output_dir.starts_with('/') { + // Absolute path + PathBuf::from(output_dir).join(&rpm_filename) + } else { + // Relative path from current directory + std::env::current_dir()? + .join(output_dir) + .join(&rpm_filename) + }; + + // Canonicalize the path to resolve . and .. components for clean display + let canonical_path = host_output_path.canonicalize().unwrap_or(host_output_path); + Ok(canonical_path) + } else { + // Return the container path for informational purposes + Ok(PathBuf::from(container_rpm_path)) + } + } + + /// Copy the RPM from the container to the host using docker cp + async fn copy_rpm_to_host( + &self, + volume_name: &str, + container_rpm_path: &str, + output_dir: &str, + rpm_filename: &str, + _container_image: &str, + ) -> Result<()> { + if self.verbose { + print_info( + &format!("Copying RPM to host: {output_dir}"), + OutputLevel::Normal, + ); + } + + // Create a temporary container to access the volume (following checkout pattern) + let temp_container_id = self.create_temp_container(volume_name).await?; + + // Determine the output path on host + let host_output_dir = if output_dir.starts_with('/') { + // Absolute path + PathBuf::from(output_dir) + } else { + // Relative path from current directory + std::env::current_dir()?.join(output_dir) + }; + + // Create output directory on host + fs::create_dir_all(&host_output_dir)?; + + let docker_cp_source = format!("{temp_container_id}:{container_rpm_path}"); + let docker_cp_dest = host_output_dir.join(rpm_filename); + + if self.verbose { + print_info( + &format!( + "Docker cp: {docker_cp_source} -> {}", + docker_cp_dest.display() + ), + OutputLevel::Normal, + ); + } + + // Use tokio::process::Command directly like checkout does + let copy_output = tokio::process::Command::new("docker") + .arg("cp") + .arg(&docker_cp_source) + .arg(&docker_cp_dest) + .output() + .await + .context("Failed to execute docker cp")?; + + // Clean up temporary container + let _ = tokio::process::Command::new("docker") + .arg("rm") + .arg("-f") + .arg(&temp_container_id) + .output() + .await; + + if !copy_output.status.success() { + let stderr = String::from_utf8_lossy(©_output.stderr); + return Err(anyhow::anyhow!("Docker cp failed: {}", stderr)); + } + + if self.verbose { + print_info( + &format!("RPM copied to: {}", docker_cp_dest.display()), + OutputLevel::Normal, + ); + } + + Ok(()) + } + + /// Create a temporary container to access the volume (following checkout pattern) + async fn create_temp_container(&self, volume_name: &str) -> Result { + let output = tokio::process::Command::new("docker") + .arg("create") + .arg("-v") + .arg(format!("{volume_name}:/opt/_avocado:ro")) + .arg("alpine:latest") + .arg("true") + .output() + .await + .context("Failed to create temporary container")?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(anyhow::anyhow!( + "Failed to create temporary container: {}", + stderr + )); + } + + let container_id = String::from_utf8_lossy(&output.stdout).trim().to_string(); + Ok(container_id) + } +} + +/// RPM metadata structure +#[derive(Debug)] +struct RpmMetadata { + name: String, + version: String, + release: String, + summary: String, + description: String, + license: String, + arch: String, + vendor: String, + url: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_generate_summary_from_name() { + let cmd = ExtPackageCommand::new( + "test.toml".to_string(), + "test-ext".to_string(), + "x86_64-unknown-linux-gnu".to_string(), + None, + false, + None, + None, + ); + + assert_eq!( + cmd.generate_summary_from_name("web-server"), + "Web Server system extension" + ); + assert_eq!( + cmd.generate_summary_from_name("my-app"), + "My App system extension" + ); + assert_eq!( + cmd.generate_summary_from_name("database-backend"), + "Database Backend system extension" + ); + assert_eq!( + cmd.generate_summary_from_name("simple"), + "Simple system extension" + ); + } + + #[test] + fn test_generate_description_from_name() { + let cmd = ExtPackageCommand::new( + "test.toml".to_string(), + "test-ext".to_string(), + "x86_64-unknown-linux-gnu".to_string(), + None, + false, + None, + None, + ); + + assert_eq!( + cmd.generate_description_from_name("web-server"), + "System extension package for web-server" + ); + assert_eq!( + cmd.generate_description_from_name("my-app"), + "System extension package for my-app" + ); + } + + #[test] + fn test_generate_arch_from_target() { + let cmd = ExtPackageCommand::new( + "test.toml".to_string(), + "test-ext".to_string(), + "x86_64-unknown-linux-gnu".to_string(), + None, + false, + None, + None, + ); + + assert_eq!( + cmd.generate_arch_from_target("x86_64-unknown-linux-gnu"), + "avocado_x86_64_unknown_linux_gnu" + ); + assert_eq!( + cmd.generate_arch_from_target("aarch64-unknown-linux-gnu"), + "avocado_aarch64_unknown_linux_gnu" + ); + assert_eq!( + cmd.generate_arch_from_target("riscv64-unknown-linux-gnu"), + "avocado_riscv64_unknown_linux_gnu" + ); + assert_eq!( + cmd.generate_arch_from_target("i686-unknown-linux-gnu"), + "avocado_i686_unknown_linux_gnu" + ); + } + + #[test] + fn test_extract_rpm_metadata_minimal() { + let cmd = ExtPackageCommand::new( + "test.toml".to_string(), + "test-extension".to_string(), + "x86_64-unknown-linux-gnu".to_string(), + None, + false, + None, + None, + ); + + let mut ext_config = toml::Value::Table(toml::value::Table::new()); + ext_config.as_table_mut().unwrap().insert( + "version".to_string(), + toml::Value::String("1.0.0".to_string()), + ); + + let metadata = cmd + .extract_rpm_metadata(&ext_config, "x86_64-unknown-linux-gnu") + .unwrap(); + + assert_eq!(metadata.name, "test-extension"); + assert_eq!(metadata.version, "1.0.0"); + assert_eq!(metadata.release, "1"); + assert_eq!(metadata.summary, "Test Extension system extension"); + assert_eq!( + metadata.description, + "System extension package for test-extension" + ); + assert_eq!(metadata.license, "Unspecified"); + assert_eq!(metadata.arch, "avocado_x86_64_unknown_linux_gnu"); + assert_eq!(metadata.vendor, "Unspecified"); + assert_eq!(metadata.url, None); + } + + #[test] + fn test_extract_rpm_metadata_full() { + let cmd = ExtPackageCommand::new( + "test.toml".to_string(), + "web-server".to_string(), + "x86_64-unknown-linux-gnu".to_string(), + None, + false, + None, + None, + ); + + let mut ext_config = toml::Value::Table(toml::value::Table::new()); + let config_map = ext_config.as_table_mut().unwrap(); + + config_map.insert( + "version".to_string(), + toml::Value::String("2.1.3".to_string()), + ); + config_map.insert("release".to_string(), toml::Value::String("2".to_string())); + config_map.insert( + "summary".to_string(), + toml::Value::String("Custom web server".to_string()), + ); + config_map.insert( + "description".to_string(), + toml::Value::String("A custom web server extension".to_string()), + ); + config_map.insert( + "license".to_string(), + toml::Value::String("MIT".to_string()), + ); + config_map.insert( + "arch".to_string(), + toml::Value::String("noarch".to_string()), + ); + config_map.insert( + "vendor".to_string(), + toml::Value::String("Acme Corp".to_string()), + ); + config_map.insert( + "url".to_string(), + toml::Value::String("https://example.com".to_string()), + ); + + let metadata = cmd + .extract_rpm_metadata(&ext_config, "aarch64-unknown-linux-gnu") + .unwrap(); + + assert_eq!(metadata.name, "web-server"); + assert_eq!(metadata.version, "2.1.3"); + assert_eq!(metadata.release, "2"); + assert_eq!(metadata.summary, "Custom web server"); + assert_eq!(metadata.description, "A custom web server extension"); + assert_eq!(metadata.license, "MIT"); + assert_eq!(metadata.arch, "noarch"); // Explicit arch overrides generated + assert_eq!(metadata.vendor, "Acme Corp"); + assert_eq!(metadata.url, Some("https://example.com".to_string())); + } + + #[test] + fn test_extract_rpm_metadata_missing_version() { + let cmd = ExtPackageCommand::new( + "test.toml".to_string(), + "test-extension".to_string(), + "x86_64-unknown-linux-gnu".to_string(), + None, + false, + None, + None, + ); + + let ext_config = toml::Value::Table(toml::value::Table::new()); + + let result = cmd.extract_rpm_metadata(&ext_config, "x86_64-unknown-linux-gnu"); + + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("missing required 'version' field")); + } + + #[test] + fn test_arch_generation_with_different_targets() { + let cmd = ExtPackageCommand::new( + "test.toml".to_string(), + "test-ext".to_string(), + "x86_64-unknown-linux-gnu".to_string(), + None, + false, + None, + None, + ); + + let mut ext_config = toml::Value::Table(toml::value::Table::new()); + ext_config.as_table_mut().unwrap().insert( + "version".to_string(), + toml::Value::String("1.0.0".to_string()), + ); + + // Test various target architectures + let test_cases = vec![ + ( + "x86_64-unknown-linux-gnu", + "avocado_x86_64_unknown_linux_gnu", + ), + ( + "aarch64-unknown-linux-gnu", + "avocado_aarch64_unknown_linux_gnu", + ), + ( + "riscv64-unknown-linux-gnu", + "avocado_riscv64_unknown_linux_gnu", + ), + ("i686-unknown-linux-gnu", "avocado_i686_unknown_linux_gnu"), + ( + "armv7-unknown-linux-gnueabihf", + "avocado_armv7_unknown_linux_gnueabihf", + ), + ]; + + for (target, expected_arch) in test_cases { + let metadata = cmd.extract_rpm_metadata(&ext_config, target).unwrap(); + assert_eq!(metadata.arch, expected_arch, "Failed for target: {target}"); + } + } +} diff --git a/src/main.rs b/src/main.rs index dc3750b..b529cc1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use commands::build::BuildCommand; use commands::clean::CleanCommand; use commands::ext::{ ExtBuildCommand, ExtCheckoutCommand, ExtCleanCommand, ExtDepsCommand, ExtDnfCommand, - ExtImageCommand, ExtInstallCommand, ExtListCommand, + ExtImageCommand, ExtInstallCommand, ExtListCommand, ExtPackageCommand, }; use commands::hitl::HitlServerCommand; use commands::init::InitCommand; @@ -764,6 +764,27 @@ async fn main() -> Result<()> { image_cmd.execute().await?; Ok(()) } + ExtCommands::Package { + extension, + target, + config, + verbose, + output_dir, + container_args, + dnf_args, + } => { + let package_cmd = ExtPackageCommand::new( + config, + extension, + target, + output_dir, + verbose, + container_args, + dnf_args, + ); + package_cmd.execute().await?; + Ok(()) + } }, Commands::Hitl { command } => match command { HitlCommands::Server { @@ -1034,6 +1055,30 @@ enum ExtCommands { #[arg(long = "dnf-arg", num_args = 1, allow_hyphen_values = true, action = clap::ArgAction::Append)] dnf_args: Option>, }, + /// Package extension sysroot into an RPM + Package { + /// Path to avocado.toml configuration file + #[arg(short = 'C', long, default_value = "avocado.toml")] + config: String, + /// Enable verbose output + #[arg(short, long)] + verbose: bool, + /// Name of the extension to package + #[arg(short = 'e', long = "extension", required = true)] + extension: String, + /// Target architecture (e.g., x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu) + #[arg(short = 't', long = "target", required = true)] + target: String, + /// Output directory on host for the RPM package (relative or absolute path). If not specified, RPM stays in container at $AVOCADO_PREFIX/output/extensions + #[arg(long = "out-dir")] + output_dir: Option, + /// Additional arguments to pass to the container runtime + #[arg(long = "container-arg", num_args = 1, allow_hyphen_values = true, action = clap::ArgAction::Append)] + container_args: Option>, + /// Additional arguments to pass to DNF commands + #[arg(long = "dnf-arg", num_args = 1, allow_hyphen_values = true, action = clap::ArgAction::Append)] + dnf_args: Option>, + }, } #[derive(Subcommand)] diff --git a/test-arch.toml b/test-arch.toml new file mode 100644 index 0000000..e807235 --- /dev/null +++ b/test-arch.toml @@ -0,0 +1,10 @@ +[sdk] +image = "ghcr.io/avocado-framework/avocado-sdk:latest" + +[runtime.default] +target = "aarch64-unknown-linux-gnu" + +[ext.my-service] +types = ["sysext"] +packages = ["systemd"] +version = "1.0.0" diff --git a/test-explicit-arch.toml b/test-explicit-arch.toml new file mode 100644 index 0000000..c520d3f --- /dev/null +++ b/test-explicit-arch.toml @@ -0,0 +1,11 @@ +[sdk] +image = "ghcr.io/avocado-framework/avocado-sdk:latest" + +[runtime.default] +target = "aarch64-unknown-linux-gnu" + +[ext.custom-app] +types = ["sysext"] +packages = ["curl"] +version = "1.5.0" +arch = "noarch" diff --git a/test-x86.toml b/test-x86.toml new file mode 100644 index 0000000..9eaf500 --- /dev/null +++ b/test-x86.toml @@ -0,0 +1,10 @@ +[sdk] +image = "ghcr.io/avocado-framework/avocado-sdk:latest" + +[runtime.default] +target = "x86_64-unknown-linux-gnu" + +[ext.web-app] +types = ["sysext"] +packages = ["nginx"] +version = "2.1.0" diff --git a/test_package_functionality.rs b/test_package_functionality.rs new file mode 100644 index 0000000..48100bb --- /dev/null +++ b/test_package_functionality.rs @@ -0,0 +1,43 @@ +#!/usr/bin/env rust-script + +use std::fs; +use std::path::Path; + +fn main() -> Result<(), Box> { + // Create a temporary test sysroot structure + let test_dir = "test-sysroot"; + + // Clean up any existing test directory + if Path::new(test_dir).exists() { + fs::remove_dir_all(test_dir)?; + } + + // Create a mock sysroot structure + fs::create_dir_all(format!("{}/usr/bin", test_dir))?; + fs::create_dir_all(format!("{}/usr/lib", test_dir))?; + fs::create_dir_all(format!("{}/etc", test_dir))?; + fs::create_dir_all(format!("{}/var/log", test_dir))?; + + // Create some sample files + fs::write(format!("{}/usr/bin/nginx", test_dir), "#!/bin/bash\necho 'nginx mock binary'\n")?; + fs::write(format!("{}/usr/bin/curl", test_dir), "#!/bin/bash\necho 'curl mock binary'\n")?; + fs::write(format!("{}/etc/nginx.conf", test_dir), "server { listen 80; }\n")?; + fs::write(format!("{}/usr/lib/libnginx.so", test_dir), "mock library content")?; + fs::write(format!("{}/var/log/access.log", test_dir), "127.0.0.1 - - [date] GET / 200\n")?; + + println!("Created test sysroot structure in '{}':", test_dir); + + // List all created files + for entry in walkdir::WalkDir::new(test_dir) { + let entry = entry?; + if entry.file_type().is_file() { + println!(" {}", entry.path().display()); + } + } + + println!("\nTest structure created successfully!"); + println!("To test packaging, manually modify the get_sysroot_path function to return"); + println!("the path to this test directory instead of extracting from container."); + + Ok(()) +}