From cd461fa5a5353b8294b879953e7a6aa75366f9dd Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 14 Oct 2021 15:22:48 -0400 Subject: [PATCH 1/2] apply clippy lints and small refactors (#86) --- src/commands.rs | 8 ++++---- src/error.rs | 16 ++++++---------- src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index bf278b6..24847bc 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -29,7 +29,7 @@ const BUFFER_CAPACITY: usize = 1024 * 64; fn represents_several_files(files: &[PathBuf]) -> bool { let is_non_empty_dir = |path: &PathBuf| { - let is_non_empty = || !dir_is_empty(&path); + let is_non_empty = || !dir_is_empty(path); path.is_dir().then(is_non_empty).unwrap_or_default() }; @@ -51,7 +51,7 @@ pub fn run(command: Command, flags: &oof::Flags) -> crate::Result<()> { .hint("Examples:") .hint(format!(" ouch compress ... {}.tar.gz", to_utf(&output_path))) .hint(format!(" ouch compress ... {}.zip", to_utf(&output_path))) - .into_owned(); + .clone(); return Err(Error::with_reason(reason)); } @@ -80,7 +80,7 @@ pub fn run(command: Command, flags: &oof::Flags) -> crate::Result<()> { .hint(format!("Try inserting '.tar' or '.zip' before '{}'.", &formats[0])) .hint(format!("From: {}", output_path)) .hint(format!(" To : {}", suggested_output_path)) - .into_owned(); + .clone(); return Err(Error::with_reason(reason)); } @@ -91,7 +91,7 @@ pub fn run(command: Command, flags: &oof::Flags) -> crate::Result<()> { .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 {} from '{}'.", format, to_utf(&output_path))) - .into_owned(); + .clone(); return Err(Error::with_reason(reason)); } diff --git a/src/error.rs b/src/error.rs index 3792bfb..caf7e6c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -79,10 +79,6 @@ impl FinalError { self.hints.push(hint.to_string()); self } - - pub fn into_owned(&mut self) -> Self { - std::mem::take(self) - } } impl fmt::Display for Error { @@ -93,7 +89,7 @@ impl fmt::Display for Error { .detail("Ouch could not detect the compression format") .hint("Use a supported format extension, like '.zip' or '.tar.gz'") .hint("Check https://github.com/vrmiguel/ouch for a full list of supported formats") - .into_owned(); + .clone(); error } @@ -111,7 +107,7 @@ impl fmt::Display for Error { let error = FinalError::with_title("It seems you're trying to compress the root folder.") .detail("This is unadvisable since ouch does compressions in-memory.") .hint("Use a more appropriate tool for this, such as rsync.") - .into_owned(); + .clone(); error } @@ -123,7 +119,7 @@ impl fmt::Display for Error { .hint(" - The output argument.") .hint("") .hint("Example: `ouch compress image.png img.zip`") - .into_owned(); + .clone(); error } @@ -134,7 +130,7 @@ impl fmt::Display for Error { .hint(" - At least one input argument.") .hint("") .hint("Example: `ouch decompress imgs.tar.gz`") - .into_owned(); + .clone(); error } @@ -144,7 +140,7 @@ impl fmt::Display for Error { .detail("It's probably our fault") .detail("Please help us improve by reporting the issue at:") .detail(format!(" {}https://github.com/vrmiguel/ouch/issues ", cyan())) - .into_owned(); + .clone(); error } @@ -152,7 +148,7 @@ impl fmt::Display for Error { Error::IoError { reason } => FinalError::with_title(reason), Error::CompressionTypo => FinalError::with_title("Possible typo detected") .hint(format!("Did you mean '{}ouch compress{}'?", magenta(), reset())) - .into_owned(), + .clone(), Error::UnknownExtensionError(_) => todo!(), Error::AlreadyExists => todo!(), Error::InvalidZipArchive(_) => todo!(), diff --git a/src/lib.rs b/src/lib.rs index b6fd3b7..52537a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ use lazy_static::lazy_static; /// The status code ouch has when an error is encountered pub const EXIT_FAILURE: i32 = libc::EXIT_FAILURE; -const VERSION: &'static str = env!("CARGO_PKG_VERSION"); +const VERSION: &str = env!("CARGO_PKG_VERSION"); lazy_static! { static ref NO_COLOR_IS_SET: bool = { From f923423a06a2ed68c4f3a249ecfe4fd992488282 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 14 Oct 2021 15:55:34 -0400 Subject: [PATCH 2/2] Extension: add support for tgz (#85) * extension: add support for tgz --- README.md | 2 +- src/commands.rs | 33 ++++++++++++++++++++++++++------ src/extension.rs | 25 ++++++++++++------------ tests/compress_and_decompress.rs | 4 +++- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 4c70fae..cea0c4c 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ For compiling, check [the wiki guide](https://github.com/ouch-org/ouch/wiki/Comp ## Supported formats -| | .tar | .zip | .bz, .bz2 | .gz | .xz, .lz, .lzma | .zst | +| | .tar, .tgz | .zip | .bz, .bz2 | .gz | .xz, .lz, .lzma | .zst | |:-------------:|:----:|:----:|:---------:| --- |:---------------:| --- | | Decompression | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Compression | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | diff --git a/src/commands.rs b/src/commands.rs index 24847bc..3ae5cd9 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -170,14 +170,23 @@ fn compress_files( let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file); if formats.len() == 1 { - let build_archive_from_paths = match formats[0] { - Tar => archive::tar::build_archive_from_paths, - Zip => archive::zip::build_archive_from_paths, + 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()?; + } _ => unreachable!(), }; - - let mut bufwriter = build_archive_from_paths(&files, file_writer)?; - bufwriter.flush()?; } else { let mut writer: Box = Box::new(file_writer); @@ -213,6 +222,12 @@ fn compress_files( let mut writer = archive::tar::build_archive_from_paths(&files, writer)?; writer.flush()?; } + Tgz => { + // Wrap it into an gz_decoder, and pass to the tar archive builder + let gz_decoder = flate2::write::GzEncoder::new(writer, Default::default()); + let mut writer = archive::tar::build_archive_from_paths(&files, gz_decoder)?; + writer.flush()?; + } Zip => { eprintln!("{yellow}Warning:{reset}", yellow = colors::yellow(), reset = colors::reset()); eprintln!("\tCompressing .zip entirely in memory."); @@ -305,6 +320,12 @@ fn decompress_file( let _ = crate::archive::tar::unpack_archive(reader, output_folder, flags)?; info!("Successfully uncompressed archive in '{}'.", to_utf(output_folder)); } + Tgz => { + utils::create_dir_if_non_existent(output_folder)?; + let reader = chain_reader_decoder(&Gzip, reader)?; + let _ = crate::archive::tar::unpack_archive(reader, output_folder, flags)?; + info!("Successfully uncompressed archive in '{}'.", to_utf(output_folder)); + } Zip => { utils::create_dir_if_non_existent(output_folder)?; diff --git a/src/extension.rs b/src/extension.rs index 5f33b58..aa2777a 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -1,6 +1,6 @@ //! Our representation of all the supported compression formats. -use std::{fmt, path::Path}; +use std::{ffi::OsStr, fmt, path::Path}; use self::CompressionFormat::*; @@ -11,6 +11,7 @@ pub enum CompressionFormat { Bzip, // .bz Lzma, // .lzma Tar, // .tar (technically not a compression extension, but will do for now) + Tgz, // .tgz Zstd, // .zst Zip, // .zip } @@ -26,6 +27,7 @@ impl fmt::Display for CompressionFormat { Zstd => ".zst", Lzma => ".lz", Tar => ".tar", + Tgz => ".tgz", Zip => ".zip", } ) @@ -44,18 +46,17 @@ pub fn separate_known_extensions_from_name(mut path: &Path) -> (&Path, Vec Tar, - _ if extension == "zip" => Zip, - _ if extension == "bz" || extension == "bz2" => Bzip, - _ if extension == "gz" => Gzip, - _ if extension == "xz" || extension == "lzma" || extension == "lz" => Lzma, - _ if extension == "zst" => Zstd, + while let Some(extension) = path.extension().and_then(OsStr::to_str) { + extensions.push(match extension { + "tar" => Tar, + "tgz" => Tgz, + "zip" => Zip, + "bz" | "bz2" => Bzip, + "gz" => Gzip, + "xz" | "lzma" | "lz" => Lzma, + "zst" => Zstd, _ => break, - }; - - extensions.push(extension); + }); // Update for the next iteration path = if let Some(stem) = path.file_stem() { Path::new(stem) } else { Path::new("") }; diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 22b99fc..e97ab33 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -27,12 +27,13 @@ fn sanity_check_through_mime() { let bytes = generate_random_file_content(&mut SmallRng::from_entropy()); test_file.write_all(&bytes).expect("to successfully write bytes to the file"); - let formats = ["tar", "zip", "tar.gz", "tar.bz", "tar.bz2", "tar.lzma", "tar.xz", "tar.zst"]; + let formats = ["tar", "zip", "tar.gz", "tgz", "tar.bz", "tar.bz2", "tar.lzma", "tar.xz", "tar.zst"]; let expected_mimes = [ "application/x-tar", "application/zip", "application/gzip", + "application/gzip", "application/x-bzip2", "application/x-bzip2", "application/x-xz", @@ -67,6 +68,7 @@ fn test_each_format() { 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("zip"); test_compressing_and_decompressing_archive("zip.gz"); test_compressing_and_decompressing_archive("zip.bz");