diff --git a/.github/workflows/all-tests-slow.yml b/.github/workflows/all-tests-slow.yml index 7d090ac..dbf90cf 100644 --- a/.github/workflows/all-tests-slow.yml +++ b/.github/workflows/all-tests-slow.yml @@ -14,4 +14,4 @@ jobs: uses: ./.github/workflows/build-artifacts-and-run-tests.yml with: matrix_all_combinations: true - upload_artifacts: false + artifact_upload_mode: none diff --git a/.github/workflows/build-artifacts-and-run-tests.yml b/.github/workflows/build-artifacts-and-run-tests.yml index 39df8af..3b84f9d 100644 --- a/.github/workflows/build-artifacts-and-run-tests.yml +++ b/.github/workflows/build-artifacts-and-run-tests.yml @@ -10,20 +10,23 @@ on: type: boolean required: true default: true - upload_artifacts: - description: "if built artifacts should be uploaded" - type: boolean + artifact_upload_mode: + description: "Control what artifacts to upload: 'none' for no uploads, 'with_default_features' to upload artifacts with default features (for releases), or 'all' for all feature combinations." + type: choice + options: + - none + - with_default_features + - all required: true - default: true workflow_call: inputs: matrix_all_combinations: description: "if matrix should have all combinations of targets and features" type: boolean required: true - upload_artifacts: - description: "if built artifacts should be uploaded" - type: boolean + artifact_upload_mode: + description: "Control which artifacts to upload: 'none' for no uploads, 'with_default_features' to upload only artifacts with default features (use_zlib+use_zstd_thin+unrar), or 'all' to upload all feature combinations." + type: string required: true jobs: @@ -99,15 +102,19 @@ jobs: shell: bash run: | FEATURES=(allow_piped_choice) + if [[ "${{ matrix.feature-unrar }}" == true ]]; then FEATURES+=(unrar); fi if [[ "${{ matrix.feature-use-zlib }}" == true ]]; then FEATURES+=(use_zlib); fi if [[ "${{ matrix.feature-use-zstd-thin }}" == true ]]; then FEATURES+=(use_zstd_thin); fi - if [[ "${{ matrix.feature-unrar }}" == true ]]; then FEATURES+=(unrar); fi + # Output plus-separated list for artifact names + IFS='+' + echo "FEATURES_PLUS=${FEATURES[*]}" >> $GITHUB_OUTPUT + # Output comma-separated list for cargo flags IFS=',' - echo "FEATURES=${FEATURES[*]}" >> $GITHUB_OUTPUT + echo "FEATURES_COMMA=${FEATURES[*]}" >> $GITHUB_OUTPUT - name: Set up extra cargo flags env: - FEATURES: ${{steps.concat-features.outputs.FEATURES}} + FEATURES: ${{steps.concat-features.outputs.FEATURES_COMMA}} shell: bash run: | FLAGS="--no-default-features" @@ -120,7 +127,7 @@ jobs: - uses: Swatinem/rust-cache@v2 with: - key: "${{ matrix.target }}-${{ matrix.feature-unrar }}-${{ matrix.feature-use-zstd-thin }}-${{ matrix.feature-unrar }}" + key: "${{ matrix.target }}-${{ matrix.feature-unrar }}-${{ matrix.feature-use-zlib }}-${{ matrix.feature-use-zstd-thin }}" - name: Test on stable # there's no way to run tests for ARM64 Windows for now @@ -129,18 +136,21 @@ jobs: ${{ env.CARGO }} +stable test --profile fast --target ${{ matrix.target }} $EXTRA_CARGO_FLAGS - name: Build release artifacts (binary and completions) - if: ${{ inputs.upload_artifacts }} + if: ${{ inputs.artifact_upload_mode != 'none' }} run: | ${{ env.CARGO }} +stable build --release --target ${{ matrix.target }} $EXTRA_CARGO_FLAGS env: - OUCH_ARTIFACTS_FOLDER: artifacts + OUCH_ARTIFACTS_FOLDER: man-page-and-completions-artifacts - name: Upload release artifacts - if: ${{ inputs.upload_artifacts }} + if: | + ${{ inputs.artifact_upload_mode != 'none' && + (inputs.artifact_upload_mode == 'all' || + (matrix.feature-unrar && matrix.feature-use-zlib && matrix.feature-use-zstd-thin)) }} uses: actions/upload-artifact@v4 with: - name: ouch-${{ matrix.target }}-${{ steps.concat-features.outputs.FEATURES }} + name: ouch-${{ matrix.target }}${{ steps.concat-features.outputs.FEATURES_PLUS != '' && format('-{0}', steps.concat-features.outputs.FEATURES_PLUS) || '' }} path: | target/${{ matrix.target }}/release/ouch target/${{ matrix.target }}/release/ouch.exe - artifacts/ + man-page-and-completions-artifacts/ diff --git a/.github/workflows/draft-release-automatic-trigger.yml b/.github/workflows/draft-release-automatic-trigger.yml index affcac7..c43d0eb 100644 --- a/.github/workflows/draft-release-automatic-trigger.yml +++ b/.github/workflows/draft-release-automatic-trigger.yml @@ -3,14 +3,14 @@ name: Automatic trigger draft release on: push: tags: - - "[0-9]+.[0-9]+.[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+-rc[0-9]+" jobs: call-workflow-build-artifacts-and-run-tests: uses: ./.github/workflows/build-artifacts-and-run-tests.yml with: matrix_all_combinations: true - upload_artifacts: true + artifact_upload_mode: with_default_features automated-draft-release: runs-on: ubuntu-latest @@ -21,9 +21,10 @@ jobs: uses: actions/checkout@v4 - name: Download artifacts - uses: dawidd6/action-download-artifact@v6 + uses: actions/download-artifact@v4 with: - path: artifacts + path: downloaded_artifacts + pattern: ouch-* - name: Package release assets run: scripts/package-release-assets.sh @@ -32,4 +33,4 @@ jobs: uses: softprops/action-gh-release@v2 with: draft: true - files: release/ouch-* + files: output_assets/ouch-* diff --git a/.github/workflows/draft-release-manual-trigger.yml b/.github/workflows/draft-release-manual-trigger.yml deleted file mode 100644 index f4e3014..0000000 --- a/.github/workflows/draft-release-manual-trigger.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Manual trigger draft release - -on: - workflow_dispatch: - inputs: - run_id: - description: Run id of the action run to pull artifacts from - required: true - -jobs: - create-draft-release-from-manual-trigger: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download artifacts - uses: dawidd6/action-download-artifact@v6 - with: - path: artifacts - workflow: build-artifacts-and-run-tests.yml - run_id: ${{ github.event.inputs.run_id }} - - - name: Package release assets - run: scripts/package-release-assets.sh - - - name: Create release - uses: softprops/action-gh-release@v2 - with: - draft: true - name: manual release ${{ github.event.inputs.run_id }} - files: release/ouch-* diff --git a/.github/workflows/pr-workflow.yml b/.github/workflows/pr-workflow.yml index e804c0c..6ef3cfd 100644 --- a/.github/workflows/pr-workflow.yml +++ b/.github/workflows/pr-workflow.yml @@ -32,4 +32,4 @@ jobs: uses: ./.github/workflows/build-artifacts-and-run-tests.yml with: matrix_all_combinations: false - upload_artifacts: false + artifact_upload_mode: none diff --git a/CHANGELOG.md b/CHANGELOG.md index ba482f4..a80d90c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,18 @@ Categories Used: **Bullet points in chronological order by PR** -## [Unreleased](https://github.com/ouch-org/ouch/compare/0.5.1...HEAD) +## [Unreleased](https://github.com/ouch-org/ouch/compare/0.6.1...HEAD) + +### New Features +### Improvements +### Bug Fixes +### Tweaks + +## [0.6.1](https://github.com/ouch-org/ouch/compare/0.6.0...0.6.1) + +- Fix .zip crash when file mode isn't present [\#804](https://github.com/ouch-org/ouch/pull/804) ([marcospb19](https://github.com/marcospb19)) + +## [0.6.0](https://github.com/ouch-org/ouch/compare/0.5.1...0.6.0) ### New Features @@ -37,7 +48,9 @@ Categories Used: - CI refactor [\#578](https://github.com/ouch-org/ouch/pull/578) ([cyqsimon](https://github.com/cyqsimon)) - Use a prefix `tmp-ouch-` for temporary decompression path name to avoid conflicts [\#725](https://github.com/ouch-org/ouch/pull/725) ([valoq](https://github.com/valoq)) & [\#788](https://github.com/ouch-org/ouch/pull/788) ([talis-fb](https://github.com/talis-fb)) +- Ignore `.git/` when `-g/--gitignore` is set [\#507](https://github.com/ouch-org/ouch/pull/507) ([talis-fb](https://github.com/talis-fb)) - Run clippy for tests too [\#738](https://github.com/ouch-org/ouch/pull/738) ([marcospb19](https://github.com/marcospb19)) +- Sevenz-rust is unmaintained, switch to sevenz-rust2 [\#796](https://github.com/ouch-org/ouch/pull/796) ([tommady](https://github.com/tommady)) ### Improvements @@ -46,6 +59,7 @@ Categories Used: - Make `--format` more forgiving with the formatting of the provided format [\#519](https://github.com/ouch-org/ouch/pull/519) ([marcospb19](https://github.com/marcospb19)) - Use buffered writer for list output [\#764](https://github.com/ouch-org/ouch/pull/764) ([killercup](https://github.com/killercup)) - Disable smart unpack when `--dir` flag is provided in decompress command [\#782](https://github.com/ouch-org/ouch/pull/782) ([talis-fb](https://github.com/talis-fb)) +- Align file sizes at left for each extracted file to make output clearer [\#792](https://github.com/ouch-org/ouch/pull/792) ([talis-fb](https://github.com/talis-fb)) ## [0.5.1](https://github.com/ouch-org/ouch/compare/0.5.0...0.5.1) diff --git a/Cargo.lock b/Cargo.lock index 1524148..c95299d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,30 +154,15 @@ dependencies = [ "which", ] -[[package]] -name = "bit-set" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f" -dependencies = [ - "bit-vec 0.7.0", -] - [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec 0.8.0", + "bit-vec", ] -[[package]] -name = "bit-vec" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" - [[package]] name = "bit-vec" version = "0.8.0" @@ -481,21 +466,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - [[package]] name = "crc32fast" version = "1.4.2" @@ -542,9 +512,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] @@ -848,6 +818,30 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "jiff" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ad87c89110f55e4cd4dc2893a9790820206729eaf221555f742d540b0724a0" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d076d5b64a7e2fe6f0743f02c43ca4a6725c0f904203bfe276a5b3e793103605" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "jobserver" version = "0.1.32" @@ -968,10 +962,10 @@ dependencies = [ ] [[package]] -name = "lzma-rust" -version = "0.1.7" +name = "lzma-rust2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baab2bbbd7d75a144d671e9ff79270e903957d92fb7386fd39034c709bd2661" +checksum = "561d131e2d9b07641ac55bc35de5ae4ac3e783fdeebd3c4c1dd3b6a7b920051a" dependencies = [ "byteorder", ] @@ -1029,11 +1023,13 @@ dependencies = [ [[package]] name = "nt-time" -version = "0.8.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2de419e64947cd8830e66beb584acc3fb42ed411d103e3c794dda355d1b374b5" +checksum = "f5e71108c089b161344bacb1227dd2124fee63ed1792fdd8308e6689197c2754" dependencies = [ "chrono", + "jiff", + "rand 0.9.0", "time", ] @@ -1070,7 +1066,7 @@ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "ouch" -version = "0.5.1" +version = "0.6.1" dependencies = [ "assert_cmd", "atty", @@ -1097,11 +1093,11 @@ dependencies = [ "once_cell", "parse-display", "proptest", - "rand", + "rand 0.8.5", "rayon", "regex", "same-file", - "sevenz-rust", + "sevenz-rust2", "snap", "tar", "tempfile", @@ -1145,7 +1141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1193,6 +1189,21 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1205,7 +1216,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -1250,13 +1261,13 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ - "bit-set 0.8.0", - "bit-vec 0.8.0", + "bit-set", + "bit-vec", "bitflags 2.8.0", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -1286,8 +1297,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.24", ] [[package]] @@ -1297,7 +1319,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -1309,13 +1341,22 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", +] + [[package]] name = "rand_xorshift" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1455,21 +1496,21 @@ dependencies = [ ] [[package]] -name = "sevenz-rust" -version = "0.6.1" +name = "sevenz-rust2" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26482cf1ecce4540dc782fc70019eba89ffc4d87b3717eb5ec524b5db6fdefef" +checksum = "dd27d0f7d5e54cab609728bf243f870469dcc845b052285e7e47ef097c04ec6a" dependencies = [ "aes", - "bit-set 0.6.0", + "bit-set", "byteorder", "cbc", - "crc", + "crc32fast", "filetime_creation", + "getrandom 0.3.1", "js-sys", - "lzma-rust", + "lzma-rust2", "nt-time", - "rand", "sha2", "wasm-bindgen", ] @@ -1651,9 +1692,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "num-conv", @@ -1665,15 +1706,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -2013,7 +2054,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", ] [[package]] @@ -2027,6 +2077,17 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "zip" version = "0.6.6" diff --git a/Cargo.toml b/Cargo.toml index a9f3ba8..835e55f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "ouch" -version = "0.5.1" +version = "0.6.1" authors = [ - "João M. Bezerra ", + "João Marcos ", "Vinícius Rodrigues Miguel ", ] edition = "2021" @@ -35,7 +35,7 @@ num_cpus = "1.16.0" once_cell = "1.20.2" rayon = "1.10.0" same-file = "1.0.6" -sevenz-rust = { version = "0.6.1", features = ["compress", "aes256"] } +sevenz-rust2 = { version = "0.13.1", features = ["compress", "aes256"] } snap = "1.1.1" tar = "0.4.42" tempfile = "3.10.1" @@ -70,7 +70,7 @@ regex = "1.10.4" test-strategy = "0.4.0" [features] -default = ["use_zlib", "use_zstd_thin", "unrar"] +default = ["unrar", "use_zlib", "use_zstd_thin"] use_zlib = ["flate2/zlib", "gzp/deflate_zlib", "zip/deflate-zlib"] use_zstd_thin = ["zstd/thin"] allow_piped_choice = [] diff --git a/build.rs b/build.rs index c7a1f91..c023757 100644 --- a/build.rs +++ b/build.rs @@ -5,18 +5,12 @@ /// Set `OUCH_ARTIFACTS_FOLDER` to the name of the destination folder: /// /// ```sh -/// OUCH_ARTIFACTS_FOLDER=my-folder cargo build +/// OUCH_ARTIFACTS_FOLDER=man-page-and-completions-artifacts cargo build /// ``` /// -/// All completion files will be generated inside of the folder "my-folder". +/// All completion files will be generated inside of the folder "man-page-and-completions-artifacts". /// /// If the folder does not exist, it will be created. -/// -/// We recommend you naming this folder "artifacts" for the sake of consistency. -/// -/// ```sh -/// OUCH_ARTIFACTS_FOLDER=artifacts cargo build -/// ``` use std::{ env, fs::{create_dir_all, File}, diff --git a/scripts/package-release-assets.sh b/scripts/package-release-assets.sh index c2e1ba9..621f28e 100755 --- a/scripts/package-release-assets.sh +++ b/scripts/package-release-assets.sh @@ -1,28 +1,60 @@ #!/usr/bin/env bash - set -e -mkdir release -cd artifacts +mkdir output_assets +echo "created folder 'output_assets/'" +ls -lA -w 1 +cd downloaded_artifacts +echo "entered 'downloaded_artifacts/'" +ls -lA -w 1 -for dir in ouch-*; do - cp -r "$dir/artifacts" "$dir/completions" - mkdir "$dir/man" - mv "$dir"/completions/*.1 "$dir/man" +PLATFORMS=( + "aarch64-pc-windows-msvc" + "aarch64-unknown-linux-gnu" + "aarch64-unknown-linux-musl" + "armv7-unknown-linux-gnueabihf" + "armv7-unknown-linux-musleabihf" + "x86_64-apple-darwin" + "x86_64-pc-windows-gnu" + "x86_64-pc-windows-msvc" + "x86_64-unknown-linux-gnu" + "x86_64-unknown-linux-musl" +) +# TODO: remove allow_piped_choice later +DEFAULT_FEATURES="allow_piped_choice+unrar+use_zlib+use_zstd_thin" - cp ../{README.md,LICENSE,CHANGELOG.md} "$dir" - rm -r "$dir/artifacts" +for platform in "${PLATFORMS[@]}"; do + path="ouch-${platform}" + echo "Processing $path" - if [[ "$dir" = *.exe ]]; then - target=${dir%.exe} - mv "$dir/target/${target/ouch-/}/release/ouch.exe" "$dir" - rm -r "$dir/target" - mv "$dir" "$target" - zip -r "../release/$target.zip" "$target" + if [ ! -d "${path}-${DEFAULT_FEATURES}" ]; then + echo "ERROR: Could not find artifact directory for $platform with default features ($path)" + exit 1 + fi + mv "${path}-${DEFAULT_FEATURES}" "$path" # remove the annoying suffix + + cp ../{README.md,LICENSE,CHANGELOG.md} "$path" + mkdir -p "$path/man" + mkdir -p "$path/completions" + + mv "$path"/man-page-and-completions-artifacts/*.1 "$path/man" + mv "$path"/man-page-and-completions-artifacts/* "$path/completions" + rm -r "$path/man-page-and-completions-artifacts" + + if [[ "$platform" == *"-windows-"* ]]; then + mv "$path/target/$platform/release/ouch.exe" "$path" + rm -rf "$path/target" + + zip -r "../output_assets/${path}.zip" "$path" + echo "Created output_assets/${path}.zip" else - mv "$dir/target/${dir/ouch-/}/release/ouch" "$dir" - rm -r "$dir/target" - chmod +x "$dir/ouch" - tar czf "../release/$dir.tar.gz" "$dir" + mv "$path/target/$platform/release/ouch" "$path" + rm -rf "$path/target" + chmod +x "$path/ouch" + + tar czf "../output_assets/${path}.tar.gz" "$path" + echo "Created output_assets/${path}.tar.gz" fi done + +echo "Done." diff --git a/src/archive/rar.rs b/src/archive/rar.rs index ec2d1e6..37894a0 100644 --- a/src/archive/rar.rs +++ b/src/archive/rar.rs @@ -7,7 +7,7 @@ use unrar::Archive; use crate::{ error::{Error, Result}, list::FileInArchive, - utils::logger::info, + utils::{logger::info, Bytes}, }; /// Unpacks the archive given by `archive_path` into the folder given by `output_folder`. @@ -33,9 +33,9 @@ pub fn unpack_archive( archive = if entry.is_file() { if !quiet { info(format!( - "{} extracted. ({})", + "extracted ({}) {}", + Bytes::new(entry.unpacked_size), entry.filename.display(), - entry.unpacked_size )); } unpacked += 1; diff --git a/src/archive/sevenz.rs b/src/archive/sevenz.rs index 8898f5f..2618209 100644 --- a/src/archive/sevenz.rs +++ b/src/archive/sevenz.rs @@ -9,7 +9,7 @@ use std::{ use bstr::ByteSlice; use fs_err as fs; use same_file::Handle; -use sevenz_rust::SevenZArchiveEntry; +use sevenz_rust2::SevenZArchiveEntry; use crate::{ error::{Error, FinalError, Result}, @@ -31,7 +31,7 @@ pub fn compress_sevenz( where W: Write + Seek, { - let mut writer = sevenz_rust::SevenZWriter::new(writer)?; + let mut writer = sevenz_rust2::SevenZWriter::new(writer)?; let output_handle = Handle::from_path(output_path); for filename in files { @@ -81,7 +81,7 @@ where .detail(format!("File at '{path:?}' has a non-UTF-8 name")) })?; - let entry = sevenz_rust::SevenZArchiveEntry::from_path(path, entry_name.to_owned()); + let entry = sevenz_rust2::SevenZArchiveEntry::from_path(path, entry_name.to_owned()); let entry_data = if metadata.is_dir() { None } else { @@ -127,9 +127,9 @@ where } else { if !quiet { info(format!( - "{:?} extracted. ({})", + "extracted ({}) {:?}", + Bytes::new(entry.size()), file_path.display(), - Bytes::new(entry.size()) )); } @@ -156,15 +156,15 @@ where }; match password { - Some(password) => sevenz_rust::decompress_with_extract_fn_and_password( + Some(password) => sevenz_rust2::decompress_with_extract_fn_and_password( reader, output_path, - sevenz_rust::Password::from(password.to_str().map_err(|err| Error::InvalidPassword { + sevenz_rust2::Password::from(password.to_str().map_err(|err| Error::InvalidPassword { reason: err.to_string(), })?), entry_extract_fn, )?, - None => sevenz_rust::decompress_with_extract_fn(reader, output_path, entry_extract_fn)?, + None => sevenz_rust2::decompress_with_extract_fn(reader, output_path, entry_extract_fn)?, } Ok(count) @@ -197,14 +197,14 @@ pub fn list_archive( }) } }; - sevenz_rust::decompress_with_extract_fn_and_password( + sevenz_rust2::decompress_with_extract_fn_and_password( reader, ".", - sevenz_rust::Password::from(password), + sevenz_rust2::Password::from(password), entry_extract_fn, )?; } - None => sevenz_rust::decompress_with_extract_fn(reader, ".", entry_extract_fn)?, + None => sevenz_rust2::decompress_with_extract_fn(reader, ".", entry_extract_fn)?, } Ok(files.into_iter()) diff --git a/src/archive/tar.rs b/src/archive/tar.rs index c0d962d..513d36c 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -56,9 +56,9 @@ pub fn unpack_archive(reader: Box, output_folder: &Path, quiet: bool) // and so on if !quiet { info(format!( - "{:?} extracted. ({})", - utils::strip_cur_dir(&output_folder.join(file.path()?)), + "extracted ({}) {:?}", Bytes::new(file.size()), + utils::strip_cur_dir(&output_folder.join(file.path()?)), )); files_unpacked += 1; diff --git a/src/archive/zip.rs b/src/archive/zip.rs index d593477..9beac49 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -79,16 +79,14 @@ where // same reason is in _is_dir: long, often not needed text if !quiet { info(format!( - "{:?} extracted. ({})", + "extracted ({}) {:?}", + Bytes::new(file.size()), file_path.display(), - Bytes::new(file.size()) )); } - let mode = file.unix_mode().ok_or_else(|| { - std::io::Error::new(std::io::ErrorKind::InvalidData, "Cannot extract file's mode") - })?; - let is_symlink = (mode & 0o170000) == 0o120000; + let mode = file.unix_mode(); + let is_symlink = mode.is_some_and(|mode| mode & 0o170000 == 0o120000); if is_symlink { let mut target = String::new(); diff --git a/src/error.rs b/src/error.rs index 6b2e92d..3f5bc3e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -235,8 +235,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: sevenz_rust::Error) -> Self { +impl From for Error { + fn from(err: sevenz_rust2::Error) -> Self { Self::SevenzipError { reason: err.to_string(), } diff --git a/src/utils/file_visibility.rs b/src/utils/file_visibility.rs index d8abd40..fc478b2 100644 --- a/src/utils/file_visibility.rs +++ b/src/utils/file_visibility.rs @@ -69,11 +69,18 @@ impl FileVisibilityPolicy { /// Walks through a directory using [`ignore::Walk`] pub fn build_walker(&self, path: impl AsRef) -> ignore::Walk { - ignore::WalkBuilder::new(path) + let mut builder = ignore::WalkBuilder::new(path); + + builder .git_exclude(self.read_git_exclude) .git_ignore(self.read_git_ignore) .ignore(self.read_ignore) - .hidden(self.read_hidden) - .build() + .hidden(self.read_hidden); + + if self.read_git_ignore { + builder.filter_entry(|p| p.path().file_name().is_some_and(|name| name != ".git")); + } + + builder.build() } } diff --git a/src/utils/formatting.rs b/src/utils/formatting.rs index 9ebef96..3b82a09 100644 --- a/src/utils/formatting.rs +++ b/src/utils/formatting.rs @@ -105,11 +105,11 @@ impl Bytes { impl std::fmt::Display for Bytes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let &Self(num) = self; + let num = self.0; debug_assert!(num >= 0.0); if num < 1_f64 { - return write!(f, "{} B", num); + return write!(f, "{:>6.2} B", num); } let delimiter = 1000_f64; @@ -117,9 +117,9 @@ impl std::fmt::Display for Bytes { write!( f, - "{:.2} {}B", + "{:>6.2} {:>2}B", num / delimiter.powi(exponent), - Bytes::UNIT_PREFIXES[exponent as usize] + Bytes::UNIT_PREFIXES[exponent as usize], ) } } @@ -138,33 +138,33 @@ mod tests { let mb = kb * 1000; let gb = mb * 1000; - assert_eq!("0 B", format_bytes(0)); // This is weird - assert_eq!("1.00 B", format_bytes(b)); - assert_eq!("999.00 B", format_bytes(b * 999)); - assert_eq!("12.00 MiB", format_bytes(mb * 12)); + assert_eq!(" 0.00 B", format_bytes(0)); // This is weird + assert_eq!(" 1.00 B", format_bytes(b)); + assert_eq!("999.00 B", format_bytes(b * 999)); + assert_eq!(" 12.00 MiB", format_bytes(mb * 12)); assert_eq!("123.00 MiB", format_bytes(mb * 123)); - assert_eq!("5.50 MiB", format_bytes(mb * 5 + kb * 500)); - assert_eq!("7.54 GiB", format_bytes(gb * 7 + 540 * mb)); - assert_eq!("1.20 TiB", format_bytes(gb * 1200)); + assert_eq!(" 5.50 MiB", format_bytes(mb * 5 + kb * 500)); + assert_eq!(" 7.54 GiB", format_bytes(gb * 7 + 540 * mb)); + assert_eq!(" 1.20 TiB", format_bytes(gb * 1200)); // bytes - assert_eq!("234.00 B", format_bytes(234)); - assert_eq!("999.00 B", format_bytes(999)); + assert_eq!("234.00 B", format_bytes(234)); + assert_eq!("999.00 B", format_bytes(999)); // kilobytes - assert_eq!("2.23 kiB", format_bytes(2234)); - assert_eq!("62.50 kiB", format_bytes(62500)); + assert_eq!(" 2.23 kiB", format_bytes(2234)); + assert_eq!(" 62.50 kiB", format_bytes(62500)); assert_eq!("329.99 kiB", format_bytes(329990)); // megabytes - assert_eq!("2.75 MiB", format_bytes(2750000)); - assert_eq!("55.00 MiB", format_bytes(55000000)); + assert_eq!(" 2.75 MiB", format_bytes(2750000)); + assert_eq!(" 55.00 MiB", format_bytes(55000000)); assert_eq!("987.65 MiB", format_bytes(987654321)); // gigabytes - assert_eq!("5.28 GiB", format_bytes(5280000000)); - assert_eq!("95.20 GiB", format_bytes(95200000000)); + assert_eq!(" 5.28 GiB", format_bytes(5280000000)); + assert_eq!(" 95.20 GiB", format_bytes(95200000000)); assert_eq!("302.00 GiB", format_bytes(302000000000)); assert_eq!("302.99 GiB", format_bytes(302990000000)); // Weird aproximation cases: assert_eq!("999.90 GiB", format_bytes(999900000000)); - assert_eq!("1.00 TiB", format_bytes(999990000000)); + assert_eq!(" 1.00 TiB", format_bytes(999990000000)); } } diff --git a/tests/integration.rs b/tests/integration.rs index 0216a48..ea82326 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -753,3 +753,48 @@ fn symlink_pack_and_unpack( assert!(!f.file_type().unwrap().is_symlink()) } } + +#[test] +fn no_git_folder_after_decompression_with_gitignore_flag_active() { + use std::process::Command; + + let dir = tempdir().unwrap(); + let dir_path = dir.path(); + + let before = dir_path.join("before"); + + let decompressed = dir_path.join("decompressed"); + + // Create directory and a dummy file + fs::create_dir(&before).unwrap(); + fs::write(before.join("hello.txt"), b"Hello, world!").unwrap(); + + // Run `git init` inside it + Command::new("git") + .arg("init") + .current_dir(&before) + .output() + .expect("failed to run git init"); + + assert!(before.join(".git").exists(), ".git folder should exist after git init"); + + // Compress it + let archive = dir_path.join("archive.zip"); + ouch!("c", &before, &archive, "--gitignore"); + + // Decompress it + ouch!("d", &archive, "-d", &decompressed); + + // Find the subdirectory inside decompressed (e.g., "before") + let decompressed_subdir = fs::read_dir(&decompressed) + .unwrap() + .find_map(Result::ok) + .map(|entry| entry.path()) + .expect("Expected one directory inside decompressed"); + + // Assert that the decompressed folder does not include `.git/` + assert!( + !decompressed_subdir.join(".git").exists(), + ".git folder should not exist after decompression" + ); +} diff --git a/tests/snapshots/ui__ui_test_ok_decompress_multiple_files.snap b/tests/snapshots/ui__ui_test_ok_decompress_multiple_files.snap new file mode 100644 index 0000000..4240b95 --- /dev/null +++ b/tests/snapshots/ui__ui_test_ok_decompress_multiple_files.snap @@ -0,0 +1,13 @@ +--- +source: tests/ui.rs +expression: stdout_lines +--- +{ + "", + "[INFO] Files unpacked: 4", + "[INFO] Successfully decompressed archive in /outputs", + "[INFO] extracted ( 0.00 B) \"outputs/inputs\"", + "[INFO] extracted ( 0.00 B) \"outputs/inputs/input\"", + "[INFO] extracted ( 0.00 B) \"outputs/inputs/input2\"", + "[INFO] extracted ( 0.00 B) \"outputs/inputs/input3\"", +} diff --git a/tests/ui.rs b/tests/ui.rs index e9d3508..9492d1a 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -6,7 +6,7 @@ #[macro_use] mod utils; -use std::{ffi::OsStr, io, path::Path, process::Output}; +use std::{collections::BTreeSet, ffi::OsStr, io, path::Path, process::Output}; use insta::assert_snapshot as ui; use regex::Regex; @@ -142,6 +142,29 @@ fn ui_test_ok_decompress() { ui!(run_ouch("ouch decompress output.zst", dir)); } +#[cfg(target_os = "linux")] +#[test] +fn ui_test_ok_decompress_multiple_files() { + let (_dropper, dir) = testdir().unwrap(); + + let inputs_dir = dir.join("inputs"); + std::fs::create_dir(&inputs_dir).unwrap(); + + let outputs_dir = dir.join("outputs"); + std::fs::create_dir(&outputs_dir).unwrap(); + + // prepare + create_files_in(&inputs_dir, &["input", "input2", "input3"]); + + let compress_command = format!("ouch compress {} output.tar.zst", inputs_dir.to_str().unwrap()); + run_ouch(&compress_command, dir); + + let decompress_command = format!("ouch decompress output.tar.zst --dir {}", outputs_dir.to_str().unwrap()); + let stdout = run_ouch(&decompress_command, dir); + let stdout_lines = stdout.split('\n').collect::>(); + insta::assert_debug_snapshot!(stdout_lines); +} + #[test] fn ui_test_usage_help_flag() { insta::with_settings!({filters => vec![