Merge branch 'main' into close-issue-466-727

This commit is contained in:
tommady 2025-04-19 20:34:29 +08:00 committed by GitHub
commit ab294d1eaa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 167 additions and 116 deletions

View File

@ -14,4 +14,4 @@ jobs:
uses: ./.github/workflows/build-artifacts-and-run-tests.yml uses: ./.github/workflows/build-artifacts-and-run-tests.yml
with: with:
matrix_all_combinations: true matrix_all_combinations: true
upload_artifacts: false artifact_upload_mode: none

View File

@ -10,20 +10,23 @@ on:
type: boolean type: boolean
required: true required: true
default: true default: true
upload_artifacts: artifact_upload_mode:
description: "if built artifacts should be uploaded" 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: boolean type: choice
options:
- none
- with_default_features
- all
required: true required: true
default: true
workflow_call: workflow_call:
inputs: inputs:
matrix_all_combinations: matrix_all_combinations:
description: "if matrix should have all combinations of targets and features" description: "if matrix should have all combinations of targets and features"
type: boolean type: boolean
required: true required: true
upload_artifacts: artifact_upload_mode:
description: "if built artifacts should be uploaded" 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: boolean type: string
required: true required: true
jobs: jobs:
@ -99,15 +102,19 @@ jobs:
shell: bash shell: bash
run: | run: |
FEATURES=(allow_piped_choice) 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-zlib }}" == true ]]; then FEATURES+=(use_zlib); fi
if [[ "${{ matrix.feature-use-zstd-thin }}" == true ]]; then FEATURES+=(use_zstd_thin); 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=',' IFS=','
echo "FEATURES=${FEATURES[*]}" >> $GITHUB_OUTPUT echo "FEATURES_COMMA=${FEATURES[*]}" >> $GITHUB_OUTPUT
- name: Set up extra cargo flags - name: Set up extra cargo flags
env: env:
FEATURES: ${{steps.concat-features.outputs.FEATURES}} FEATURES: ${{steps.concat-features.outputs.FEATURES_COMMA}}
shell: bash shell: bash
run: | run: |
FLAGS="--no-default-features" FLAGS="--no-default-features"
@ -120,7 +127,7 @@ jobs:
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with: 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 - name: Test on stable
# there's no way to run tests for ARM64 Windows for now # 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 ${{ env.CARGO }} +stable test --profile fast --target ${{ matrix.target }} $EXTRA_CARGO_FLAGS
- name: Build release artifacts (binary and completions) - name: Build release artifacts (binary and completions)
if: ${{ inputs.upload_artifacts }} if: ${{ inputs.artifact_upload_mode != 'none' }}
run: | run: |
${{ env.CARGO }} +stable build --release --target ${{ matrix.target }} $EXTRA_CARGO_FLAGS ${{ env.CARGO }} +stable build --release --target ${{ matrix.target }} $EXTRA_CARGO_FLAGS
env: env:
OUCH_ARTIFACTS_FOLDER: artifacts OUCH_ARTIFACTS_FOLDER: man-page-and-completions-artifacts
- name: Upload release 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 uses: actions/upload-artifact@v4
with: 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: | path: |
target/${{ matrix.target }}/release/ouch target/${{ matrix.target }}/release/ouch
target/${{ matrix.target }}/release/ouch.exe target/${{ matrix.target }}/release/ouch.exe
artifacts/ man-page-and-completions-artifacts/

View File

@ -10,7 +10,7 @@ jobs:
uses: ./.github/workflows/build-artifacts-and-run-tests.yml uses: ./.github/workflows/build-artifacts-and-run-tests.yml
with: with:
matrix_all_combinations: true matrix_all_combinations: true
upload_artifacts: true artifact_upload_mode: with_default_features
automated-draft-release: automated-draft-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -21,9 +21,10 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Download artifacts - name: Download artifacts
uses: dawidd6/action-download-artifact@v6 uses: actions/download-artifact@v4
with: with:
path: artifacts path: downloaded_artifacts
pattern: ouch-*
- name: Package release assets - name: Package release assets
run: scripts/package-release-assets.sh run: scripts/package-release-assets.sh
@ -32,4 +33,4 @@ jobs:
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
draft: true draft: true
files: release/ouch-* files: output_assets/ouch-*

