From 340827de1f4944c99ed0411f382fb388ae9304f7 Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Thu, 21 Oct 2021 19:17:14 +0300 Subject: [PATCH 1/5] Introduce `is_archive_format` method on `CompressionFormat` --- src/extension.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/extension.rs b/src/extension.rs index b1828f0..87efbc6 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -19,6 +19,12 @@ pub enum CompressionFormat { Zip, // .zip } +impl CompressionFormat { + pub fn is_archive_format(&self) -> bool { + matches!(self, Tar | Tgz | Tbz | Tlzma | Tzst | Zstd | Zip) + } +} + impl fmt::Display for CompressionFormat { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( From 0f3bc4f444f66c993802d04a877b9c3f3b315ddd Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:04:08 +0300 Subject: [PATCH 2/5] Use the new method were applicable --- src/commands.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 6d41347..d98d297 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -56,7 +56,9 @@ pub fn run(args: Opts, skip_questions_positively: Option) -> crate::Result return Err(Error::with_reason(reason)); } - if matches!(&formats[0], Bzip | Gzip | Lzma) && represents_several_files(&files) { + if !formats.get(0).map(CompressionFormat::is_archive_format).unwrap_or(false) + && represents_several_files(&files) + { // This piece of code creates a suggestion for compressing multiple files // It says: // Change from file.bz.xz @@ -84,7 +86,7 @@ pub fn run(args: Opts, skip_questions_positively: Option) -> crate::Result return Err(Error::with_reason(reason)); } - if let Some(format) = formats.iter().skip(1).find(|format| matches!(format, Tar | Zip)) { + if let Some(format) = formats.iter().skip(1).find(|format| format.is_archive_format()) { let reason = 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)) From 91a1054c3c8f6c2f42b0ea0fb811a54835c73837 Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:05:38 +0300 Subject: [PATCH 3/5] Remove duplicated if/else branches --- src/commands.rs | 142 +++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 81 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index d98d297..2a627dd 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -188,94 +188,74 @@ pub fn run(args: Opts, skip_questions_positively: Option) -> crate::Result fn compress_files(files: Vec, formats: Vec, output_file: fs::File) -> crate::Result<()> { let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file); - if let [Tar | Tgz | Zip] = *formats.as_slice() { - match formats[0] { - Tar => { - let mut bufwriter = archive::tar::build_archive_from_paths(&files, file_writer)?; - bufwriter.flush()?; - } - Tgz => { - // Wrap it into an gz_decoder, and pass to the tar archive builder - let gz_decoder = flate2::write::GzEncoder::new(file_writer, Default::default()); - let mut bufwriter = archive::tar::build_archive_from_paths(&files, gz_decoder)?; - bufwriter.flush()?; - } - Zip => { - let mut bufwriter = archive::zip::build_archive_from_paths(&files, file_writer)?; - bufwriter.flush()?; + let mut writer: Box = Box::new(file_writer); + + // Grab previous encoder and wrap it inside of a new one + let chain_writer_encoder = |format: &CompressionFormat, encoder: Box| { + let encoder: Box = match format { + 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!(), }; - } else { - let mut writer: Box = Box::new(file_writer); + encoder + }; - // Grab previous encoder and wrap it inside of a new one - let chain_writer_encoder = |format: &CompressionFormat, encoder: Box| { - let encoder: Box = match format { - 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 - }; + for format in formats.iter().skip(1).rev() { + writer = chain_writer_encoder(format, writer); + } - for format in formats.iter().skip(1).rev() { - writer = chain_writer_encoder(format, writer); + match formats[0] { + 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)?; } + Tar => { + let mut writer = archive::tar::build_archive_from_paths(&files, writer)?; + writer.flush()?; + } + Tgz => { + let encoder = flate2::write::GzEncoder::new(writer, Default::default()); + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Tbz => { + let encoder = bzip2::write::BzEncoder::new(writer, Default::default()); + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Tlzma => { + let encoder = xz2::write::XzEncoder::new(writer, 6); + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Tzst => { + let encoder = zstd::stream::write::Encoder::new(writer, Default::default())?; + let writer = archive::tar::build_archive_from_paths(&files, encoder)?; + writer.finish()?.flush()?; + } + Zip => { + eprintln!("{yellow}Warning:{reset}", yellow = *colors::YELLOW, reset = *colors::RESET); + eprintln!("\tCompressing .zip entirely in memory."); + eprintln!("\tIf the file is too big, your PC might freeze!"); + eprintln!( + "\tThis is a limitation for formats like '{}'.", + formats.iter().map(|format| format.to_string()).collect::() + ); + eprintln!("\tThe design of .zip makes it impossible to compress via stream."); - match formats[0] { - 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)?; - } - Tar => { - let mut writer = archive::tar::build_archive_from_paths(&files, writer)?; - writer.flush()?; - } - Tgz => { - let encoder = flate2::write::GzEncoder::new(writer, Default::default()); - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Tbz => { - let encoder = bzip2::write::BzEncoder::new(writer, Default::default()); - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Tlzma => { - let encoder = xz2::write::XzEncoder::new(writer, 6); - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Tzst => { - let encoder = zstd::stream::write::Encoder::new(writer, Default::default())?; - let writer = archive::tar::build_archive_from_paths(&files, encoder)?; - writer.finish()?.flush()?; - } - Zip => { - eprintln!("{yellow}Warning:{reset}", yellow = *colors::YELLOW, reset = *colors::RESET); - eprintln!("\tCompressing .zip entirely in memory."); - eprintln!("\tIf the file is too big, your PC might freeze!"); - eprintln!( - "\tThis is a limitation for formats like '{}'.", - formats.iter().map(|format| format.to_string()).collect::() - ); - eprintln!("\tThe design of .zip makes it impossible to compress via stream."); - - let mut vec_buffer = io::Cursor::new(vec![]); - archive::zip::build_archive_from_paths(&files, &mut vec_buffer)?; - let vec_buffer = vec_buffer.into_inner(); - io::copy(&mut vec_buffer.as_slice(), &mut writer)?; - } + let mut vec_buffer = io::Cursor::new(vec![]); + archive::zip::build_archive_from_paths(&files, &mut vec_buffer)?; + let vec_buffer = vec_buffer.into_inner(); + io::copy(&mut vec_buffer.as_slice(), &mut writer)?; } } From 0ed684186598a7e840e87c4c27aa34448c10e99d Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:14:04 +0300 Subject: [PATCH 4/5] Fix tests so they don't use `tar.zst` --- tests/compress_and_decompress.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 77d929d..0a34f47 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -32,7 +32,7 @@ fn sanity_check_through_mime() { let formats = [ "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma", - "tar.xz", "tar.zst", + "tar.xz", "zst", ]; let expected_mimes = [ @@ -79,7 +79,6 @@ 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("tgz"); test_compressing_and_decompressing_archive("tbz"); test_compressing_and_decompressing_archive("tbz2"); @@ -97,7 +96,7 @@ fn test_each_format() { // Why not test_compressing_and_decompressing_archive( - "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", + "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", ); } From bdf5090844ed267621ab9e3e9bdda6de6a05b68a Mon Sep 17 00:00:00 2001 From: Spyros Roum Date: Fri, 22 Oct 2021 02:21:31 +0300 Subject: [PATCH 5/5] zst is not an archive format.. --- src/archive/zip.rs | 2 +- src/extension.rs | 2 +- tests/compress_and_decompress.rs | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/archive/zip.rs b/src/archive/zip.rs index db35727..f15e650 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -11,7 +11,7 @@ use zip::{self, read::ZipFile, ZipArchive}; use crate::{ info, - utils::{self, dir_is_empty,strip_cur_dir, Bytes}, + utils::{self, dir_is_empty, strip_cur_dir, Bytes}, }; use self::utf8::get_invalid_utf8_paths; diff --git a/src/extension.rs b/src/extension.rs index 87efbc6..9ff200f 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -21,7 +21,7 @@ pub enum CompressionFormat { impl CompressionFormat { pub fn is_archive_format(&self) -> bool { - matches!(self, Tar | Tgz | Tbz | Tlzma | Tzst | Zstd | Zip) + matches!(self, Tar | Tgz | Tbz | Tlzma | Tzst | Zip) } } diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 0a34f47..77d929d 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -32,7 +32,7 @@ fn sanity_check_through_mime() { let formats = [ "tar", "zip", "tar.gz", "tgz", "tbz", "tbz2", "txz", "tlz", "tlzma", "tzst", "tar.bz", "tar.bz2", "tar.lzma", - "tar.xz", "zst", + "tar.xz", "tar.zst", ]; let expected_mimes = [ @@ -79,6 +79,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("tgz"); test_compressing_and_decompressing_archive("tbz"); test_compressing_and_decompressing_archive("tbz2"); @@ -96,7 +97,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", ); }