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");