View File

@ -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-*

View File

@ -32,4 +32,4 @@ jobs:
uses: ./.github/workflows/build-artifacts-and-run-tests.yml uses: ./.github/workflows/build-artifacts-and-run-tests.yml
with: with:
matrix_all_combinations: false matrix_all_combinations: false
upload_artifacts: false artifact_upload_mode: none

View File

@ -18,7 +18,14 @@ Categories Used:
**Bullet points in chronological order by PR** **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.0...HEAD)
### New Features
### Improvements
### Bug Fixes
### Tweaks
## [0.6.0](https://github.com/ouch-org/ouch/compare/0.5.1...0.6.0)
### New Features ### New Features
@ -48,6 +55,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)) - 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)) - 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)) - 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) ## [0.5.1](https://github.com/ouch-org/ouch/compare/0.5.0...0.5.1)

2
Cargo.lock generated
View File

@ -1066,7 +1066,7 @@ checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]] [[package]]
name = "ouch" name = "ouch"
version = "0.5.1" version = "0.6.0"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"atty", "atty",

View File

@ -1,8 +1,8 @@
[package] [package]
name = "ouch" name = "ouch"
version = "0.5.1" version = "0.6.0"
authors = [ authors = [
"João M. Bezerra <marcospb19@hotmail.com>", "João Marcos <marcospb19@hotmail.com>",
"Vinícius Rodrigues Miguel <vrmiguel99@gmail.com>", "Vinícius Rodrigues Miguel <vrmiguel99@gmail.com>",
] ]
edition = "2021" edition = "2021"
@ -70,7 +70,7 @@ regex = "1.10.4"
test-strategy = "0.4.0" test-strategy = "0.4.0"
[features] [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_zlib = ["flate2/zlib", "gzp/deflate_zlib", "zip/deflate-zlib"]
use_zstd_thin = ["zstd/thin"] use_zstd_thin = ["zstd/thin"]
allow_piped_choice = [] allow_piped_choice = []

View File

@ -5,18 +5,12 @@
/// Set `OUCH_ARTIFACTS_FOLDER` to the name of the destination folder: /// Set `OUCH_ARTIFACTS_FOLDER` to the name of the destination folder:
/// ///
/// ```sh /// ```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. /// 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::{ use std::{
env, env,
fs::{create_dir_all, File}, fs::{create_dir_all, File},

View File

@ -1,28 +1,62 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
mkdir release mkdir output_assets
cd artifacts 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 TARGETS=(
cp -r "$dir/artifacts" "$dir/completions" "aarch64-pc-windows-msvc"
mkdir "$dir/man" "aarch64-unknown-linux-gnu"
mv "$dir"/completions/*.1 "$dir/man" "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"
)
# Temporary, we'll remove allow_piped_choice later
DEFAULT_FEATURES="allow_piped_choice+unrar+use_zlib+use_zstd_thin"
cp ../{README.md,LICENSE,CHANGELOG.md} "$dir" for target in "${TARGETS[@]}"; do
rm -r "$dir/artifacts" input_dir="ouch-${target}-${DEFAULT_FEATURES}"
if [[ "$dir" = *.exe ]]; then if [ ! -d "$input_dir" ]; then
target=${dir%.exe} echo "ERROR: Could not find artifact directory for $target with default features ($input_dir)"
mv "$dir/target/${target/ouch-/}/release/ouch.exe" "$dir" exit 1
rm -r "$dir/target" fi
mv "$dir" "$target"
zip -r "../release/$target.zip" "$target" echo "Processing $input_dir"
cp ../{README.md,LICENSE,CHANGELOG.md} "$input_dir"
mkdir -p "$input_dir/man"
mkdir -p "$input_dir/completions"
mv "$input_dir"/man-page-and-completions-artifacts/*.1 "$input_dir/man"
mv "$input_dir"/man-page-and-completions-artifacts/* "$input_dir/completions"
rm -r "$input_dir/man-page-and-completions-artifacts"
output_name="ouch-${target}"
if [[ "$target" == *"-windows-"* ]]; then
mv "$input_dir/target/$target/release/ouch.exe" "$input_dir"
rm -rf "$input_dir/target"
zip -r "../output_assets/${output_name}.zip" "$input_dir"
echo "Created output_assets/${output_name}.zip"
else else
mv "$dir/target/${dir/ouch-/}/release/ouch" "$dir" mv "$input_dir/target/$target/release/ouch" "$input_dir"
rm -r "$dir/target" rm -rf "$input_dir/target"
chmod +x "$dir/ouch" chmod +x "$input_dir/ouch"
tar czf "../release/$dir.tar.gz" "$dir"
tar czf "../output_assets/${output_name}.tar.gz" "$input_dir"
echo "Created output_assets/${output_name}.tar.gz"
fi fi
done done
echo "Done."

View File

@ -7,7 +7,7 @@ use unrar::Archive;
use crate::{ use crate::{
error::{Error, Result}, error::{Error, Result},
list::FileInArchive, list::FileInArchive,
utils::logger::info, utils::{logger::info, Bytes},
}; };
/// Unpacks the archive given by `archive_path` into the folder given by `output_folder`. /// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
@ -31,9 +31,9 @@ pub fn unpack_archive(
archive = if entry.is_file() { archive = if entry.is_file() {
if !quiet { if !quiet {
info(format!( info(format!(
"{} extracted. ({})", "extracted ({}) {}",
Bytes::new(entry.unpacked_size),
entry.filename.display(), entry.filename.display(),
entry.unpacked_size
)); ));
} }
unpacked += 1; unpacked += 1;

View File

@ -127,9 +127,9 @@ where
} else { } else {
if !quiet { if !quiet {
info(format!( info(format!(
"{:?} extracted. ({})", "extracted ({}) {:?}",
Bytes::new(entry.size()),
file_path.display(), file_path.display(),
Bytes::new(entry.size())
)); ));
} }

View File

@ -55,9 +55,9 @@ pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool)
// and so on // and so on
if !quiet { if !quiet {
info(format!( info(format!(
"{:?} extracted. ({})", "extracted ({}) {:?}",
utils::strip_cur_dir(&output_folder.join(file.path()?)),
Bytes::new(file.size()), Bytes::new(file.size()),
utils::strip_cur_dir(&output_folder.join(file.path()?)),
)); ));
files_unpacked += 1; files_unpacked += 1;

View File

@ -77,9 +77,9 @@ where
// same reason is in _is_dir: long, often not needed text // same reason is in _is_dir: long, often not needed text
if !quiet { if !quiet {
info(format!( info(format!(
"{:?} extracted. ({})", "extracted ({}) {:?}",
Bytes::new(file.size()),
file_path.display(), file_path.display(),
Bytes::new(file.size())
)); ));
} }

View File

@ -105,11 +105,11 @@ impl Bytes {
impl std::fmt::Display for Bytes { impl std::fmt::Display for Bytes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let &Self(num) = self; let num = self.0;
debug_assert!(num >= 0.0); debug_assert!(num >= 0.0);
if num < 1_f64 { if num < 1_f64 {
return write!(f, "{} B", num); return write!(f, "{:>6.2} B", num);
} }
let delimiter = 1000_f64; let delimiter = 1000_f64;
@ -117,9 +117,9 @@ impl std::fmt::Display for Bytes {
write!( write!(
f, f,
"{:.2} {}B", "{:>6.2} {:>2}B",
num / delimiter.powi(exponent), 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 mb = kb * 1000;
let gb = mb * 1000; let gb = mb * 1000;
assert_eq!("0 B", format_bytes(0)); // This is weird assert_eq!(" 0.00 B", format_bytes(0)); // This is weird
assert_eq!("1.00 B", format_bytes(b)); assert_eq!(" 1.00 B", format_bytes(b));
assert_eq!("999.00 B", format_bytes(b * 999)); assert_eq!("999.00 B", format_bytes(b * 999));
assert_eq!("12.00 MiB", format_bytes(mb * 12)); assert_eq!(" 12.00 MiB", format_bytes(mb * 12));
assert_eq!("123.00 MiB", format_bytes(mb * 123)); assert_eq!("123.00 MiB", format_bytes(mb * 123));
assert_eq!("5.50 MiB", format_bytes(mb * 5 + kb * 500)); assert_eq!(" 5.50 MiB", format_bytes(mb * 5 + kb * 500));
assert_eq!("7.54 GiB", format_bytes(gb * 7 + 540 * mb)); assert_eq!(" 7.54 GiB", format_bytes(gb * 7 + 540 * mb));
assert_eq!("1.20 TiB", format_bytes(gb * 1200)); assert_eq!(" 1.20 TiB", format_bytes(gb * 1200));
// bytes // bytes
assert_eq!("234.00 B", format_bytes(234)); assert_eq!("234.00 B", format_bytes(234));
assert_eq!("999.00 B", format_bytes(999)); assert_eq!("999.00 B", format_bytes(999));
// kilobytes // kilobytes
assert_eq!("2.23 kiB", format_bytes(2234)); assert_eq!(" 2.23 kiB", format_bytes(2234));
assert_eq!("62.50 kiB", format_bytes(62500)); assert_eq!(" 62.50 kiB", format_bytes(62500));
assert_eq!("329.99 kiB", format_bytes(329990)); assert_eq!("329.99 kiB", format_bytes(329990));
// megabytes // megabytes
assert_eq!("2.75 MiB", format_bytes(2750000)); assert_eq!(" 2.75 MiB", format_bytes(2750000));
assert_eq!("55.00 MiB", format_bytes(55000000)); assert_eq!(" 55.00 MiB", format_bytes(55000000));
assert_eq!("987.65 MiB", format_bytes(987654321)); assert_eq!("987.65 MiB", format_bytes(987654321));
// gigabytes // gigabytes
assert_eq!("5.28 GiB", format_bytes(5280000000)); assert_eq!(" 5.28 GiB", format_bytes(5280000000));
assert_eq!("95.20 GiB", format_bytes(95200000000)); assert_eq!(" 95.20 GiB", format_bytes(95200000000));
assert_eq!("302.00 GiB", format_bytes(302000000000)); assert_eq!("302.00 GiB", format_bytes(302000000000));
assert_eq!("302.99 GiB", format_bytes(302990000000)); assert_eq!("302.99 GiB", format_bytes(302990000000));
// Weird aproximation cases: // Weird aproximation cases:
assert_eq!("999.90 GiB", format_bytes(999900000000)); assert_eq!("999.90 GiB", format_bytes(999900000000));
assert_eq!("1.00 TiB", format_bytes(999990000000)); assert_eq!(" 1.00 TiB", format_bytes(999990000000));
} }
} }

View File

@ -0,0 +1,13 @@
---
source: tests/ui.rs
expression: stdout_lines
---
{
"",
"[INFO] Files unpacked: 4",
"[INFO] Successfully decompressed archive in <TMP_DIR>/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\"",
}

View File

@ -6,7 +6,7 @@
#[macro_use] #[macro_use]
mod utils; 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 insta::assert_snapshot as ui;
use regex::Regex; use regex::Regex;
@ -142,6 +142,29 @@ fn ui_test_ok_decompress() {
ui!(run_ouch("ouch decompress output.zst", dir)); 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::<BTreeSet<_>>();
insta::assert_debug_snapshot!(stdout_lines);
}
#[test] #[test]
fn ui_test_usage_help_flag() { fn ui_test_usage_help_flag() {
insta::with_settings!({filters => vec![ insta::with_settings!({filters => vec![