Add support for Zstd

This commit is contained in:
Vinícius Rodrigues Miguel 2021-10-05 23:56:09 -03:00
parent 3f718b8335
commit e9bc65a787
5 changed files with 62 additions and 7 deletions

42
Cargo.lock generated
View File

@ -63,6 +63,9 @@ name = "cc"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
@ -124,6 +127,15 @@ dependencies = [
"libc",
]
[[package]]
name = "jobserver"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
dependencies = [
"libc",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -184,6 +196,7 @@ dependencies = [
"walkdir",
"xz2",
"zip",
"zstd",
]
[[package]]
@ -434,3 +447,32 @@ dependencies = [
"flate2",
"thiserror",
]
[[package]]
name = "zstd"
version = "0.9.0+zstd.1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "4.1.1+zstd.1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079"
dependencies = [
"libc",
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "1.6.1+zstd.1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33"
dependencies = [
"cc",
"libc",
]

View File

@ -23,6 +23,7 @@ tar = "0.4.37"
xz2 = "0.1.6"
zip = { version = "0.5.13", default-features = false, features = ["deflate-miniz"] }
flate2 = { version = "1.0.22", default-features = false, features = ["zlib"] }
zstd = "0.9.0+zstd.1.5.0"
[dev-dependencies]
tempfile = "3.2.0"

View File

@ -170,6 +170,13 @@ fn compress_files(
Gzip => Box::new(flate2::write::GzEncoder::new(encoder, Default::default())),
Bzip => Box::new(bzip2::write::BzEncoder::new(encoder, Default::default())),
Lzma => Box::new(xz2::write::XzEncoder::new(encoder, 6)),
Zstd => {
let zstd_encoder = zstd::stream::write::Encoder::new(encoder, Default::default());
// Safety:
// Encoder::new() can only fail if `level` is invalid, but Default::default()
// is guaranteed to be valid
Box::new(zstd_encoder.unwrap().auto_finish())
}
_ => unreachable!(),
};
encoder
@ -180,7 +187,7 @@ fn compress_files(
}
match formats[0] {
Gzip | Bzip | Lzma => {
Gzip | Bzip | Lzma | Zstd => {
writer = chain_writer_encoder(&formats[0], writer);
let mut reader = fs::File::open(&files[0]).unwrap();
io::copy(&mut reader, &mut writer)?;
@ -251,23 +258,24 @@ fn decompress_file(
let mut reader: Box<dyn Read> = Box::new(reader);
// Grab previous decoder and wrap it inside of a new one
let chain_reader_decoder = |format: &CompressionFormat, decoder: Box<dyn Read>| {
let chain_reader_decoder = |format: &CompressionFormat, decoder: Box<dyn Read>| -> crate::Result<Box<dyn Read>> {
let decoder: Box<dyn Read> = match format {
Gzip => Box::new(flate2::read::GzDecoder::new(decoder)),
Bzip => Box::new(bzip2::read::BzDecoder::new(decoder)),
Lzma => Box::new(xz2::read::XzDecoder::new(decoder)),
Zstd => Box::new(zstd::stream::Decoder::new(decoder)?),
_ => unreachable!(),
};
decoder
Ok(decoder)
};
for format in formats.iter().skip(1).rev() {
reader = chain_reader_decoder(format, reader);
reader = chain_reader_decoder(format, reader)?;
}
match formats[0] {
Gzip | Bzip | Lzma => {
reader = chain_reader_decoder(&formats[0], reader);
Gzip | Bzip | Lzma | Zstd => {
reader = chain_reader_decoder(&formats[0], reader)?;
// TODO: improve error treatment
let mut writer = fs::File::create(&output_path)?;

View File

@ -11,6 +11,7 @@ pub enum CompressionFormat {
Bzip, // .bz
Lzma, // .lzma
Tar, // .tar (technically not a compression extension, but will do for now)
Zstd, // .zst
Zip, // .zip
}
@ -22,6 +23,7 @@ impl fmt::Display for CompressionFormat {
match self {
Gzip => ".gz",
Bzip => ".bz",
Zstd => ".zst",
Lzma => ".lz",
Tar => ".tar",
Zip => ".zip",
@ -49,6 +51,7 @@ pub fn separate_known_extensions_from_name(mut path: &Path) -> (&Path, Vec<Compr
_ if extension == "bz" => Bzip,
_ if extension == "gz" || extension == "bz2" => Gzip,
_ if extension == "xz" || extension == "lzma" || extension == "lz" => Lzma,
_ if extension == "zst" => Zstd,
_ => break,
};

View File

@ -21,6 +21,7 @@ fn test_each_format() {
test_compressing_and_decompressing_archive("tar.xz");
test_compressing_and_decompressing_archive("tar.lz");
test_compressing_and_decompressing_archive("tar.lzma");
test_compressing_and_decompressing_archive("tar.zst");
test_compressing_and_decompressing_archive("zip");
test_compressing_and_decompressing_archive("zip.gz");
test_compressing_and_decompressing_archive("zip.bz");
@ -31,7 +32,7 @@ fn test_each_format() {
// Why not
test_compressing_and_decompressing_archive(
"tar.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.lz.lz.lz.lz.lz.lz.lz.lz.lz.lz.bz.bz.bz.bz.bz.bz.bz",
"tar.gz.gz.gz.gz.gz.gz.gz.gz.zst.gz.gz.gz.gz.gz.gz.gz.gz.gz.gz.lz.lz.lz.lz.lz.lz.lz.lz.lz.lz.bz.bz.bz.bz.bz.bz.bz",
);
}