diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index ff468d3..374783d 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -102,5 +102,5 @@ jobs: fault_type="${{ steps.vars.outputs.FAULT_TYPE }}" fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]') # * convert any warnings to GHA UI annotations; ref: - S=$(cargo clippy --all-targets -ptar -- ${CLIPPY_FLAGS} -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::${fault_type} file=\2,line=\3,col=\4::${fault_prefix}: \`cargo clippy\`: \1 (file:'\2', line:\3)/p;" -e '}' ; fault=true ; } + S=$(cargo clippy --all-targets -ptarapp -- ${CLIPPY_FLAGS} -D warnings 2>&1) && printf "%s\n" "$S" || { printf "%s\n" "$S" ; printf "%s" "$S" | sed -E -n -e '/^error:/{' -e "N; s/^error:[[:space:]]+(.*)\\n[[:space:]]+-->[[:space:]]+(.*):([0-9]+):([0-9]+).*$/::${fault_type} file=\2,line=\3,col=\4::${fault_prefix}: \`cargo clippy\`: \1 (file:'\2', line:\3)/p;" -e '}' ; fault=true ; } if [ -n "${{ steps.vars.outputs.FAIL_ON_FAULT }}" ] && [ -n "$fault" ]; then exit 1 ; fi diff --git a/.gitignore b/.gitignore index ea8c4bf..7528e5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,23 @@ -/target +# spell-checker:ignore (misc) direnv + +target/ +coverage/ +/src/*/gen_table +/build/ +/tmp/ +/busybox/ +/.vscode/ +/.vs/ +/public/ +*~ +.*.swp +.*.swo +.idea +lib*.a +/docs/_build +*.iml +### macOS ### +.DS_Store + +### direnv ### +/.direnv/ diff --git a/Cargo.lock b/Cargo.lock index 2c23655..86cd22d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -54,37 +54,37 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", - "once_cell", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys 0.60.2", ] [[package]] @@ -98,15 +98,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "block-buffer" @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -130,9 +130,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bzip2" @@ -145,10 +145,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.16" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -156,9 +157,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -174,7 +175,7 @@ checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "num-traits", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -220,9 +221,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "clap_mangen" @@ -236,9 +237,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "constant_time_eq" @@ -313,15 +314,15 @@ checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" [[package]] name = "deflate64" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" +checksum = "26bf8fc351c5ed29b5c2f0cbbac1b209b74f60ecd62e675a998df72c49af5204" [[package]] name = "deranged" -version = "0.4.1" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -367,9 +368,9 @@ dependencies = [ [[package]] name = "dns-lookup" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853d5bcf0b73bd5e6d945b976288621825c7166e9f06c5a035ae1aaf42d1b64f" +checksum = "6e39034cee21a2f5bbb66ba0e3689819c4bb5d00382a282006e802a7ffa6c41d" dependencies = [ "cfg-if", "libc", @@ -400,12 +401,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -415,10 +416,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "flate2" -version = "1.1.2" +name = "filetime" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "flate2" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "libz-rs-sys", @@ -453,9 +472,9 @@ dependencies = [ [[package]] name = "fluent-langneg" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0" dependencies = [ "unic-langid", ] @@ -472,9 +491,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -482,21 +501,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi", + "wasip2", ] [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hashbrown" @@ -521,14 +540,15 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -544,9 +564,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", @@ -582,9 +602,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" @@ -645,9 +665,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -665,6 +685,17 @@ version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + [[package]] name = "libz-rs-sys" version = "0.5.2" @@ -676,15 +707,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lzma-rust2" @@ -698,9 +729,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miniz_oxide" @@ -709,6 +740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -755,17 +787,23 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "os_display" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6229bad892b46b0dcfaaeb18ad0d2e56400f5aaea05b768bde96e73676cf75" +checksum = "ad5fd71b79026fb918650dde6d125000a233764f1c2f1659a1c71118e33ea08f" dependencies = [ - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -846,9 +884,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppmd-rust" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b" +checksum = "d558c559f0450f16f2a27a1f017ef38468c1090c9ce63c8e51366232d53717b4" [[package]] name = "ppv-lite86" @@ -871,9 +909,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -904,18 +942,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -946,6 +984,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.12.2" @@ -971,9 +1018,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rlimit" @@ -998,43 +1045,53 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustix" -version = "1.0.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "self_cell" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -1095,12 +1152,12 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1117,9 +1174,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -1128,6 +1185,15 @@ dependencies = [ [[package]] name = "tar" +version = "0.4.44" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tarapp" version = "0.0.1" dependencies = [ "chrono", @@ -1142,6 +1208,7 @@ dependencies = [ "rand", "regex", "rlimit", + "tar", "tempfile", "textwrap", "uu_tar", @@ -1162,17 +1229,17 @@ dependencies = [ "getrandom", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1184,23 +1251,23 @@ dependencies = [ "smawk", "terminal_size", "unicode-linebreak", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -1209,9 +1276,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -1226,15 +1293,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -1242,11 +1309,12 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -1261,9 +1329,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unic-langid" @@ -1285,9 +1353,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-linebreak" @@ -1297,15 +1365,9 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "utf8parse" @@ -1319,6 +1381,7 @@ version = "0.0.1" dependencies = [ "clap", "regex", + "tar", "uucore", ] @@ -1389,45 +1452,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1435,22 +1485,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -1466,18 +1516,38 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "windows-link" -version = "0.1.3" +name = "windows-implement" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "windows-link" @@ -1485,6 +1555,24 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -1500,7 +1588,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -1521,19 +1618,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -1544,9 +1641,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -1556,9 +1653,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -1568,9 +1665,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -1580,9 +1677,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -1592,9 +1689,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -1604,9 +1701,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -1616,9 +1713,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -1628,18 +1725,15 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "xattr" @@ -1659,18 +1753,18 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -1685,9 +1779,9 @@ checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -1705,10 +1799,11 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ + "serde", "zerofrom", ] @@ -1747,9 +1842,9 @@ checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" [[package]] name = "zopfli" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index ca0a764..0d993e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ # spell-checker:ignore (libs) bigdecimal datetime fundu gethostid kqueue libselinux mangen memmap tar uuhelp [package] -name = "tar" +name = "tarapp" version = "0.0.1" authors = ["uutils developers"] license = "MIT" @@ -46,6 +46,7 @@ regex = "1.10.4" uucore = "0.4.0" uuhelp_parser = "0.2.0" uutests = "0.4.0" +tar = "0.4" tempfile = "3.10.1" textwrap = { version = "0.16.1", features = ["terminal_size"] } xattr = "1.3.1" @@ -71,6 +72,7 @@ libc = { workspace = true } pretty_assertions = "1" rand = { workspace = true } regex = { workspace = true } +tar-rs-crate = { version = "0.4", package = "tar" } tempfile = { workspace = true } uucore = { workspace = true, features = ["entries", "process", "signals"] } uutests = { workspace = true } diff --git a/src/bin/tarapp.rs b/src/bin/tarapp.rs index 2cb9fad..b8814cc 100644 --- a/src/bin/tarapp.rs +++ b/src/bin/tarapp.rs @@ -7,5 +7,12 @@ use std::env; use tar::uumain; fn main() { - std::process::exit(uumain(env::args_os())); + let exit_code = uumain(env::args_os()); + + // If exiting with code 2, show the "not recoverable" message + if exit_code == 2 { + uucore::show_error!("Error is not recoverable: exiting now"); + } + + std::process::exit(exit_code); } diff --git a/src/uu/tar/Cargo.toml b/src/uu/tar/Cargo.toml index fe25ea7..d6ed134 100644 --- a/src/uu/tar/Cargo.toml +++ b/src/uu/tar/Cargo.toml @@ -16,6 +16,7 @@ categories = ["command-line-utilities"] uucore = { workspace = true } clap = { workspace = true } regex = { workspace = true } +tar = { workspace = true } [lib] path = "src/tar.rs" diff --git a/src/uu/tar/src/errors.rs b/src/uu/tar/src/errors.rs new file mode 100644 index 0000000..5c51ff4 --- /dev/null +++ b/src/uu/tar/src/errors.rs @@ -0,0 +1,85 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use std::fmt; +use std::io; +use uucore::error::UError; + +/// Error types for tar operations +#[derive(Debug)] +pub enum TarError { + /// I/O error occurred + IoError(io::Error), + /// Invalid archive format or corrupted archive + InvalidArchive(String), + /// File or directory not found + FileNotFound(String), + /// Permission denied + PermissionDenied(String), + /// General tar operation error + TarOperationError(String), +} + +/// Implements display formatting for TarError. +impl fmt::Display for TarError { + /// Formats the error for display to users + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TarError::IoError(err) => write!(f, "{err}"), + TarError::InvalidArchive(msg) => write!(f, "{msg}"), + TarError::FileNotFound(path) => { + write!(f, "{path}: Cannot open: No such file or directory") + } + TarError::PermissionDenied(path) => { + write!(f, "{path}: Cannot open: Permission denied") + } + TarError::TarOperationError(msg) => write!(f, "{msg}"), + } + } +} + +impl TarError { + /// Create a TarError from an io::Error with file path context + pub fn from_io_error(err: io::Error, path: &std::path::Path) -> Self { + match err.kind() { + io::ErrorKind::NotFound => TarError::FileNotFound(path.display().to_string()), + io::ErrorKind::PermissionDenied => { + TarError::PermissionDenied(path.display().to_string()) + } + _ => TarError::IoError(err), + } + } +} + +impl std::error::Error for TarError { + /// Returns the underlying error cause, if any + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + TarError::IoError(err) => Some(err), + _ => None, + } + } +} + +impl UError for TarError { + /// Returns the exit code for this error type + fn code(&self) -> i32 { + match self { + TarError::IoError(_) => 2, + TarError::InvalidArchive(_) => 2, + TarError::FileNotFound(_) => 2, + TarError::PermissionDenied(_) => 2, + TarError::TarOperationError(_) => 2, + } + } +} + +impl From for TarError { + /// Converts io::Error into the appropriate TarError variant + fn from(err: io::Error) -> Self { + // For generic io::Error without context, just wrap it + TarError::IoError(err) + } +} diff --git a/src/uu/tar/src/operations/create.rs b/src/uu/tar/src/operations/create.rs new file mode 100644 index 0000000..022cb62 --- /dev/null +++ b/src/uu/tar/src/operations/create.rs @@ -0,0 +1,81 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use crate::errors::TarError; +use std::fs::File; +use std::path::Path; +use tar::Builder; +use uucore::error::UResult; + +/// Create a tar archive from the specified files +/// +/// # Arguments +/// +/// * `archive_path` - Path where the tar archive should be created +/// * `files` - Slice of file paths to add to the archive +/// * `verbose` - Whether to print verbose output during creation +/// +/// # Errors +/// +/// Returns an error if: +/// - The archive file cannot be created +/// - Any input file cannot be read +/// - Files cannot be added due to I/O or permission errors +pub fn create_archive(archive_path: &Path, files: &[&Path], verbose: bool) -> UResult<()> { + // Create the output file + let file = File::create(archive_path).map_err(|e| { + TarError::TarOperationError(format!( + "Cannot create archive '{}': {}", + archive_path.display(), + e + )) + })?; + + // Create Builder instance + let mut builder = Builder::new(file); + + if verbose { + println!("Creating archive: {}", archive_path.display()); + } + + // Add each file or directory to the archive + for &path in files { + if verbose { + println!("{}", path.display()); + } + + // Check if path exists + if !path.exists() { + return Err(TarError::FileNotFound(path.display().to_string()).into()); + } + + // If it's a directory, recursively add all contents + if path.is_dir() { + builder.append_dir_all(path, path).map_err(|e| { + TarError::TarOperationError(format!( + "Failed to add directory '{}': {}", + path.display(), + e + )) + })?; + } else { + // For files, add them directly + builder.append_path(path).map_err(|e| { + TarError::TarOperationError(format!( + "Failed to add file '{}': {}", + path.display(), + e + )) + })?; + } + } + + // Finish writing the archive + builder + .finish() + .map_err(|e| TarError::TarOperationError(format!("Failed to finalize archive: {e}")))?; + + Ok(()) +} diff --git a/src/uu/tar/src/operations/extract.rs b/src/uu/tar/src/operations/extract.rs new file mode 100644 index 0000000..2668009 --- /dev/null +++ b/src/uu/tar/src/operations/extract.rs @@ -0,0 +1,62 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use crate::errors::TarError; +use std::fs::File; +use std::path::Path; +use tar::Archive; +use uucore::error::UResult; + +/// Extract files from a tar archive +/// +/// # Arguments +/// +/// * `archive_path` - Path to the tar archive to extract +/// * `verbose` - Whether to print verbose output during extraction +/// +/// # Errors +/// +/// Returns an error if: +/// - The archive file cannot be opened +/// - The archive format is invalid +/// - Files cannot be extracted due to I/O or permission errors +pub fn extract_archive(archive_path: &Path, verbose: bool) -> UResult<()> { + // Open the archive file + let file = File::open(archive_path).map_err(|e| TarError::from_io_error(e, archive_path))?; + + // Create Archive instance + let mut archive = Archive::new(file); + + // Extract to current directory + if verbose { + println!("Extracting archive: {}", archive_path.display()); + } + + // Iterate through entries for verbose output and error handling + for entry_result in archive + .entries() + .map_err(|e| TarError::InvalidArchive(format!("Failed to read archive entries: {e}")))? + { + let mut entry = entry_result + .map_err(|e| TarError::InvalidArchive(format!("Failed to read entry: {e}")))?; + + // Get the path before unpacking (clone it so we can use it after borrowing entry mutably) + let path = entry + .path() + .map_err(|e| TarError::InvalidArchive(format!("Failed to read entry path: {e}")))? + .to_path_buf(); + + if verbose { + println!("{}", path.display()); + } + + // Unpack the entry + entry.unpack_in(".").map_err(|e| { + TarError::TarOperationError(format!("Failed to extract '{}': {}", path.display(), e)) + })?; + } + + Ok(()) +} diff --git a/src/uu/tar/src/operations/mod.rs b/src/uu/tar/src/operations/mod.rs new file mode 100644 index 0000000..b11efb7 --- /dev/null +++ b/src/uu/tar/src/operations/mod.rs @@ -0,0 +1,7 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +pub mod create; +pub mod extract; diff --git a/src/uu/tar/src/tar.rs b/src/uu/tar/src/tar.rs index 90c3224..4db1bd5 100644 --- a/src/uu/tar/src/tar.rs +++ b/src/uu/tar/src/tar.rs @@ -3,29 +3,73 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use clap::{arg, crate_version, Arg, ArgAction, Command}; -use std::path::PathBuf; +pub mod errors; +mod operations; + +use clap::{arg, crate_version, ArgAction, Command}; +use std::path::{Path, PathBuf}; use uucore::error::UResult; use uucore::format_usage; const ABOUT: &str = "an archiving utility"; -const USAGE: &str = "tar {A|c|d|r|t|u|x}[GnSkUWOmpsMBiajJzZhPlRvwo] [ARG...]"; +const USAGE: &str = "tar {c|x}[v] -f ARCHIVE [FILE...]"; #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { - let matches = uu_app().try_get_matches_from(args)?; + // Collect args - the test framework may add util_name as args[1], so skip it if present + let args_vec: Vec<_> = args.collect(); + let util_name = uucore::util_name(); - // For now, just print a basic message indicating the command was parsed - println!("tar: basic implementation - command line parsed successfully"); + // Skip duplicate util name if present (can be "tar" or "tarapp") + let args_to_parse = if args_vec.len() > 1 + && (args_vec[1] == util_name || args_vec[1] == "tar" || args_vec[1] == "tarapp") + { + let mut result = vec![args_vec[0].clone()]; + result.extend_from_slice(&args_vec[2..]); + result + } else { + args_vec + }; - // Check if any files were specified - if let Some(files) = matches.get_many::("file") { - for file in files { - println!("File: {}", file.display()); - } + let matches = uu_app().try_get_matches_from(args_to_parse)?; + + let verbose = matches.get_flag("verbose"); + + // Handle extract operation + if matches.get_flag("extract") { + let archive_path = matches.get_one::("file").ok_or_else(|| { + uucore::error::USimpleError::new(1, "option requires an argument -- 'f'") + })?; + + return operations::extract::extract_archive(archive_path, verbose); } - Ok(()) + // Handle create operation + if matches.get_flag("create") { + let archive_path = matches.get_one::("file").ok_or_else(|| { + uucore::error::USimpleError::new(1, "option requires an argument -- 'f'") + })?; + + let files: Vec<&Path> = matches + .get_many::("files") + .map(|v| v.map(|p| p.as_path()).collect()) + .unwrap_or_default(); + + if files.is_empty() { + return Err(uucore::error::USimpleError::new( + 1, + "Cowardly refusing to create an empty archive", + )); + } + + return operations::create::create_archive(archive_path, &files, verbose); + } + + // If no operation specified, show error + Err(uucore::error::USimpleError::new( + 1, + "You must specify one of the '-c' or '-x' options", + )) } #[allow(clippy::cognitive_complexity)] @@ -38,33 +82,29 @@ pub fn uu_app() -> Command { .disable_help_flag(true) .args([ // Main operation modes - arg!(-A --catenate "Append tar files to archive"), arg!(-c --create "Create a new archive"), - arg!(-d --diff "Find differences between archive and file system").alias("compare"), - arg!(-r --append "Append files to end of archive"), - arg!(-t --list "List contents of archive"), - arg!(-u --update "Only append files newer than copy in archive"), + // arg!(-d --diff "Find differences between archive and file system").alias("compare"), + // arg!(-r --append "Append files to end of archive"), + // arg!(-t --list "List contents of archive"), + // arg!(-u --update "Only append files newer than copy in archive"), arg!(-x --extract "Extract files from archive").alias("get"), // Archive file - arg!(-f --file "Use archive file").value_parser(clap::value_parser!(PathBuf)), + arg!(-f --file "Use archive file or device ARCHIVE") + .value_parser(clap::value_parser!(PathBuf)), // Compression options - arg!(-z --gzip "Filter through gzip"), - arg!(-j --bzip2 "Filter through bzip2"), - arg!(-J --xz "Filter through xz"), + // arg!(-z --gzip "Filter through gzip"), + // arg!(-j --bzip2 "Filter through bzip2"), + // arg!(-J --xz "Filter through xz"), // Common options arg!(-v --verbose "Verbosely list files processed"), - arg!(-h --dereference "Follow symlinks"), - arg!(-p --"preserve-permissions" "Extract information about file permissions"), - arg!(-P --"absolute-names" "Don't strip leading '/' from file names"), + // arg!(-h --dereference "Follow symlinks"), + // arg!(-p --"preserve-permissions" "Extract information about file permissions"), + // arg!(-P --"absolute-names" "Don't strip leading '/' from file names"), // Help arg!(--help "Print help information").action(ArgAction::Help), // Files to process - Arg::new("files") - .help("Files to archive or extract") - .value_parser(clap::value_parser!(PathBuf)) - .num_args(0..), + arg!([files]... "Files to archive or extract") + .action(ArgAction::Append) + .value_parser(clap::value_parser!(PathBuf)), ]) } - -#[cfg(test)] -mod tests {} diff --git a/src/uu/tar/tests/test_cli.rs b/src/uu/tar/tests/test_cli.rs new file mode 100644 index 0000000..9b42cd7 --- /dev/null +++ b/src/uu/tar/tests/test_cli.rs @@ -0,0 +1,34 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use uu_tar::uu_app; + +#[test] +fn test_extract_flag_parsing() { + let app = uu_app(); + let result = app.try_get_matches_from(vec!["tar", "-xf", "archive.tar"]); + assert!(result.is_ok()); + let matches = result.unwrap(); + assert!(matches.get_flag("extract")); +} + +#[test] +fn test_create_flag_parsing() { + let app = uu_app(); + let result = app.try_get_matches_from(vec!["tar", "-cf", "archive.tar", "file.txt"]); + assert!(result.is_ok()); + let matches = result.unwrap(); + assert!(matches.get_flag("create")); +} + +#[test] +fn test_verbose_flag_parsing() { + let app = uu_app(); + let result = app.try_get_matches_from(vec!["tar", "-cvf", "archive.tar", "file.txt"]); + assert!(result.is_ok()); + let matches = result.unwrap(); + assert!(matches.get_flag("verbose")); + assert!(matches.get_flag("create")); +} diff --git a/src/uu/tar/tests/test_errors.rs b/src/uu/tar/tests/test_errors.rs new file mode 100644 index 0000000..405d7df --- /dev/null +++ b/src/uu/tar/tests/test_errors.rs @@ -0,0 +1,92 @@ +// This file is part of the uutils tar package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use std::io; +use uu_tar::errors::TarError; + +#[test] +fn test_tar_error_display() { + let err = TarError::FileNotFound("test.txt".to_string()); + assert_eq!( + err.to_string(), + "test.txt: Cannot open: No such file or directory" + ); + + let err = TarError::InvalidArchive("corrupted header".to_string()); + assert_eq!(err.to_string(), "corrupted header"); + + let err = TarError::PermissionDenied("/root/file".to_string()); + assert_eq!( + err.to_string(), + "/root/file: Cannot open: Permission denied" + ); + + let err = TarError::TarOperationError("failed to write".to_string()); + assert_eq!(err.to_string(), "failed to write"); +} + +#[test] +fn test_tar_error_code() { + use uucore::error::UError; + + assert_eq!(TarError::FileNotFound("test".to_string()).code(), 2); + assert_eq!(TarError::InvalidArchive("test".to_string()).code(), 2); + assert_eq!(TarError::PermissionDenied("test".to_string()).code(), 2); + assert_eq!(TarError::TarOperationError("test".to_string()).code(), 2); +} + +#[test] +fn test_io_error_conversion_not_found() { + let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found"); + let tar_err = TarError::from(io_err); + + match tar_err { + TarError::IoError(e) => assert_eq!(e.kind(), io::ErrorKind::NotFound), + _ => panic!("Expected IoError variant"), + } +} + +#[test] +fn test_io_error_conversion_permission_denied() { + let io_err = io::Error::new(io::ErrorKind::PermissionDenied, "access denied"); + let tar_err = TarError::from(io_err); + + match tar_err { + TarError::IoError(e) => assert_eq!(e.kind(), io::ErrorKind::PermissionDenied), + _ => panic!("Expected IoError variant"), + } +} + +#[test] +fn test_io_error_conversion_other() { + let io_err = io::Error::new(io::ErrorKind::BrokenPipe, "pipe broken"); + let tar_err = TarError::from(io_err); + + match tar_err { + TarError::IoError(e) => assert_eq!(e.kind(), io::ErrorKind::BrokenPipe), + _ => panic!("Expected IoError variant"), + } +} + +#[test] +fn test_error_source() { + let io_err = io::Error::other("some error"); + let tar_err = TarError::IoError(io_err); + + // IoError should have a source + assert!(std::error::Error::source(&tar_err).is_some()); + + // Other variants should not have a source + let tar_err = TarError::FileNotFound("test".to_string()); + assert!(std::error::Error::source(&tar_err).is_none()); +} + +#[test] +fn test_tar_error_is_debug() { + let err = TarError::TarOperationError("test".to_string()); + let debug_str = format!("{err:?}"); + assert!(debug_str.contains("TarOperationError")); + assert!(debug_str.contains("test")); +} diff --git a/tests/by-util/test_tar.rs b/tests/by-util/test_tar.rs index 8760d48..741f2b4 100644 --- a/tests/by-util/test_tar.rs +++ b/tests/by-util/test_tar.rs @@ -3,9 +3,10 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use uutests::new_ucmd; +use uutests::{at_and_ucmd, new_ucmd}; + +// Basic CLI Tests -// Basic tar tests #[test] fn test_invalid_arg() { new_ucmd!().arg("--definitely-invalid").fails().code_is(1); @@ -13,10 +14,103 @@ fn test_invalid_arg() { #[test] fn test_help() { - new_ucmd!().arg("--help").succeeds().code_is(0); + new_ucmd!() + .arg("--help") + .succeeds() + .code_is(0) + .stdout_contains("an archiving utility"); } #[test] fn test_version() { - new_ucmd!().arg("--version").succeeds().code_is(0); + new_ucmd!() + .arg("--version") + .succeeds() + .code_is(0) + .stdout_contains("tar"); +} + +// Create operation tests + +#[test] +fn test_create_single_file() { + let (at, mut ucmd) = at_and_ucmd!(); + + at.write("file1.txt", "test content"); + + ucmd.args(&["-cf", "archive.tar", "file1.txt"]).succeeds(); + + assert!(at.file_exists("archive.tar")); +} + +#[test] +fn test_create_multiple_files() { + let (at, mut ucmd) = at_and_ucmd!(); + + at.write("file1.txt", "content1"); + at.write("file2.txt", "content2"); + + ucmd.args(&["-cf", "archive.tar", "file1.txt", "file2.txt"]) + .succeeds(); + + assert!(at.file_exists("archive.tar")); +} + +// Extract operation tests + +#[test] +fn test_extract_single_file() { + let (at, mut ucmd) = at_and_ucmd!(); + + // Create an archive first + at.write("original.txt", "test content"); + ucmd.args(&["-cf", "archive.tar", "original.txt"]) + .succeeds(); + + // Remove original and extract + at.remove("original.txt"); + + new_ucmd!() + .arg("-xf") + .arg(at.plus("archive.tar")) + .current_dir(at.as_string()) + .succeeds(); + + assert!(at.file_exists("original.txt")); + assert_eq!(at.read("original.txt"), "test content"); +} + +#[test] +fn test_extract_multiple_files() { + let (at, mut ucmd) = at_and_ucmd!(); + + // Create an archive with multiple files + at.write("file1.txt", "content1"); + at.write("file2.txt", "content2"); + ucmd.args(&["-cf", "archive.tar", "file1.txt", "file2.txt"]) + .succeeds(); + + // Remove originals + at.remove("file1.txt"); + at.remove("file2.txt"); + + // Extract + new_ucmd!() + .arg("-xf") + .arg(at.plus("archive.tar")) + .current_dir(at.as_string()) + .succeeds(); + + assert!(at.file_exists("file1.txt")); + assert!(at.file_exists("file2.txt")); + assert_eq!(at.read("file1.txt"), "content1"); + assert_eq!(at.read("file2.txt"), "content2"); +} + +#[test] +fn test_extract_nonexistent_archive() { + new_ucmd!() + .args(&["-xf", "nonexistent.tar"]) + .fails() + .code_is(2); }