Merge pull request #150 from figsoda/lz4

Add support for lz4
This commit is contained in:
João Marcos Bezerra 2021-11-02 18:45:53 -03:00 committed by GitHub
commit a1c4f0373f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 12 deletions

26
Cargo.lock generated
View File

@ -255,6 +255,15 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lz4_flex"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177c079243f6867429aca5af5053747f57e329d44f0c58bebca078cd14873ec2"
dependencies = [
"twox-hash",
]
[[package]] [[package]]
name = "lzma-sys" name = "lzma-sys"
version = "0.1.17" version = "0.1.17"
@ -310,6 +319,7 @@ dependencies = [
"infer", "infer",
"libc", "libc",
"linked-hash-map", "linked-hash-map",
"lz4_flex",
"once_cell", "once_cell",
"rand", "rand",
"tar", "tar",
@ -441,6 +451,12 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
@ -521,6 +537,16 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "twox-hash"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f559b464de2e2bdabcac6a210d12e9b5a5973c251e102c44c585c71d51bd78e"
dependencies = [
"cfg-if",
"static_assertions",
]
[[package]] [[package]]
name = "unicase" name = "unicase"
version = "2.6.0" version = "2.6.0"

View File

@ -21,6 +21,7 @@ walkdir = "2.3.2"
bzip2 = "0.4.3" bzip2 = "0.4.3"
libc = "0.2.103" libc = "0.2.103"
tar = "0.4.37" tar = "0.4.37"
lz4_flex = "0.9.0"
xz2 = "0.1.6" xz2 = "0.1.6"
zip = { version = "0.5.13", default-features = false, features = ["deflate-miniz"] } zip = { version = "0.5.13", default-features = false, features = ["deflate-miniz"] }
flate2 = { version = "1.0.22", default-features = false, features = ["zlib"] } flate2 = { version = "1.0.22", default-features = false, features = ["zlib"] }

View File

@ -82,11 +82,11 @@ For compiling, check the [wiki guide](https://github.com/ouch-org/ouch/wiki/Comp
## Supported formats ## Supported formats
| Format | .tar | .zip | .bz, .bz2 | .gz | .xz, .lz, .lzma | .zst | | Format | .tar | .zip | .bz, .bz2 | .gz | .lz4 | .xz, .lz, .lzma | .zst |
|:-------------:|:----:|:----:|:---------:| --- |:---------------:| --- | |:-------------:|:----:|:----:|:---------:|:---:|:----:|:---------------:|:----:|
| Supported | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Supported | ✓ | ✓ | ✓ | ✓ | | | ✓ |
And the aliases: `tgz`, `tbz`, `tbz2`, `txz`, `tlz`, `tlzma`, `tzst`. And the aliases: `tgz`, `tbz`, `tbz2`, `tlz4`, `txz`, `tlz`, `tlzma`, `tzst`.
Formats can be chained (`ouch` keeps it _fast_): Formats can be chained (`ouch` keeps it _fast_):

View File

@ -270,6 +270,7 @@ fn compress_files(files: Vec<PathBuf>, formats: Vec<Extension>, output_file: fs:
let encoder: Box<dyn Write> = match format { let encoder: Box<dyn Write> = match format {
Gzip => Box::new(flate2::write::GzEncoder::new(encoder, Default::default())), Gzip => Box::new(flate2::write::GzEncoder::new(encoder, Default::default())),
Bzip => Box::new(bzip2::write::BzEncoder::new(encoder, Default::default())), Bzip => Box::new(bzip2::write::BzEncoder::new(encoder, Default::default())),
Lz4 => Box::new(lz4_flex::frame::FrameEncoder::new(encoder)),
Lzma => Box::new(xz2::write::XzEncoder::new(encoder, 6)), Lzma => Box::new(xz2::write::XzEncoder::new(encoder, 6)),
Zstd => { Zstd => {
let zstd_encoder = zstd::stream::write::Encoder::new(encoder, Default::default()); let zstd_encoder = zstd::stream::write::Encoder::new(encoder, Default::default());
@ -278,7 +279,7 @@ fn compress_files(files: Vec<PathBuf>, formats: Vec<Extension>, output_file: fs:
// is guaranteed to be valid // is guaranteed to be valid
Box::new(zstd_encoder.unwrap().auto_finish()) Box::new(zstd_encoder.unwrap().auto_finish())
} }
_ => unreachable!(), Tar | Zip => unreachable!(),
}; };
encoder encoder
}; };
@ -288,7 +289,7 @@ fn compress_files(files: Vec<PathBuf>, formats: Vec<Extension>, output_file: fs:
} }
match formats[0].compression_formats[0] { match formats[0].compression_formats[0] {
Gzip | Bzip | Lzma | Zstd => { Gzip | Bzip | Lz4 | Lzma | Zstd => {
writer = chain_writer_encoder(&formats[0].compression_formats[0], writer); writer = chain_writer_encoder(&formats[0].compression_formats[0], writer);
let mut reader = fs::File::open(&files[0]).unwrap(); let mut reader = fs::File::open(&files[0]).unwrap();
io::copy(&mut reader, &mut writer)?; io::copy(&mut reader, &mut writer)?;
@ -364,9 +365,10 @@ fn decompress_file(
let decoder: Box<dyn Read> = match format { let decoder: Box<dyn Read> = match format {
Gzip => Box::new(flate2::read::GzDecoder::new(decoder)), Gzip => Box::new(flate2::read::GzDecoder::new(decoder)),
Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)), Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)),
Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)),
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)), Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?), Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
_ => unreachable!(), Tar | Zip => unreachable!(),
}; };
Ok(decoder) Ok(decoder)
}; };
@ -380,7 +382,7 @@ fn decompress_file(
let files_unpacked; let files_unpacked;
match formats[0].compression_formats[0] { match formats[0].compression_formats[0] {
Gzip | Bzip | Lzma | Zstd => { Gzip | Bzip | Lz4 | Lzma | Zstd => {
reader = chain_reader_decoder(&formats[0].compression_formats[0], reader)?; reader = chain_reader_decoder(&formats[0].compression_formats[0], reader)?;
let writer = utils::create_or_ask_overwrite(&output_path, question_policy)?; let writer = utils::create_or_ask_overwrite(&output_path, question_policy)?;
@ -451,9 +453,10 @@ fn list_archive_contents(
let decoder: Box<dyn Read> = match format { let decoder: Box<dyn Read> = match format {
Gzip => Box::new(flate2::read::GzDecoder::new(decoder)), Gzip => Box::new(flate2::read::GzDecoder::new(decoder)),
Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)), Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)),
Lz4 => Box::new(lz4_flex::frame::FrameDecoder::new(decoder)),
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)), Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?), Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
_ => unreachable!(), Tar | Zip => unreachable!(),
}; };
Ok(decoder) Ok(decoder)
}; };
@ -476,7 +479,7 @@ fn list_archive_contents(
crate::archive::zip::list_archive(zip_archive)? crate::archive::zip::list_archive(zip_archive)?
} }
Gzip | Bzip | Lzma | Zstd => { Gzip | Bzip | Lz4 | Lzma | Zstd => {
panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!"); panic!("Not an archive! This should never happen, if it does, something is wrong with `CompressionFormat::is_archive()`. Please report this error!");
} }
}; };

