Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ouch for openSUSE:Factory checked in at 2023-01-07 17:19:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ouch (Old) and /work/SRC/openSUSE:Factory/.ouch.new.1563 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ouch" Sat Jan 7 17:19:52 2023 rev:4 rq:1056759 version:0.4.1~0 Changes: -------- --- /work/SRC/openSUSE:Factory/ouch/ouch.changes 2022-12-01 17:22:21.546605963 +0100 +++ /work/SRC/openSUSE:Factory/.ouch.new.1563/ouch.changes 2023-01-07 17:23:14.971421358 +0100 @@ -1,0 +2,21 @@ +Sat Jan 7 11:39:00 UTC 2023 - Michael Vetter <mvet...@suse.com> + +- Update to 0.4.1: + New Features: + * Add cli option to (de)compress quietly #325 + Improvements: + * Allow ouch to decompress archive into existing folder #321 + * Accept inserting subcommand-independent flags in any position #329 + * Improve extension parsing logic #330 + * Slight refactor when ensuring archive-only inputs #331 + * Use BStr to display possibly non-UTF8 byte sequences#332 + * Use ubyte instead of humansize #333 #333 + * Stop keeping track of the names of unpacked files #334 + * Clean up #335 + Bug fixes: + * Stop incorrectly asking to remove the parent dir #321 + * Fixed overwriting archive file when decompressing archive detected with MIME types. + Tweaks: + * Add scoop install instructions to readme #323 + +------------------------------------------------------------------- Old: ---- ouch-0.4.0~0.tar.xz New: ---- ouch-0.4.1~0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ouch.spec ++++++ --- /var/tmp/diff_new_pack.5qfvOe/_old 2023-01-07 17:23:16.027427658 +0100 +++ /var/tmp/diff_new_pack.5qfvOe/_new 2023-01-07 17:23:16.031427682 +0100 @@ -1,7 +1,7 @@ # # spec file for package ouch # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: ouch -Version: 0.4.0~0 +Version: 0.4.1~0 Release: 0 Summary: Compression and decompression utility for the terminal License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.5qfvOe/_old 2023-01-07 17:23:16.067427896 +0100 +++ /var/tmp/diff_new_pack.5qfvOe/_new 2023-01-07 17:23:16.071427920 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/ouch-org/ouch.git</param> <param name="versionformat">@PARENT_TAG@~@TAG_OFFSET@</param> <param name="scm">git</param> - <param name="revision">0.4.0</param> + <param name="revision">0.4.1</param> <param name="match-tag">*</param> <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param> <param name="versionrewrite-replacement">\1</param> ++++++ ouch-0.4.0~0.tar.xz -> ouch-0.4.1~0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/CHANGELOG.md new/ouch-0.4.1~0/CHANGELOG.md --- old/ouch-0.4.0~0/CHANGELOG.md 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/CHANGELOG.md 2023-01-05 23:15:43.000000000 +0100 @@ -18,9 +18,32 @@ **Bullet points in chronological order by PR** -## [Unreleased](https://github.com/ouch-org/ouch/compare/0.4.0...HEAD) +## [Unreleased](https://github.com/ouch-org/ouch/compare/0.4.1...HEAD) -This is currently empty. +## [0.4.1](https://github.com/ouch-org/ouch/compare/0.4.0...0.4.1) + +### New Features + +- Add cli option to (de)compress quietly [\#325](https://github.com/ouch-org/ouch/pull/325) ([a-moreira](https://github.com/a-moreira)) + +### Improvements + +- Allow ouch to decompress archive into existing folder [\#321](https://github.com/ouch-org/ouch/pull/321) ([a-moreira](https://github.com/a-moreira)) +- Accept inserting subcommand-independent flags in any position [\#329](https://github.com/ouch-org/ouch/pull/329) ([marcospb19](https://github.com/marcospb19)) +- Improve extension parsing logic [\#330](https://github.com/ouch-org/ouch/pull/330) ([figsoda](https://github.com/figsoda)) +- Slight refactor when ensuring archive-only inputs [\#331](https://github.com/ouch-org/ouch/pull/331) ([vrmiguel](https://github.com/vrmiguel)) +- Use BStr to display possibly non-UTF8 byte sequences[\#332](https://github.com/ouch-org/ouch/pull/332) ([vrmiguel](https://github.com/vrmiguel)) +- Use ubyte instead of humansize #333 [\#333](https://github.com/ouch-org/ouch/pull/333) ([vrmiguel](https://github.com/vrmiguel)) +- Stop keeping track of the names of unpacked files [\#334](https://github.com/ouch-org/ouch/pull/334) ([vrmiguel](https://github.com/vrmiguel)) +- Clean up [\#335](https://github.com/ouch-org/ouch/pull/335) ([figsoda](https://github.com/figsoda)) + +### Bug fixes + +- Stop incorrectly asking to remove the parent dir [\#321](https://github.com/ouch-org/ouch/pull/321) ([a-moreira](https://github.com/a-moreira)) + +### Tweaks + +- Add scoop install instructions to readme [\#323](https://github.com/ouch-org/ouch/pull/323) ([rasa](https://github.com/rasa)) ## [0.4.0](https://github.com/ouch-org/ouch/compare/0.3.1...0.4.0) (2022-11-20) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/Cargo.lock new/ouch-0.4.1~0/Cargo.lock --- old/ouch-0.4.0~0/Cargo.lock 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/Cargo.lock 2023-01-05 23:15:43.000000000 +0100 @@ -19,11 +19,11 @@ [[package]] name = "assert_cmd" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba45b8163c49ab5f972e59a8a5a03b6d2972619d486e19ec9fe744f7c2753d3c" +checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3" dependencies = [ - "bstr 1.0.1", + "bstr 1.1.0", "doc-comment", "predicates", "predicates-core", @@ -37,7 +37,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -80,9 +80,9 @@ [[package]] name = "bstr" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" dependencies = [ "memchr", "once_cell", @@ -119,9 +119,9 @@ [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" dependencies = [ "jobserver", ] @@ -145,14 +145,14 @@ [[package]] name = "clap" -version = "4.0.26" +version = "4.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" dependencies = [ - "atty", "bitflags", "clap_derive", "clap_lex", + "is-terminal", "once_cell", "strsim", "termcolor", @@ -160,9 +160,9 @@ [[package]] name = "clap_complete" -version = "4.0.5" +version = "4.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b0fba905b035a30d25c1b585bf1171690712fbb0ad3ac47214963aa4acc36c" +checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" dependencies = [ "clap", ] @@ -191,9 +191,9 @@ [[package]] name = "clap_mangen" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa149477df7854a1497db0def32b8a65bf98f72a14d04ac75b01938285d83420" +checksum = "904eb24d05ad587557e0f484ddce5c737c30cf81372badb16d13e41c4b8340b1" dependencies = [ "clap", "roff", @@ -236,6 +236,27 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] name = "fastrand" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -246,9 +267,9 @@ [[package]] name = "filetime" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ "cfg-if", "libc", @@ -258,9 +279,9 @@ [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "libz-sys", @@ -319,12 +340,12 @@ ] [[package]] -name = "humansize" -version = "2.1.2" +name = "hermit-abi" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e682e2bd70ecbcce5209f11a992a4ba001fea8e60acf7860ce007629e6d2756" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ - "libm", + "libc", ] [[package]] @@ -347,9 +368,9 @@ [[package]] name = "infer" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6c16b11a665b26aeeb9b1d7f954cdeb034be38dd00adab4f2ae921a8fee804" +checksum = "a898e4b7951673fce96614ce5751d13c40fc5674bc2d759288e46c3ab62598b3" dependencies = [ "cfb", ] @@ -364,6 +385,28 @@ ] [[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] name = "is_executable" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -383,9 +426,9 @@ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "jobserver" @@ -404,15 +447,9 @@ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" - -[[package]] -name = "libm" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libz-sys" @@ -432,6 +469,12 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -468,9 +511,9 @@ [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] @@ -486,9 +529,9 @@ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "os_str_bytes" @@ -498,10 +541,11 @@ [[package]] name = "ouch" -version = "0.4.0" +version = "0.4.1" dependencies = [ "assert_cmd", "atty", + "bstr 1.1.0", "bzip2", "clap", "clap_complete", @@ -509,7 +553,6 @@ "filetime", "flate2", "fs-err", - "humansize", "ignore", "infer", "is_executable", @@ -526,6 +569,7 @@ "tempfile", "test-strategy", "time", + "ubyte", "xz2", "zip", "zstd", @@ -534,9 +578,9 @@ [[package]] name = "parse-display" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b25af4ef94a8528b41fb49a696e361dc6ef975c782417268072d987ac327964" +checksum = "6f96cc033d72896bb9a2c239a14e1141c3e2eae6d649e7c10ef4e598d66bc86c" dependencies = [ "once_cell", "parse-display-derive", @@ -545,9 +589,9 @@ [[package]] name = "parse-display-derive" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f106cced1f4b645e3fca6125105cdf7407e35d1af710f290aac530f6b826b9" +checksum = "e5587062be441f3d868f7c4c9d13c67f286b03aa679d7f8176ef80bf2ee79e5d" dependencies = [ "once_cell", "proc-macro2", @@ -572,9 +616,9 @@ [[package]] name = "predicates" -version = "2.1.3" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6bd09a7f7e68f3f0bf710fb7ab9c4615a488b58b5f653382a687701e458c92" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", "itertools", @@ -623,9 +667,9 @@ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -664,9 +708,9 @@ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -758,6 +802,20 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] +name = "rustix" +version = "0.36.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] name = "rusty-fork" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -780,9 +838,9 @@ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" [[package]] name = "snap" @@ -821,9 +879,9 @@ [[package]] name = "syn" -version = "1.0.103" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -919,10 +977,16 @@ ] [[package]] +name = "ubyte" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" + +[[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "uuid" @@ -1089,9 +1153,9 @@ [[package]] name = "zstd" -version = "0.12.0+zstd.1.5.2" +version = "0.12.1+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8148aa921e9d53217ab9322f8553bd130f7ae33489db68b381d76137d2e6374" +checksum = "5c947d2adc84ff9a59f2e3c03b81aa4128acf28d6ad7d56273f7e8af14e47bea" dependencies = [ "zstd-safe", ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/Cargo.toml new/ouch-0.4.1~0/Cargo.toml --- old/ouch-0.4.0~0/Cargo.toml 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/Cargo.toml 2023-01-05 23:15:43.000000000 +0100 @@ -1,35 +1,36 @@ [package] name = "ouch" -version = "0.4.0" +version = "0.4.1" authors = ["VinÃcius Rodrigues Miguel <vrmigue...@gmail.com>", "João M. Bezerra <marcosp...@hotmail.com>"] edition = "2021" readme = "README.md" repository = "https://github.com/ouch-org/ouch" license = "MIT" -keywords = ["decompression", "compression", "zip", "tar", "gzip", "accessibility", "a11y"] +keywords = ["decompression", "compression", "cli"] categories = ["command-line-utilities", "compression", "encoding"] description = "A command-line utility for easily compressing and decompressing files and directories." [dependencies] atty = "0.2.14" +bstr = { version = "1.1.0", default-features = false, features = ["std"] } bzip2 = "0.4.3" -clap = { version = "4.0.26", features = ["derive", "env"] } -filetime = "0.2.18" -flate2 = { version = "1.0.24", default-features = false } +clap = { version = "4.0.32", features = ["derive", "env"] } +filetime = "0.2.19" +flate2 = { version = "1.0.25", default-features = false } fs-err = "2.9.0" -humansize = "2.1.2" ignore = "0.4.18" -libc = "0.2.137" +libc = "0.2.139" linked-hash-map = "0.5.6" lzzzz = "1.0.4" -once_cell = "1.16.0" +once_cell = "1.17.0" same-file = "1.0.6" snap = "1.1.0" tar = "0.4.38" tempfile = "3.3.0" +ubyte = { version = "0.10.3", default-features = false } xz2 = "0.1.7" zip = { version = "0.6.3", default-features = false, features = ["time"] } -zstd = { version = "0.12.0", default-features = false } +zstd = { version = "0.12.1", default-features = false } # zstd-sys > 2.0.1 unconditionally enables thin LTO and causes CI to fail # https://github.com/gyscos/zstd-rs/pull/155 zstd-sys = "=2.0.1" @@ -41,14 +42,14 @@ is_executable = "1.0.1" [build-dependencies] -clap = { version = "4.0.26", features = ["derive", "env", "string"] } -clap_complete = "4.0.5" -clap_mangen = "0.2.4" +clap = { version = "4.0.32", features = ["derive", "env", "string"] } +clap_complete = "4.0.7" +clap_mangen = "0.2.6" [dev-dependencies] -assert_cmd = "2.0.6" -infer = "0.11.0" -parse-display = "0.6.0" +assert_cmd = "2.0.7" +infer = "0.12.0" +parse-display = "0.8.0" proptest = "1.0.0" rand = { version = "0.8.5", default-features = false, features = ["small_rng", "std"] } test-strategy = "0.2.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/LICENSE new/ouch-0.4.1~0/LICENSE --- old/ouch-0.4.0~0/LICENSE 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/LICENSE 2023-01-05 23:15:43.000000000 +0100 @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2022 VinÃcius R. Miguel, João Marcos P. Bezerra and contributors +Copyright (c) 2021-2023 VinÃcius R. Miguel, João Marcos P. Bezerra and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/README.md new/ouch-0.4.1~0/README.md --- old/ouch-0.4.0~0/README.md 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/README.md 2023-01-05 23:15:43.000000000 +0100 @@ -126,6 +126,12 @@ yay -S ouch ``` +## On Windows via Scoop + +```cmd +scoop install ouch +``` + ## From crates.io ```bash diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/rust-toolchain new/ouch-0.4.1~0/rust-toolchain --- old/ouch-0.4.0~0/rust-toolchain 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/rust-toolchain 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -nightly diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/archive/tar.rs new/ouch-0.4.1~0/src/archive/tar.rs --- old/ouch-0.4.0~0/src/archive/tar.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/archive/tar.rs 2023-01-05 23:15:43.000000000 +0100 @@ -9,43 +9,43 @@ }; use fs_err as fs; -use humansize::{format_size, DECIMAL}; use same_file::Handle; +use ubyte::ToByteUnit; use crate::{ error::FinalError, info, list::FileInArchive, - utils::{self, FileVisibilityPolicy}, + utils::{self, EscapedPathDisplay, FileVisibilityPolicy}, warning, }; /// Unpacks the archive given by `archive` into the folder given by `into`. /// Assumes that output_folder is empty -pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path) -> crate::Result<Vec<PathBuf>> { +pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool) -> crate::Result<usize> { assert!(output_folder.read_dir().expect("dir exists").count() == 0); let mut archive = tar::Archive::new(reader); - let mut files_unpacked = vec![]; + let mut files_unpacked = 0; for file in archive.entries()? { let mut file = file?; - let file_path = output_folder.join(file.path()?); file.unpack_in(output_folder)?; // This is printed for every file in the archive and has little // importance for most users, but would generate lots of // spoken text for users using screen readers, braille displays // and so on + if !quiet { + info!( + inaccessible, + "{:?} extracted. ({})", + utils::strip_cur_dir(&output_folder.join(file.path()?)), + file.size().bytes(), + ); - info!( - inaccessible, - "{:?} extracted. ({})", - utils::strip_cur_dir(&output_folder.join(file.path()?)), - format_size(file.size(), DECIMAL), - ); - - files_unpacked.push(file_path); + files_unpacked += 1; + } } Ok(files_unpacked) @@ -86,6 +86,7 @@ output_path: &Path, writer: W, file_visibility_policy: FileVisibilityPolicy, + quiet: bool, ) -> crate::Result<W> where W: Write, @@ -118,7 +119,9 @@ // little importance for most users, but would generate lots of // spoken text for users using screen readers, braille displays // and so on - info!(inaccessible, "Compressing '{}'.", utils::to_utf(path)); + if !quiet { + info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path)); + } if path.is_dir() { builder.append_dir(path, path)?; @@ -137,7 +140,7 @@ builder.append_file(path, file.file_mut()).map_err(|err| { FinalError::with_title("Could not create archive") .detail("Unexpected error while trying to read file") - .detail(format!("Error: {}.", err)) + .detail(format!("Error: {err}.")) })?; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/archive/zip.rs new/ouch-0.4.1~0/src/archive/zip.rs --- old/ouch-0.4.0~0/src/archive/zip.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/archive/zip.rs 2023-01-05 23:15:43.000000000 +0100 @@ -12,8 +12,8 @@ use filetime::{set_file_mtime, FileTime}; use fs_err as fs; -use humansize::{format_size, DECIMAL}; use same_file::Handle; +use ubyte::ToByteUnit; use zip::{self, read::ZipFile, DateTime, ZipArchive}; use crate::{ @@ -21,21 +21,21 @@ info, list::FileInArchive, utils::{ - self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, to_utf, - FileVisibilityPolicy, + self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, + EscapedPathDisplay, FileVisibilityPolicy, }, warning, }; /// Unpacks the archive given by `archive` into the folder given by `output_folder`. /// Assumes that output_folder is empty -pub fn unpack_archive<R>(mut archive: ZipArchive<R>, output_folder: &Path) -> crate::Result<Vec<PathBuf>> +pub fn unpack_archive<R>(mut archive: ZipArchive<R>, output_folder: &Path, quiet: bool) -> crate::Result<usize> where R: Read + Seek, { assert!(output_folder.read_dir().expect("dir exists").count() == 0); - let mut unpacked_files = Vec::with_capacity(archive.len()); + let mut unpacked_files = 0; for idx in 0..archive.len() { let mut file = archive.by_index(idx)?; @@ -54,7 +54,9 @@ // importance for most users, but would generate lots of // spoken text for users using screen readers, braille displays // and so on - info!(inaccessible, "File {} extracted to \"{}\"", idx, file_path.display()); + if !quiet { + info!(inaccessible, "File {} extracted to \"{}\"", idx, file_path.display()); + } fs::create_dir_all(&file_path)?; } _is_file @ false => { @@ -66,12 +68,14 @@ let file_path = strip_cur_dir(file_path.as_path()); // same reason is in _is_dir: long, often not needed text - info!( - inaccessible, - "{:?} extracted. ({})", - file_path.display(), - format_size(file.size(), DECIMAL), - ); + if !quiet { + info!( + inaccessible, + "{:?} extracted. ({})", + file_path.display(), + file.size().bytes() + ); + } let mut output_file = fs::File::create(file_path)?; io::copy(&mut file, &mut output_file)?; @@ -83,7 +87,7 @@ #[cfg(unix)] unix_set_permissions(&file_path, &file)?; - unpacked_files.push(file_path); + unpacked_files += 1; } Ok(unpacked_files) @@ -135,6 +139,7 @@ output_path: &Path, writer: W, file_visibility_policy: FileVisibilityPolicy, + quiet: bool, ) -> crate::Result<W> where W: Write + Seek, @@ -185,7 +190,9 @@ // little importance for most users, but would generate lots of // spoken text for users using screen readers, braille displays // and so on - info!(inaccessible, "Compressing '{}'.", to_utf(path)); + if !quiet { + info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path)); + } let metadata = match path.metadata() { Ok(metadata) => metadata, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/commands/compress.rs new/ouch-0.4.1~0/src/commands/compress.rs --- old/ouch-0.4.0~0/src/commands/compress.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/commands/compress.rs 2023-01-05 23:15:43.000000000 +0100 @@ -32,6 +32,7 @@ extensions: Vec<Extension>, output_file: fs::File, output_path: &Path, + quiet: bool, question_policy: QuestionPolicy, file_visibility_policy: FileVisibilityPolicy, ) -> crate::Result<bool> { @@ -74,7 +75,7 @@ io::copy(&mut reader, &mut writer)?; } Tar => { - archive::tar::build_archive_from_paths(&files, output_path, &mut writer, file_visibility_policy)?; + archive::tar::build_archive_from_paths(&files, output_path, &mut writer, file_visibility_policy, quiet)?; writer.flush()?; } Zip => { @@ -88,7 +89,13 @@ let mut vec_buffer = Cursor::new(vec![]); - archive::zip::build_archive_from_paths(&files, output_path, &mut vec_buffer, file_visibility_policy)?; + archive::zip::build_archive_from_paths( + &files, + output_path, + &mut vec_buffer, + file_visibility_policy, + quiet, + )?; vec_buffer.rewind()?; io::copy(&mut vec_buffer, &mut writer)?; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/commands/decompress.rs new/ouch-0.4.1~0/src/commands/decompress.rs --- old/ouch-0.4.0~0/src/commands/decompress.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/commands/decompress.rs 2023-01-05 23:15:43.000000000 +0100 @@ -30,6 +30,7 @@ output_dir: &Path, output_file_path: PathBuf, question_policy: QuestionPolicy, + quiet: bool, ) -> crate::Result<()> { assert!(output_dir.exists()); let reader = fs::File::open(input_file_path)?; @@ -47,8 +48,8 @@ }] = formats.as_slice() { let zip_archive = zip::ZipArchive::new(reader)?; - let files = if let ControlFlow::Continue(files) = smart_unpack( - |output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir), + let files_unpacked = if let ControlFlow::Continue(files) = smart_unpack( + |output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet), output_dir, &output_file_path, question_policy, @@ -66,7 +67,7 @@ accessible, "Successfully decompressed archive in {} ({} files).", nice_directory_display(output_dir), - files.len() + files_unpacked ); return Ok(()); @@ -107,11 +108,11 @@ io::copy(&mut reader, &mut writer)?; - vec![output_file_path] + 1 } Tar => { if let ControlFlow::Continue(files) = smart_unpack( - |output_dir| crate::archive::tar::unpack_archive(reader, output_dir), + |output_dir| crate::archive::tar::unpack_archive(reader, output_dir, quiet), output_dir, &output_file_path, question_policy, @@ -135,7 +136,7 @@ let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?; if let ControlFlow::Continue(files) = smart_unpack( - |output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir), + |output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet), output_dir, &output_file_path, question_policy, @@ -156,7 +157,7 @@ "Successfully decompressed archive in {}.", nice_directory_display(output_dir) ); - info!(accessible, "Files unpacked: {}", files_unpacked.len()); + info!(accessible, "Files unpacked: {}", files_unpacked); Ok(()) } @@ -167,11 +168,11 @@ /// output_dir named after the archive (given by `output_file_path`) /// Note: This functions assumes that `output_dir` exists fn smart_unpack( - unpack_fn: impl FnOnce(&Path) -> crate::Result<Vec<PathBuf>>, + unpack_fn: impl FnOnce(&Path) -> crate::Result<usize>, output_dir: &Path, output_file_path: &Path, question_policy: QuestionPolicy, -) -> crate::Result<ControlFlow<(), Vec<PathBuf>>> { +) -> crate::Result<ControlFlow<(), usize>> { assert!(output_dir.exists()); let temp_dir = tempfile::tempdir_in(output_dir)?; let temp_dir_path = temp_dir.path(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/commands/mod.rs new/ouch-0.4.1~0/src/commands/mod.rs --- old/ouch-0.4.0~0/src/commands/mod.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/commands/mod.rs 2023-01-05 23:15:43.000000000 +0100 @@ -18,7 +18,8 @@ info, list::ListOptions, utils::{ - self, pretty_format_list_of_paths, to_utf, try_infer_extension, user_wants_to_continue, FileVisibilityPolicy, + self, pretty_format_list_of_paths, to_utf, try_infer_extension, user_wants_to_continue, EscapedPathDisplay, + FileVisibilityPolicy, }, warning, Opts, QuestionAction, QuestionPolicy, Subcommand, }; @@ -67,6 +68,31 @@ None } +/// In the context of listing archives, this function checks if `ouch` was told to list +/// the contents of a compressed file that is not an archive +fn check_for_non_archive_formats(files: &[PathBuf], formats: &[Vec<Extension>]) -> crate::Result<()> { + let mut not_archives = files + .iter() + .zip(formats) + .filter(|(_, formats)| !formats.first().map(Extension::is_archive).unwrap_or(false)) + .map(|(path, _)| path) + .peekable(); + + if not_archives.peek().is_some() { + let not_archives: Vec<_> = not_archives.collect(); + let error = FinalError::with_title("Cannot list archive contents") + .detail("Only archives can have their contents listed") + .detail(format!( + "Files are not archives: {}", + pretty_format_list_of_paths(¬_archives) + )); + + return Err(error.into()); + } + + Ok(()) +} + /// This function checks what command needs to be run and performs A LOT of ahead-of-time checks /// to assume everything is OK. /// @@ -90,7 +116,7 @@ let formats = extension::extensions_from_path(&output_path); let first_format = formats.first().ok_or_else(|| { - let output_path = to_utf(&output_path); + let output_path = EscapedPathDisplay::new(&output_path); FinalError::with_title(format!("Cannot compress to '{output_path}'.")) .detail("You shall supply the compression format") .hint("Try adding supported extensions (see --help):") @@ -113,43 +139,43 @@ // To file.tar.bz.xz let suggested_output_path = build_archive_file_suggestion(&output_path, ".tar") .expect("output path should contain a compression format"); - let output_path = to_utf(&output_path); + let output_path = EscapedPathDisplay::new(&output_path); let first_detail_message = if is_multiple_inputs { "You are trying to compress multiple files." } else { "You are trying to compress a folder." }; - let error = FinalError::with_title(format!("Cannot compress to '{}'.", output_path)) + let error = FinalError::with_title(format!("Cannot compress to '{output_path}'.")) .detail(first_detail_message) .detail(format!( - "The compression format '{}' does not accept multiple files.", - &formats[0] + "The compression format '{first_format}' does not accept multiple files.", )) .detail("Formats that bundle files into an archive are .tar and .zip.") - .hint(format!("Try inserting '.tar' or '.zip' before '{}'.", &formats[0])) - .hint(format!("From: {}", output_path)) - .hint(format!("To: {}", suggested_output_path)); + .hint(format!("Try inserting '.tar' or '.zip' before '{first_format}'.")) + .hint(format!("From: {output_path}")) + .hint(format!("To: {suggested_output_path}")); return Err(error.into()); } if let Some(format) = formats.iter().skip(1).find(|format| format.is_archive()) { - let error = FinalError::with_title(format!("Cannot compress to '{}'.", to_utf(&output_path))) - .detail(format!("Found the format '{}' in an incorrect position.", format)) - .detail(format!( - "'{}' can only be used at the start of the file extension.", - format - )) - .hint(format!( - "If you wish to compress multiple files, start the extension with '{}'.", - format - )) - .hint(format!( - "Otherwise, remove the last '{}' from '{}'.", - format, - to_utf(&output_path) - )); + let error = FinalError::with_title(format!( + "Cannot compress to '{}'.", + EscapedPathDisplay::new(&output_path) + )) + .detail(format!("Found the format '{format}' in an incorrect position.")) + .detail(format!( + "'{format}' can only be used at the start of the file extension." + )) + .hint(format!( + "If you wish to compress multiple files, start the extension with '{format}'." + )) + .hint(format!( + "Otherwise, remove the last '{}' from '{}'.", + format, + EscapedPathDisplay::new(&output_path) + )); return Err(error.into()); } @@ -164,6 +190,7 @@ formats, output_file, &output_path, + args.quiet, question_policy, file_visibility_policy, ); @@ -181,7 +208,10 @@ // out that we left a possibly CORRUPTED file at `output_path` if utils::remove_file_or_dir(&output_path).is_err() { eprintln!("{red}FATAL ERROR:\n", red = *colors::RED); - eprintln!(" Ouch failed to delete the file '{}'.", to_utf(&output_path)); + eprintln!( + " Ouch failed to delete the file '{}'.", + EscapedPathDisplay::new(&output_path) + ); eprintln!(" Please delete it manually."); eprintln!(" This file is corrupted if compression didn't finished."); @@ -214,7 +244,7 @@ .map(|(input_path, _)| PathBuf::from(input_path)) .collect(); - if !files_missing_format.is_empty() { + if let Some(path) = files_missing_format.first() { let error = FinalError::with_title("Cannot decompress files without extensions") .detail(format!( "Files without supported extensions: {}", @@ -227,7 +257,7 @@ .hint("Or overwrite this option with the '--format' flag:") .hint(format!( " ouch decompress {} --format tar.gz", - to_utf(&files_missing_format[0]) + EscapedPathDisplay::new(path), )); return Err(error.into()); @@ -236,10 +266,6 @@ // The directory that will contain the output files // We default to the current directory if the user didn't specify an output directory with --dir let output_dir = if let Some(dir) = output_dir { - if !utils::clear_path(&dir, question_policy)? { - // User doesn't want to overwrite - return Ok(()); - } utils::create_dir_if_non_existent(&dir)?; dir } else { @@ -248,14 +274,21 @@ for ((input_path, formats), file_name) in files.iter().zip(formats).zip(output_paths) { let output_file_path = output_dir.join(file_name); // Path used by single file format archives - decompress_file(input_path, formats, &output_dir, output_file_path, question_policy)?; + decompress_file( + input_path, + formats, + &output_dir, + output_file_path, + question_policy, + args.quiet, + )?; } } Subcommand::List { archives: files, tree } => { let mut formats = vec![]; for path in files.iter() { - let (_, file_formats) = extension::separate_known_extensions_from_name(path); + let file_formats = extension::extensions_from_path(path); formats.push(file_formats); } @@ -263,23 +296,8 @@ return Ok(()); } - let not_archives: Vec<PathBuf> = files - .iter() - .zip(&formats) - .filter(|(_, formats)| !formats.first().map(Extension::is_archive).unwrap_or(false)) - .map(|(path, _)| path.clone()) - .collect(); - - if !not_archives.is_empty() { - let error = FinalError::with_title("Cannot list archive contents") - .detail("Only archives can have their contents listed") - .detail(format!( - "Files are not archives: {}", - pretty_format_list_of_paths(¬_archives) - )); - - return Err(error.into()); - } + // Ensure we were not told to list the content of a non-archive compressed file + check_for_non_archive_formats(&files, &formats)?; let list_options = ListOptions { tree }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/error.rs new/ouch-0.4.1~0/src/error.rs --- old/ouch-0.4.0~0/src/error.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/error.rs 2023-01-05 23:15:43.000000000 +0100 @@ -76,7 +76,7 @@ if is_running_in_accessible_mode() { write!(f, "\n{}hints:{}", *GREEN, *RESET)?; for hint in &self.hints { - write!(f, "\n{}", hint)?; + write!(f, "\n{hint}")?; } } else { for hint in &self.hints { @@ -138,7 +138,7 @@ Error::Custom { reason } => reason.clone(), }; - write!(f, "{}", err) + write!(f, "{err}") } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/extension.rs new/ouch-0.4.1~0/src/extension.rs --- old/ouch-0.4.0~0/src/extension.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/extension.rs 2023-01-05 23:15:43.000000000 +0100 @@ -1,6 +1,8 @@ //! Our representation of all the supported compression formats. -use std::{ffi::OsStr, fmt, path::Path}; +use std::{fmt, path::Path}; + +use bstr::ByteSlice; use self::CompressionFormat::*; use crate::warning; @@ -104,54 +106,61 @@ "zst", ]; +pub fn to_extension(ext: &[u8]) -> Option<Extension> { + Some(Extension::new( + match ext { + b"tar" => &[Tar], + b"tgz" => &[Tar, Gzip], + b"tbz" | b"tbz2" => &[Tar, Bzip], + b"tlz4" => &[Tar, Lz4], + b"txz" | b"tlzma" => &[Tar, Lzma], + b"tsz" => &[Tar, Snappy], + b"tzst" => &[Tar, Zstd], + b"zip" => &[Zip], + b"bz" | b"bz2" => &[Bzip], + b"gz" => &[Gzip], + b"lz4" => &[Lz4], + b"xz" | b"lzma" => &[Lzma], + b"sz" => &[Snappy], + b"zst" => &[Zstd], + _ => return None, + }, + ext.to_str_lossy(), + )) +} + +pub fn split_extension<'a>(name: &mut &'a [u8]) -> Option<&'a [u8]> { + let (new_name, ext) = name.rsplit_once_str(b".")?; + if matches!(new_name, b"" | b"." | b"..") { + return None; + } + *name = new_name; + Some(ext) +} + /// Extracts extensions from a path. /// /// Returns both the remaining path and the list of extension objects -pub fn separate_known_extensions_from_name(mut path: &Path) -> (&Path, Vec<Extension>) { +pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec<Extension>) { let mut extensions = vec![]; - if let Some(file_stem) = path.file_stem().and_then(OsStr::to_str) { - let file_stem = file_stem.trim_matches('.'); + let Some(mut name) = path.file_name().and_then(<[u8] as ByteSlice>::from_os_str) else { + return (path, extensions); + }; + + // While there is known extensions at the tail, grab them + while let Some(extension) = split_extension(&mut name).and_then(to_extension) { + extensions.insert(0, extension); + } + if let Ok(name) = name.to_str() { + let file_stem = name.trim_matches('.'); if SUPPORTED_EXTENSIONS.contains(&file_stem) { warning!("Received a file with name '{file_stem}', but {file_stem} was expected as the extension."); } } - // While there is known extensions at the tail, grab them - while let Some(extension) = path.extension().and_then(OsStr::to_str) { - let formats: &[CompressionFormat] = match extension { - "tar" => &[Tar], - "tgz" => &[Tar, Gzip], - "tbz" | "tbz2" => &[Tar, Bzip], - "tlz4" => &[Tar, Lz4], - "txz" | "tlzma" => &[Tar, Lzma], - "tsz" => &[Tar, Snappy], - "tzst" => &[Tar, Zstd], - "zip" => &[Zip], - "bz" | "bz2" => &[Bzip], - "gz" => &[Gzip], - "lz4" => &[Lz4], - "xz" | "lzma" => &[Lzma], - "sz" => &[Snappy], - "zst" => &[Zstd], - _ => break, - }; - - let extension = Extension::new(formats, extension); - extensions.push(extension); - - // Update for the next iteration - path = if let Some(stem) = path.file_stem() { - Path::new(stem) - } else { - Path::new("") - }; - } - // Put the extensions in the correct order: left to right - extensions.reverse(); - - (path, extensions) + (name.to_path().unwrap(), extensions) } /// Extracts extensions from a path, return only the list of extension objects diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/list.rs new/ouch-0.4.1~0/src/list.rs --- old/ouch-0.4.0~0/src/list.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/list.rs 2023-01-05 23:15:43.000000000 +0100 @@ -57,7 +57,7 @@ if is_dir { // if colors are deactivated, print final / to mark directories if BLUE.is_empty() { - println!("{}/", name); + println!("{name}/"); // if in ACCESSIBLE mode, use colors but print final / in case colors // aren't read out aloud with a screen reader or aren't printed on a // braille reader @@ -68,7 +68,7 @@ } } else { // not a dir -> just print the file name - println!("{}", name); + println!("{name}"); } } @@ -142,7 +142,7 @@ false => draw::FINAL_BRANCH, }; - print!("{}{}", prefix, final_part); + print!("{prefix}{final_part}"); let is_dir = match self.file { Some(FileInArchive { is_dir, .. }) => is_dir, None => true, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/main.rs new/ouch-0.4.1~0/src/main.rs --- old/ouch-0.4.0~0/src/main.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/main.rs 2023-01-05 23:15:43.000000000 +0100 @@ -31,7 +31,7 @@ fn main() { if let Err(err) = run() { - eprintln!("{}", err); + eprintln!("{err}"); std::process::exit(EXIT_FAILURE); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/opts.rs new/ouch-0.4.1~0/src/opts.rs --- old/ouch-0.4.0~0/src/opts.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/opts.rs 2023-01-05 23:15:43.000000000 +0100 @@ -26,11 +26,15 @@ pub accessible: bool, /// Ignores hidden files - #[arg(short = 'H', long)] + #[arg(short = 'H', long, global = true)] pub hidden: bool, + /// Silences output + #[arg(short = 'q', long, global = true)] + pub quiet: bool, + /// Ignores files matched by git's ignore files - #[arg(short = 'g', long)] + #[arg(short = 'g', long, global = true)] pub gitignore: bool, /// Ouch and claps subcommands diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/utils/formatting.rs new/ouch-0.4.1~0/src/utils/formatting.rs --- old/ouch-0.4.0~0/src/utils/formatting.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/utils/formatting.rs 2023-01-05 23:15:43.000000000 +0100 @@ -1,7 +1,45 @@ -use std::{borrow::Cow, path::Path}; +use std::{borrow::Cow, fmt::Display, path::Path}; use crate::CURRENT_DIRECTORY; +/// Converts invalid UTF-8 bytes to the Unicode replacement codepoint (�) in its Display implementation. +pub struct EscapedPathDisplay<'a> { + path: &'a Path, +} + +impl<'a> EscapedPathDisplay<'a> { + pub fn new(path: &'a Path) -> Self { + Self { path } + } +} + +#[cfg(unix)] +impl Display for EscapedPathDisplay<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use std::os::unix::prelude::OsStrExt; + + let bstr = bstr::BStr::new(self.path.as_os_str().as_bytes()); + + write!(f, "{bstr}") + } +} + +#[cfg(windows)] +impl Display for EscapedPathDisplay<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use std::{char, fmt::Write, os::windows::prelude::OsStrExt}; + + let utf16 = self.path.as_os_str().encode_wide(); + let chars = char::decode_utf16(utf16).map(|decoded| decoded.unwrap_or(char::REPLACEMENT_CHARACTER)); + + for char in chars { + f.write_char(char)?; + } + + Ok(()) + } +} + /// Converts an OsStr to utf8 with custom formatting. /// /// This is different from [`Path::display`]. @@ -9,7 +47,7 @@ /// See <https://gist.github.com/marcospb19/ebce5572be26397cf08bbd0fd3b65ac1> for a comparison. pub fn to_utf(os_str: &Path) -> Cow<str> { let format = || { - let text = format!("{:?}", os_str); + let text = format!("{os_str:?}"); Cow::Owned(text.trim_matches('"').to_string()) }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/utils/fs.rs new/ouch-0.4.1~0/src/utils/fs.rs --- old/ouch-0.4.0~0/src/utils/fs.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/utils/fs.rs 2023-01-05 23:15:43.000000000 +0100 @@ -8,8 +8,8 @@ use fs_err as fs; -use super::{to_utf, user_wants_to_overwrite}; -use crate::{extension::Extension, info, QuestionPolicy}; +use super::user_wants_to_overwrite; +use crate::{extension::Extension, info, utils::EscapedPathDisplay, QuestionPolicy}; /// Remove `path` asking the user to overwrite if necessary. /// @@ -41,7 +41,7 @@ fs::create_dir_all(path)?; // creating a directory is an important change to the file system we // should always inform the user about - info!(accessible, "directory {} created.", to_utf(path)); + info!(accessible, "directory {} created.", EscapedPathDisplay::new(path)); } Ok(()) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/utils/mod.rs new/ouch-0.4.1~0/src/utils/mod.rs --- old/ouch-0.4.0~0/src/utils/mod.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/utils/mod.rs 2023-01-05 23:15:43.000000000 +0100 @@ -10,7 +10,7 @@ mod question; pub use file_visibility::FileVisibilityPolicy; -pub use formatting::{nice_directory_display, pretty_format_list_of_paths, strip_cur_dir, to_utf}; +pub use formatting::{nice_directory_display, pretty_format_list_of_paths, strip_cur_dir, to_utf, EscapedPathDisplay}; pub use fs::{ cd_into_same_dir_as, clear_path, create_dir_if_non_existent, is_symlink, remove_file_or_dir, try_infer_extension, }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ouch-0.4.0~0/src/utils/question.rs new/ouch-0.4.1~0/src/utils/question.rs --- old/ouch-0.4.0~0/src/utils/question.rs 2022-11-23 23:04:30.000000000 +0100 +++ new/ouch-0.4.1~0/src/utils/question.rs 2023-01-05 23:15:43.000000000 +0100 @@ -86,7 +86,7 @@ let path = to_utf(strip_cur_dir(path)); let path = Some(&*path); let placeholder = Some("FILE"); - Confirmation::new(&format!("Do you want to {} 'FILE'?", action), placeholder).ask(path) + Confirmation::new(&format!("Do you want to {action} 'FILE'?"), placeholder).ask(path) } } } ++++++ vendor.tar.xz ++++++ /work/SRC/openSUSE:Factory/ouch/vendor.tar.xz /work/SRC/openSUSE:Factory/.ouch.new.1563/vendor.tar.xz differ: char 27, line 1