Merge pull request #372 from xgdgsc/feat/complevel

add raw level arg
This commit is contained in:
João Marcos 2023-03-19 15:42:25 -03:00 committed by GitHub
commit e0391a872b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 10 deletions

View File

@ -59,6 +59,10 @@ pub enum Subcommand {
/// The resulting file. Its extensions can be used to specify the compression formats
#[arg(required = true, value_hint = ValueHint::FilePath)]
output: PathBuf,
/// Compression level, applied to all formats
#[arg(short, long)]
level: Option<i16>,
},
/// Decompresses one or more files, optionally into another folder
#[command(visible_alias = "d")]

View File

@ -23,6 +23,7 @@ use crate::{
/// # Return value
/// - Returns `Ok(true)` if compressed all files normally.
/// - Returns `Ok(false)` if user opted to abort compression mid-way.
#[allow(clippy::too_many_arguments)]
pub fn compress_files(
files: Vec<PathBuf>,
extensions: Vec<Extension>,
@ -31,6 +32,7 @@ pub fn compress_files(
quiet: bool,
question_policy: QuestionPolicy,
file_visibility_policy: FileVisibilityPolicy,
level: Option<i16>,
) -> crate::Result<bool> {
// If the input files contain a directory, then the total size will be underestimated
let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file);
@ -44,18 +46,42 @@ pub fn compress_files(
// by default, ParCompress uses a default compression level of 3
// instead of the regular default that flate2 uses
gzp::par::compress::ParCompress::<gzp::deflate::Gzip>::builder()
.compression_level(Default::default())
.compression_level(
level.map_or_else(Default::default, |l| gzp::Compression::new((l as u32).clamp(0, 9))),
)
.from_writer(encoder),
),
Bzip => Box::new(bzip2::write::BzEncoder::new(
encoder,
level.map_or_else(Default::default, |l| bzip2::Compression::new((l as u32).clamp(1, 9))),
)),
Lz4 => Box::new(lzzzz::lz4f::WriteCompressor::new(
encoder,
lzzzz::lz4f::PreferencesBuilder::new()
.compression_level(level.map_or(1, |l| (l as i32).clamp(1, lzzzz::lz4f::CLEVEL_MAX)))
.build(),
)?),
Lzma => Box::new(xz2::write::XzEncoder::new(
encoder,
level.map_or(6, |l| (l as u32).clamp(0, 9)),
)),
Snappy => Box::new(
gzp::par::compress::ParCompress::<gzp::snap::Snap>::builder()
.compression_level(gzp::par::compress::Compression::new(
level.map_or_else(Default::default, |l| (l as u32).clamp(0, 9)),
))
.from_writer(encoder),
),
Bzip => Box::new(bzip2::write::BzEncoder::new(encoder, Default::default())),
Lz4 => Box::new(lzzzz::lz4f::WriteCompressor::new(encoder, Default::default())?),
Lzma => Box::new(xz2::write::XzEncoder::new(encoder, 6)),
Snappy => Box::new(gzp::par::compress::ParCompress::<gzp::snap::Snap>::builder().from_writer(encoder)),
Zstd => {
let zstd_encoder = zstd::stream::write::Encoder::new(encoder, Default::default());
let zstd_encoder = zstd::stream::write::Encoder::new(
encoder,
level.map_or(zstd::DEFAULT_COMPRESSION_LEVEL, |l| {
(l as i32).clamp(zstd::zstd_safe::min_c_level(), zstd::zstd_safe::max_c_level())
}),
);
// Safety:
// Encoder::new() can only fail if `level` is invalid, but Default::default()
// is guaranteed to be valid
// Encoder::new() can only fail if `level` is invalid, but the level
// is `clamp`ed and therefore guaranteed to be valid
Box::new(zstd_encoder.unwrap().auto_finish())
}
Tar | Zip => unreachable!(),

View File

@ -44,6 +44,7 @@ pub fn run(
Subcommand::Compress {
files,
output: output_path,
level,
} => {
// After cleaning, if there are no input files left, exit
if files.is_empty() {
@ -80,6 +81,7 @@ pub fn run(
args.quiet,
question_policy,
file_visibility_policy,
level,
);
if let Ok(true) = compress_result {

View File

@ -100,7 +100,11 @@ fn single_empty_file(ext: Extension, #[any(size_range(0..8).lift())] exts: Vec<F
// compress and decompress a single file
#[proptest(cases = 512)]
fn single_file(ext: Extension, #[any(size_range(0..8).lift())] exts: Vec<FileExtension>) {
fn single_file(
ext: Extension,
#[any(size_range(0..8).lift())] exts: Vec<FileExtension>,
#[strategy(proptest::option::of(0i16..30))] level: Option<i16>,
) {
let dir = tempdir().unwrap();
let dir = dir.path();
let before = &dir.join("before");
@ -109,7 +113,11 @@ fn single_file(ext: Extension, #[any(size_range(0..8).lift())] exts: Vec<FileExt
let archive = &dir.join(format!("file.{}", merge_extensions(ext, exts)));
let after = &dir.join("after");
fs::write(before_file, []).unwrap();
ouch!("-A", "c", before_file, archive);
if let Some(level) = level {
ouch!("-A", "c", "-l", level.to_string(), before_file, archive);
} else {
ouch!("-A", "c", before_file, archive);
}
ouch!("-A", "d", archive, "-d", after);
assert_same_directory(before, after, false);
}