mirror of
https://github.com/ouch-org/ouch.git
synced 2025-07-18 23:50:35 +00:00
Merge branch 'main' into close-issue-825
This commit is contained in:
commit
1b7389252f
@ -25,10 +25,13 @@ Categories Used:
|
||||
- Merge folders in decompression [\#798](https://github.com/ouch-org/ouch/pull/798) ([tommady](https://github.com/tommady))
|
||||
- Add `--no-smart-unpack` flag to decompression command to disable smart unpack [\#809](https://github.com/ouch-org/ouch/pull/809) ([talis-fb](https://github.com/talis-fb))
|
||||
- Provide Nushell completions (packages still need to install them) [\#827](https://github.com/ouch-org/ouch/pull/827) ([FrancescElies](https://github.com/FrancescElies))
|
||||
- Support `.lz` decompression [\#838](https://github.com/ouch-org/ouch/pull/838) ([zzzsyyy](https://github.com/zzzsyyy))
|
||||
- Support `.lzma` decompression (and fix `.lzma` being a wrong alias for `.xz`) [\#838](https://github.com/ouch-org/ouch/pull/838) ([zzzsyyy](https://github.com/zzzsyyy))
|
||||
|
||||
### Improvements
|
||||
|
||||
- Give better error messages when archive extensions are invalid [\#817](https://github.com/ouch-org/ouch/pull/817) ([marcospb19](https://github.com/marcospb19))
|
||||
- Add aliases for `--password` flag (`--pass` and `--pw`) [\#847](https://github.com/ouch-org/ouch/pull/847) ([marcospb19](https://github.com/marcospb19))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
@ -27,6 +27,10 @@ Before opening the PR, open an issue to discuss your addition, this increases th
|
||||
|
||||
[CHANGELOG.md]: https://github.com/ouch-org/ouch
|
||||
|
||||
### CI Tests
|
||||
|
||||
The CI tests will run for a combination of features, `--no-default-features` will also be tested.
|
||||
|
||||
## Dealing with UI tests
|
||||
|
||||
We use snapshots to do UI testing and guarantee a consistent output, this way, you can catch accidental changes or see what output changed in the PR diff.
|
||||
@ -35,14 +39,16 @@ We use snapshots to do UI testing and guarantee a consistent output, this way, y
|
||||
|
||||
```sh
|
||||
cargo test
|
||||
# Only run UI tests
|
||||
cargo test -- ui
|
||||
# Or, if you only want to run UI tests
|
||||
# cargo test -- ui
|
||||
```
|
||||
|
||||
- If some UI test failed, you should review it:
|
||||
- If some UI test failed, you should review them (requires `cargo install cargo-insta`):
|
||||
|
||||
```sh
|
||||
cargo insta review
|
||||
```
|
||||
|
||||
- After addressing all, you should be able to `git add` and `commit` accordingly.
|
||||
|
||||
NOTE: Sometimes, you'll have to run these two commands multiple times.
|
||||
|
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -926,6 +926,26 @@ dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "liblzma"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0791ab7e08ccc8e0ce893f6906eb2703ed8739d8e89b57c0714e71bad09024c8"
|
||||
dependencies = [
|
||||
"liblzma-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "liblzma-sys"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01b9596486f6d60c3bbe644c0e1be1aa6ccc472ad630fe8927b456973d7cb736"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
@ -995,17 +1015,6 @@ dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lzma-sys"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@ -1115,6 +1124,7 @@ dependencies = [
|
||||
"is_executable",
|
||||
"itertools",
|
||||
"libc",
|
||||
"liblzma",
|
||||
"linked-hash-map",
|
||||
"lz4_flex",
|
||||
"memchr",
|
||||
@ -1134,7 +1144,6 @@ dependencies = [
|
||||
"test-strategy",
|
||||
"time",
|
||||
"unrar",
|
||||
"xz2",
|
||||
"zip",
|
||||
"zstd",
|
||||
]
|
||||
@ -2078,15 +2087,6 @@ dependencies = [
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xz2"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2"
|
||||
dependencies = [
|
||||
"lzma-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
|
@ -41,7 +41,7 @@ tar = "0.4.42"
|
||||
tempfile = "3.10.1"
|
||||
time = { version = "0.3.36", default-features = false }
|
||||
unrar = { version = "0.5.7", optional = true }
|
||||
xz2 = "0.1.7"
|
||||
liblzma = "0.4"
|
||||
zip = { version = "0.6.6", default-features = false, features = [
|
||||
"time",
|
||||
"aes-crypto",
|
||||
|
11
README.md
11
README.md
@ -111,9 +111,9 @@ Output:
|
||||
|
||||
# Supported formats
|
||||
|
||||
| Format | `.tar` | `.zip` | `7z` | `.gz` | `.xz`, `.lzma` | `.bz`, `.bz2` | `.bz3` | `.lz4` | `.sz` (Snappy) | `.zst` | `.rar` | `.br` |
|
||||
|:---------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| Supported | ✓ | ✓¹ | ✓¹ | ✓² | ✓ | ✓ | ✓ | ✓ | ✓² | ✓² | ✓³ | ✓ |
|
||||
| Format | `.tar` | `.zip` | `7z` | `.gz` | `.xz` | `.lzma` | `.lz` | `.bz`, `.bz2` | `.bz3` | `.lz4` | `.sz` (Snappy) | `.zst` | `.rar` | `.br` |
|
||||
|:---------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||
| Supported | ✓ | ✓¹ | ✓¹ | ✓² | ✓ | ✓⁴ | ✓⁴ | ✓ | ✓ | ✓ | ✓² | ✓² | ✓³ | ✓ |
|
||||
|
||||
✓: Supports compression and decompression.
|
||||
|
||||
@ -122,10 +122,13 @@ Output:
|
||||
✓²: Supported, and compression runs in parallel.
|
||||
|
||||
✓³: Due to RAR's restrictive license, only decompression and listing can be supported.
|
||||
|
||||
✓⁴: Only decompression is supported, compression is not implemented yet.
|
||||
|
||||
If you wish to exclude non-free code from your build, you can disable RAR support
|
||||
by building without the `unrar` feature.
|
||||
|
||||
`tar` aliases are also supported: `tgz`, `tbz`, `tbz2`, `tlz4`, `txz`, `tlzma`, `tsz`, `tzst`.
|
||||
`tar` aliases are also supported: `tgz`, `tbz`, `tbz2`, `tlz4`, `txz`, `tlzma`, `tsz`, `tzst`, `tlz`.
|
||||
|
||||
Formats can be chained:
|
||||
|
||||
|
@ -56,8 +56,7 @@ pub fn check_mime_type(
|
||||
.ends_with(detected_format.compression_formats)
|
||||
{
|
||||
warning(format!(
|
||||
"The file extension: `{}` differ from the detected extension: `{}`",
|
||||
outer_ext, detected_format
|
||||
"The file extension: `{outer_ext}` differ from the detected extension: `{detected_format}`"
|
||||
));
|
||||
|
||||
if !user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? {
|
||||
|
@ -5,7 +5,7 @@ use clap::{Parser, ValueHint};
|
||||
// Ouch command line options (docstrings below are part of --help)
|
||||
/// A command-line utility for easily compressing and decompressing files and directories.
|
||||
///
|
||||
/// Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, bz3, lz4, sz (Snappy), zst, rar and br.
|
||||
/// Supported formats: tar, zip, gz, 7z, xz, lzma, lzip, bz/bz2, bz3, lz4, sz (Snappy), zst, rar and br.
|
||||
///
|
||||
/// Repository: https://github.com/ouch-org/ouch
|
||||
#[derive(Parser, Debug, PartialEq)]
|
||||
@ -30,11 +30,11 @@ pub struct CliArgs {
|
||||
pub hidden: bool,
|
||||
|
||||
/// Silence output
|
||||
#[arg(short = 'q', long, global = true)]
|
||||
#[arg(short, long, global = true)]
|
||||
pub quiet: bool,
|
||||
|
||||
/// Ignore files matched by git's ignore files
|
||||
#[arg(short = 'g', long, global = true)]
|
||||
#[arg(short, long, global = true)]
|
||||
pub gitignore: bool,
|
||||
|
||||
/// Specify the format of the archive
|
||||
@ -42,7 +42,7 @@ pub struct CliArgs {
|
||||
pub format: Option<OsString>,
|
||||
|
||||
/// Decompress or list with password
|
||||
#[arg(short = 'p', long = "password", global = true)]
|
||||
#[arg(short, long = "password", aliases = ["pass", "pw"], global = true)]
|
||||
pub password: Option<OsString>,
|
||||
|
||||
/// Concurrent working threads
|
||||
|
@ -68,10 +68,20 @@ pub fn compress_files(
|
||||
)
|
||||
}
|
||||
Lz4 => Box::new(lz4_flex::frame::FrameEncoder::new(encoder).auto_finish()),
|
||||
Lzma => Box::new(xz2::write::XzEncoder::new(
|
||||
Lzma => {
|
||||
return Err(crate::Error::UnsupportedFormat {
|
||||
reason: "LZMA1 compression is not supported in ouch, use .xz instead.".to_string(),
|
||||
})
|
||||
}
|
||||
Xz => Box::new(liblzma::write::XzEncoder::new(
|
||||
encoder,
|
||||
level.map_or(6, |l| (l as u32).clamp(0, 9)),
|
||||
)),
|
||||
Lzip => {
|
||||
return Err(crate::Error::UnsupportedFormat {
|
||||
reason: "Lzip compression is not supported in ouch.".to_string(),
|
||||
})
|
||||
}
|
||||
Snappy => Box::new(
|
||||
gzp::par::compress::ParCompress::<gzp::snap::Snap>::builder()
|
||||
.compression_level(gzp::par::compress::Compression::new(
|
||||
@ -108,7 +118,7 @@ pub fn compress_files(
|
||||
}
|
||||
|
||||
match first_format {
|
||||
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
|
||||
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Xz | Lzip | Snappy | Zstd | Brotli => {
|
||||
writer = chain_writer_encoder(&first_format, writer)?;
|
||||
let mut reader = fs::File::open(&files[0])?;
|
||||
|
||||
|
@ -128,7 +128,15 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
||||
Box::new(bzip3::read::Bz3Decoder::new(decoder)?)
|
||||
}
|
||||
Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)),
|
||||
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
|
||||
Lzma => Box::new(liblzma::read::XzDecoder::new_stream(
|
||||
decoder,
|
||||
liblzma::stream::Stream::new_lzma_decoder(u64::MAX).unwrap(),
|
||||
)),
|
||||
Xz => Box::new(liblzma::read::XzDecoder::new(decoder)),
|
||||
Lzip => Box::new(liblzma::read::XzDecoder::new_stream(
|
||||
decoder,
|
||||
liblzma::stream::Stream::new_lzip_decoder(u64::MAX, 0).unwrap(),
|
||||
)),
|
||||
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
|
||||
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
|
||||
Brotli => Box::new(brotli::Decompressor::new(decoder, BUFFER_CAPACITY)),
|
||||
@ -144,7 +152,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
||||
}
|
||||
|
||||
let files_unpacked = match first_extension {
|
||||
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
|
||||
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Xz | Lzip | Snappy | Zstd | Brotli => {
|
||||
reader = chain_reader_decoder(&first_extension, reader)?;
|
||||
|
||||
let mut writer = match utils::ask_to_create_file(
|
||||
@ -295,7 +303,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
||||
"Successfully decompressed archive in {}",
|
||||
nice_directory_display(options.output_dir)
|
||||
));
|
||||
info_accessible(format!("Files unpacked: {}", files_unpacked));
|
||||
info_accessible(format!("Files unpacked: {files_unpacked}"));
|
||||
|
||||
if !input_is_stdin && options.remove {
|
||||
fs::remove_file(options.input_file_path)?;
|
||||
|
@ -57,7 +57,15 @@ pub fn list_archive_contents(
|
||||
Box::new(bzip3::read::Bz3Decoder::new(decoder).unwrap())
|
||||
}
|
||||
Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)),
|
||||
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
|
||||
Lzma => Box::new(liblzma::read::XzDecoder::new_stream(
|
||||
decoder,
|
||||
liblzma::stream::Stream::new_lzma_decoder(u64::MAX).unwrap(),
|
||||
)),
|
||||
Xz => Box::new(liblzma::read::XzDecoder::new(decoder)),
|
||||
Lzip => Box::new(liblzma::read::XzDecoder::new_stream(
|
||||
decoder,
|
||||
liblzma::stream::Stream::new_lzip_decoder(u64::MAX, 0).unwrap(),
|
||||
)),
|
||||
Snappy => Box::new(snap::read::FrameDecoder::new(decoder)),
|
||||
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
|
||||
Brotli => Box::new(brotli::Decompressor::new(decoder, BUFFER_CAPACITY)),
|
||||
@ -127,7 +135,7 @@ pub fn list_archive_contents(
|
||||
|
||||
Box::new(archive::sevenz::list_archive(io::Cursor::new(vec), password)?)
|
||||
}
|
||||
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
|
||||
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Xz | Lzip | Snappy | Zstd | Brotli => {
|
||||
unreachable!("Not an archive, should be validated before calling this function.");
|
||||
}
|
||||
};
|
||||
|
@ -135,12 +135,12 @@ impl FinalError {
|
||||
///
|
||||
/// This is what it looks like:
|
||||
/// ```
|
||||
/// hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst
|
||||
/// hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
/// hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, lz, sz, zst
|
||||
/// hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
/// ```
|
||||
pub fn hint_all_supported_formats(self) -> Self {
|
||||
self.hint(format!("Supported extensions are: {}", PRETTY_SUPPORTED_EXTENSIONS))
|
||||
.hint(format!("Supported aliases are: {}", PRETTY_SUPPORTED_ALIASES))
|
||||
self.hint(format!("Supported extensions are: {PRETTY_SUPPORTED_EXTENSIONS}"))
|
||||
.hint(format!("Supported aliases are: {PRETTY_SUPPORTED_ALIASES}"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
|
||||
"lz4",
|
||||
"xz",
|
||||
"lzma",
|
||||
"lz",
|
||||
"sz",
|
||||
"zst",
|
||||
#[cfg(feature = "unrar")]
|
||||
@ -27,14 +28,14 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
|
||||
"br",
|
||||
];
|
||||
|
||||
pub const SUPPORTED_ALIASES: &[&str] = &["tgz", "tbz", "tlz4", "txz", "tzlma", "tsz", "tzst"];
|
||||
pub const SUPPORTED_ALIASES: &[&str] = &["tgz", "tbz", "tlz4", "txz", "tlzma", "tsz", "tzst", "tlz"];
|
||||
|
||||
#[cfg(not(feature = "unrar"))]
|
||||
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z";
|
||||
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, 7z";
|
||||
#[cfg(feature = "unrar")]
|
||||
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z";
|
||||
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, rar, 7z";
|
||||
|
||||
pub const PRETTY_SUPPORTED_ALIASES: &str = "tgz, tbz, tlz4, txz, tzlma, tsz, tzst";
|
||||
pub const PRETTY_SUPPORTED_ALIASES: &str = "tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz";
|
||||
|
||||
/// A wrapper around `CompressionFormat` that allows combinations like `tgz`
|
||||
#[derive(Debug, Clone)]
|
||||
@ -85,8 +86,12 @@ pub enum CompressionFormat {
|
||||
Bzip3,
|
||||
/// .lz4
|
||||
Lz4,
|
||||
/// .xz .lzma
|
||||
/// .xz
|
||||
Xz,
|
||||
/// .lzma
|
||||
Lzma,
|
||||
/// .lzip
|
||||
Lzip,
|
||||
/// .sz
|
||||
Snappy,
|
||||
/// tar, tgz, tbz, tbz2, tbz3, txz, tlz4, tlzma, tsz, tzst
|
||||
@ -95,7 +100,6 @@ pub enum CompressionFormat {
|
||||
Zstd,
|
||||
/// .zip
|
||||
Zip,
|
||||
// even if built without RAR support, we still want to recognise the format
|
||||
/// .rar
|
||||
Rar,
|
||||
/// .7z
|
||||
@ -105,19 +109,11 @@ pub enum CompressionFormat {
|
||||
}
|
||||
|
||||
impl CompressionFormat {
|
||||
/// Currently supported archive formats are .tar (and aliases to it) and .zip
|
||||
pub fn archive_format(&self) -> bool {
|
||||
// Keep this match like that without a wildcard `_` so we don't forget to update it
|
||||
// Keep this match without a wildcard `_` so we never forget to update it
|
||||
match self {
|
||||
Tar | Zip | Rar | SevenZip => true,
|
||||
Gzip => false,
|
||||
Bzip => false,
|
||||
Bzip3 => false,
|
||||
Lz4 => false,
|
||||
Lzma => false,
|
||||
Snappy => false,
|
||||
Zstd => false,
|
||||
Brotli => false,
|
||||
Bzip | Bzip3 | Lz4 | Lzma | Xz | Lzip | Snappy | Zstd | Brotli | Gzip => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,7 +126,9 @@ fn to_extension(ext: &[u8]) -> Option<Extension> {
|
||||
b"tbz" | b"tbz2" => &[Tar, Bzip],
|
||||
b"tbz3" => &[Tar, Bzip3],
|
||||
b"tlz4" => &[Tar, Lz4],
|
||||
b"txz" | b"tlzma" => &[Tar, Lzma],
|
||||
b"txz" => &[Tar, Xz],
|
||||
b"tlzma" => &[Tar, Lzma],
|
||||
b"tlz" => &[Tar, Lzip],
|
||||
b"tsz" => &[Tar, Snappy],
|
||||
b"tzst" => &[Tar, Zstd],
|
||||
b"zip" => &[Zip],
|
||||
@ -138,7 +136,9 @@ fn to_extension(ext: &[u8]) -> Option<Extension> {
|
||||
b"bz3" => &[Bzip3],
|
||||
b"gz" => &[Gzip],
|
||||
b"lz4" => &[Lz4],
|
||||
b"xz" | b"lzma" => &[Lzma],
|
||||
b"xz" => &[Xz],
|
||||
b"lzma" => &[Lzma],
|
||||
b"lz" => &[Lzip],
|
||||
b"sz" => &[Snappy],
|
||||
b"zst" => &[Zstd],
|
||||
b"rar" => &[Rar],
|
||||
@ -173,7 +173,7 @@ pub fn parse_format_flag(input: &OsStr) -> crate::Result<Vec<Extension>> {
|
||||
.map(|extension| {
|
||||
to_extension(extension.as_bytes()).ok_or_else(|| Error::InvalidFormatFlag {
|
||||
text: input.to_owned(),
|
||||
reason: format!("Unsupported extension '{}'", extension),
|
||||
reason: format!("Unsupported extension '{extension}'"),
|
||||
})
|
||||
})
|
||||
.collect::<crate::Result<_>>()?;
|
||||
|
@ -109,7 +109,7 @@ impl std::fmt::Display for Bytes {
|
||||
|
||||
debug_assert!(num >= 0.0);
|
||||
if num < 1_f64 {
|
||||
return write!(f, "{:>6.2} B", num);
|
||||
return write!(f, "{num:>6.2} B");
|
||||
}
|
||||
|
||||
let delimiter = 1000_f64;
|
||||
|
@ -82,7 +82,7 @@ pub fn rename_or_increment_filename(path: &Path) -> PathBuf {
|
||||
let number = number_str.parse::<u32>().unwrap_or(0);
|
||||
format!("{}_{}", base, number + 1)
|
||||
}
|
||||
_ => format!("{}_1", filename),
|
||||
_ => format!("{filename}_1"),
|
||||
};
|
||||
|
||||
let mut new_path = parent.join(new_filename);
|
||||
@ -135,9 +135,15 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
|
||||
fn is_bz3(buf: &[u8]) -> bool {
|
||||
buf.starts_with(b"BZ3v1")
|
||||
}
|
||||
fn is_lzma(buf: &[u8]) -> bool {
|
||||
buf.len() >= 14 && buf[0] == 0x5d && (buf[12] == 0x00 || buf[12] == 0xff) && buf[13] == 0x00
|
||||
}
|
||||
fn is_xz(buf: &[u8]) -> bool {
|
||||
buf.starts_with(&[0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00])
|
||||
}
|
||||
fn is_lzip(buf: &[u8]) -> bool {
|
||||
buf.starts_with(&[0x4C, 0x5A, 0x49, 0x50])
|
||||
}
|
||||
fn is_lz4(buf: &[u8]) -> bool {
|
||||
buf.starts_with(&[0x04, 0x22, 0x4D, 0x18])
|
||||
}
|
||||
@ -183,8 +189,12 @@ pub fn try_infer_extension(path: &Path) -> Option<Extension> {
|
||||
Some(Extension::new(&[Bzip], "bz2"))
|
||||
} else if is_bz3(&buf) {
|
||||
Some(Extension::new(&[Bzip3], "bz3"))
|
||||
} else if is_lzma(&buf) {
|
||||
Some(Extension::new(&[Lzma], "lzma"))
|
||||
} else if is_xz(&buf) {
|
||||
Some(Extension::new(&[Lzma], "xz"))
|
||||
Some(Extension::new(&[Xz], "xz"))
|
||||
} else if is_lzip(&buf) {
|
||||
Some(Extension::new(&[Lzip], "lzip"))
|
||||
} else if is_lz4(&buf) {
|
||||
Some(Extension::new(&[Lz4], "lz4"))
|
||||
} else if is_sz(&buf) {
|
||||
|
@ -187,7 +187,7 @@ impl<'a, T: Default> ChoicePrompt<'a, T> {
|
||||
|
||||
#[cfg(not(feature = "allow_piped_choice"))]
|
||||
if !stdin().is_terminal() {
|
||||
eprintln!("{}", message);
|
||||
eprintln!("{message}");
|
||||
eprintln!("Pass --yes to proceed");
|
||||
return Ok(T::default());
|
||||
}
|
||||
@ -222,10 +222,10 @@ impl<'a, T: Default> ChoicePrompt<'a, T> {
|
||||
.collect::<Vec<_>>()
|
||||
.join("/");
|
||||
|
||||
format!("[{}]", choises)
|
||||
format!("[{choises}]")
|
||||
};
|
||||
|
||||
eprintln!("{} {}", message, choice_prompt);
|
||||
eprintln!("{message} {choice_prompt}");
|
||||
|
||||
let mut answer = String::new();
|
||||
let bytes_read = stdin_lock.read_line(&mut answer)?;
|
||||
@ -284,7 +284,7 @@ impl<'a> Confirmation<'a> {
|
||||
|
||||
#[cfg(not(feature = "allow_piped_choice"))]
|
||||
if !stdin().is_terminal() {
|
||||
eprintln!("{}", message);
|
||||
eprintln!("{message}");
|
||||
eprintln!("Pass --yes to proceed");
|
||||
return Ok(false);
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ enum DirectoryExtension {
|
||||
Tbz3,
|
||||
Tgz,
|
||||
Tlz4,
|
||||
Tlzma,
|
||||
Tsz,
|
||||
Txz,
|
||||
Tzst,
|
||||
@ -50,7 +49,6 @@ enum FileExtension {
|
||||
Bz3,
|
||||
Gz,
|
||||
Lz4,
|
||||
Lzma,
|
||||
Sz,
|
||||
Xz,
|
||||
Zst,
|
||||
@ -175,7 +173,7 @@ fn single_file_stdin(
|
||||
fs::create_dir(before).unwrap();
|
||||
let before_file = &before.join("file");
|
||||
let format = merge_extensions(&ext, &exts);
|
||||
let archive = &dir.join(format!("file.{}", format));
|
||||
let archive = &dir.join(format!("file.{format}"));
|
||||
let after = &dir.join("after");
|
||||
write_random_content(
|
||||
&mut fs::File::create(before_file).unwrap(),
|
||||
|
@ -17,8 +17,7 @@ fn sanity_check_through_mime() {
|
||||
write_random_content(test_file, &mut SmallRng::from_entropy());
|
||||
|
||||
let formats = [
|
||||
"7z", "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma",
|
||||
"tar.xz", "tar.zst",
|
||||
"7z", "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tzst", "tar.bz", "tar.bz2", "tar.xz", "tar.zst",
|
||||
];
|
||||
|
||||
let expected_mimes = [
|
||||
@ -30,12 +29,10 @@ fn sanity_check_through_mime() {
|
||||
"application/x-bzip2",
|
||||
"application/x-bzip2",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/zstd",
|
||||
"application/x-bzip2",
|
||||
"application/x-bzip2",
|
||||
"application/x-xz",
|
||||
"application/x-xz",
|
||||
"application/zstd",
|
||||
];
|
||||
|
||||
|
@ -6,8 +6,8 @@ expression: "run_ouch(\"ouch decompress a\", dir)"
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
||||
hint: ouch decompress <TMP_DIR>/a --format tar.gz
|
||||
|
@ -7,5 +7,5 @@ expression: "run_ouch(\"ouch decompress a b.unknown\", dir)"
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
|
@ -6,8 +6,8 @@ expression: "run_ouch(\"ouch decompress b.unknown\", dir)"
|
||||
- Files with unsupported extensions: <TMP_DIR>/b.unknown
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
||||
hint: ouch decompress <TMP_DIR>/b.unknown --format tar.gz
|
||||
|
@ -6,8 +6,8 @@ expression: "run_ouch(\"ouch decompress a\", dir)"
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
||||
hint: ouch decompress <TMP_DIR>/a --format tar.gz
|
||||
|
@ -7,5 +7,5 @@ expression: "run_ouch(\"ouch decompress a b.unknown\", dir)"
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
|
@ -6,8 +6,8 @@ expression: "run_ouch(\"ouch decompress b.unknown\", dir)"
|
||||
- Files with unsupported extensions: <TMP_DIR>/b.unknown
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
||||
hint: ouch decompress <TMP_DIR>/b.unknown --format tar.gz
|
||||
|
@ -5,8 +5,8 @@ expression: "run_ouch(\"ouch compress input output --format tar.gz.unknown\", di
|
||||
[ERROR] Failed to parse `--format tar.gz.unknown`
|
||||
- Unsupported extension 'unknown'
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Examples:
|
||||
hint: --format tar
|
||||
|
@ -5,8 +5,8 @@ expression: "run_ouch(\"ouch compress input output --format targz\", dir)"
|
||||
[ERROR] Failed to parse `--format targz`
|
||||
- Unsupported extension 'targz'
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Examples:
|
||||
hint: --format tar
|
||||
|
@ -5,8 +5,8 @@ expression: "run_ouch(\"ouch compress input output --format .tar.$#!@.rest\", di
|
||||
[ERROR] Failed to parse `--format .tar.$#!@.rest`
|
||||
- Unsupported extension '$#!@'
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Examples:
|
||||
hint: --format tar
|
||||
|
@ -5,8 +5,8 @@ expression: "run_ouch(\"ouch compress input output --format tar.gz.unknown\", di
|
||||
[ERROR] Failed to parse `--format tar.gz.unknown`
|
||||
- Unsupported extension 'unknown'
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Examples:
|
||||
hint: --format tar
|
||||
|
@ -5,8 +5,8 @@ expression: "run_ouch(\"ouch compress input output --format targz\", dir)"
|
||||
[ERROR] Failed to parse `--format targz`
|
||||
- Unsupported extension 'targz'
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Examples:
|
||||
hint: --format tar
|
||||
|
@ -5,8 +5,8 @@ expression: "run_ouch(\"ouch compress input output --format .tar.$#!@.rest\", di
|
||||
[ERROR] Failed to parse `--format .tar.$#!@.rest`
|
||||
- Unsupported extension '$#!@'
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, bz3, gz, lz4, xz, lzma, lz, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tlzma, tsz, tzst, tlz
|
||||
hint:
|
||||
hint: Examples:
|
||||
hint: --format tar
|
||||
|
@ -5,7 +5,7 @@ snapshot_kind: text
|
||||
---
|
||||
A command-line utility for easily compressing and decompressing files and directories.
|
||||
|
||||
Supported formats: tar, zip, gz, 7z, xz/lzma, bz/bz2, bz3, lz4, sz (Snappy), zst, rar and br.
|
||||
Supported formats: tar, zip, gz, 7z, xz, lzma, lzip, bz/bz2, bz3, lz4, sz (Snappy), zst, rar and br.
|
||||
|
||||
Repository: https://github.com/ouch-org/ouch
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user