View File

@ -47,9 +47,11 @@ pub enum CompressionFormat {
Gzip, Gzip,
/// .bz .bz2 /// .bz .bz2
Bzip, Bzip,
/// .lz4
Lz4,
/// .xz .lzma .lz /// .xz .lzma .lz
Lzma, Lzma,
/// tar, tgz, tbz, tbz2, txz, tlz, tlzma, tzst /// tar, tgz, tbz, tbz2, txz, tlz, tlz4, tlzma, tzst
Tar, Tar,
/// .zst /// .zst
Zstd, Zstd,
@ -65,6 +67,7 @@ impl CompressionFormat {
Tar | Zip => true, Tar | Zip => true,
Gzip => false, Gzip => false,
Bzip => false, Bzip => false,
Lz4 => false,
Lzma => false, Lzma => false,
Zstd => false, Zstd => false,
} }
@ -80,6 +83,7 @@ impl fmt::Display for CompressionFormat {
Gzip => ".gz", Gzip => ".gz",
Bzip => ".bz", Bzip => ".bz",
Zstd => ".zst", Zstd => ".zst",
Lz4 => ".lz4",
Lzma => ".lz", Lzma => ".lz",
Tar => ".tar", Tar => ".tar",
Zip => ".zip", Zip => ".zip",
@ -110,11 +114,13 @@ pub fn separate_known_extensions_from_name(mut path: &Path) -> (&Path, Vec<Exten
"tar" => Extension::new([Tar], extension), "tar" => Extension::new([Tar], extension),
"tgz" => Extension::new([Tar, Gzip], extension), "tgz" => Extension::new([Tar, Gzip], extension),
"tbz" | "tbz2" => Extension::new([Tar, Bzip], extension), "tbz" | "tbz2" => Extension::new([Tar, Bzip], extension),
"tlz4" => Extension::new([Tar, Lz4], extension),
"txz" | "tlz" | "tlzma" => Extension::new([Tar, Lzma], extension), "txz" | "tlz" | "tlzma" => Extension::new([Tar, Lzma], extension),
"tzst" => Extension::new([Tar, Zstd], ".tzst"), "tzst" => Extension::new([Tar, Zstd], ".tzst"),
"zip" => Extension::new([Zip], extension), "zip" => Extension::new([Zip], extension),
"bz" | "bz2" => Extension::new([Bzip], extension), "bz" | "bz2" => Extension::new([Bzip], extension),
"gz" => Extension::new([Gzip], extension), "gz" => Extension::new([Gzip], extension),
"lz4" => Extension::new([Lz4], extension),
"xz" | "lzma" | "lz" => Extension::new([Lzma], extension), "xz" | "lzma" | "lz" => Extension::new([Lzma], extension),
"zst" => Extension::new([Zstd], extension), "zst" => Extension::new([Zstd], extension),
_ => break, _ => break,
@ -144,7 +150,7 @@ mod tests {
use CompressionFormat::*; use CompressionFormat::*;
let path = Path::new("bolovo.tar.gz"); let path = Path::new("bolovo.tar.gz");
let extensions: Vec<Extension> = extensions_from_path(&path); let extensions: Vec<Extension> = extensions_from_path(path);
let formats: Vec<&CompressionFormat> = extensions.iter().flat_map(Extension::iter).collect::<Vec<_>>(); let formats: Vec<&CompressionFormat> = extensions.iter().flat_map(Extension::iter).collect::<Vec<_>>();
assert_eq!(formats, vec![&Tar, &Gzip]); assert_eq!(formats, vec![&Tar, &Gzip]);

View File

@ -76,12 +76,14 @@ fn test_each_format() {
test_compressing_and_decompressing_archive("tar.bz2"); test_compressing_and_decompressing_archive("tar.bz2");
test_compressing_and_decompressing_archive("tar.xz"); test_compressing_and_decompressing_archive("tar.xz");
test_compressing_and_decompressing_archive("tar.lz"); test_compressing_and_decompressing_archive("tar.lz");
test_compressing_and_decompressing_archive("tar.lz4");
test_compressing_and_decompressing_archive("tar.lzma"); test_compressing_and_decompressing_archive("tar.lzma");
test_compressing_and_decompressing_archive("tar.zst"); test_compressing_and_decompressing_archive("tar.zst");
test_compressing_and_decompressing_archive("tgz"); test_compressing_and_decompressing_archive("tgz");
test_compressing_and_decompressing_archive("tbz"); test_compressing_and_decompressing_archive("tbz");
test_compressing_and_decompressing_archive("tbz2"); test_compressing_and_decompressing_archive("tbz2");
test_compressing_and_decompressing_archive("txz"); test_compressing_and_decompressing_archive("txz");
test_compressing_and_decompressing_archive("tlz4");
test_compressing_and_decompressing_archive("tlz"); test_compressing_and_decompressing_archive("tlz");
test_compressing_and_decompressing_archive("tlzma"); test_compressing_and_decompressing_archive("tlzma");
test_compressing_and_decompressing_archive("tzst"); test_compressing_and_decompressing_archive("tzst");