refactor(decompress): refactor function to use DecompressOptions struct to make linter happy (too_many_arguments)

This commit is contained in:
ttyS3 2024-11-30 16:27:02 +00:00 committed by João Marcos
parent 55aa05b631
commit 62f3d78f44
2 changed files with 58 additions and 55 deletions

View File

@ -26,24 +26,26 @@ use crate::{
trait ReadSeek: Read + io::Seek {}
impl<T: Read + io::Seek> ReadSeek for T {}
pub struct DecompressOptions<'a> {
pub input_file_path: &'a Path,
pub formats: Vec<Extension>,
pub output_dir: &'a Path,
pub output_file_path: PathBuf,
pub question_policy: QuestionPolicy,
pub quiet: bool,
pub password: Option<&'a [u8]>,
pub remove: bool,
}
/// Decompress a file
///
/// File at input_file_path is opened for reading, example: "archive.tar.gz"
/// formats contains each format necessary for decompression, example: [Gz, Tar] (in decompression order)
/// output_dir it's where the file will be decompressed to, this function assumes that the directory exists
/// output_file_path is only used when extracting single file formats, not archive formats like .tar or .zip
pub fn decompress_file(
input_file_path: &Path,
formats: Vec<Extension>,
output_dir: &Path,
output_file_path: PathBuf,
question_policy: QuestionPolicy,
quiet: bool,
password: Option<&[u8]>,
remove: bool,
) -> crate::Result<()> {
assert!(output_dir.exists());
let input_is_stdin = is_path_stdin(input_file_path);
pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
assert!(options.output_dir.exists());
let input_is_stdin = is_path_stdin(options.input_file_path);
// Zip archives are special, because they require io::Seek, so it requires it's logic separated
// from decoder chaining.
@ -55,7 +57,7 @@ pub fn decompress_file(
if let [Extension {
compression_formats: [Zip],
..
}] = formats.as_slice()
}] = options.formats.as_slice()
{
let mut vec = vec![];
let reader: Box<dyn ReadSeek> = if input_is_stdin {
@ -63,14 +65,14 @@ pub fn decompress_file(
io::copy(&mut io::stdin(), &mut vec)?;
Box::new(io::Cursor::new(vec))
} else {
Box::new(fs::File::open(input_file_path)?)
Box::new(fs::File::open(options.input_file_path)?)
};
let zip_archive = zip::ZipArchive::new(reader)?;
let files_unpacked = if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, password, quiet),
output_dir,
&output_file_path,
question_policy,
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, options.password, options.quiet),
options.output_dir,
&options.output_file_path,
options.question_policy,
)? {
files
} else {
@ -83,15 +85,15 @@ pub fn decompress_file(
// about whether the command succeeded without such a message
info_accessible(format!(
"Successfully decompressed archive in {} ({} files)",
nice_directory_display(output_dir),
nice_directory_display(options.output_dir),
files_unpacked
));
if !input_is_stdin && remove {
fs::remove_file(input_file_path)?;
if !input_is_stdin && options.remove {
fs::remove_file(options.input_file_path)?;
info(format!(
"Removed input file {}",
nice_directory_display(input_file_path)
nice_directory_display(options.input_file_path)
));
}
@ -102,7 +104,7 @@ pub fn decompress_file(
let reader: Box<dyn Read> = if input_is_stdin {
Box::new(io::stdin())
} else {
Box::new(fs::File::open(input_file_path)?)
Box::new(fs::File::open(options.input_file_path)?)
};
let reader = BufReader::with_capacity(BUFFER_CAPACITY, reader);
let mut reader: Box<dyn Read> = Box::new(reader);
@ -122,7 +124,7 @@ pub fn decompress_file(
Ok(decoder)
};
let (first_extension, extensions) = split_first_compression_format(&formats);
let (first_extension, extensions) = split_first_compression_format(&options.formats);
for format in extensions.iter().rev() {
reader = chain_reader_decoder(format, reader)?;
@ -132,7 +134,7 @@ pub fn decompress_file(
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd => {
reader = chain_reader_decoder(&first_extension, reader)?;
let mut writer = match utils::ask_to_create_file(&output_file_path, question_policy)? {
let mut writer = match utils::ask_to_create_file(&options.output_file_path, options.question_policy)? {
Some(file) => file,
None => return Ok(()),
};
@ -143,10 +145,10 @@ pub fn decompress_file(
}
Tar => {
if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::tar::unpack_archive(reader, output_dir, quiet),
output_dir,
&output_file_path,
question_policy,
|output_dir| crate::archive::tar::unpack_archive(reader, output_dir, options.quiet),
options.output_dir,
&options.output_file_path,
options.question_policy,
)? {
files
} else {
@ -154,13 +156,13 @@ pub fn decompress_file(
}
}
Zip => {
if formats.len() > 1 {
if options.formats.len() > 1 {
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();
warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(input_file_path, question_policy, QuestionAction::Decompression)? {
if !user_wants_to_continue(options.input_file_path, options.question_policy, QuestionAction::Decompression)? {
return Ok(());
}
}
@ -170,10 +172,10 @@ pub fn decompress_file(
let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?;
if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, password, quiet),
output_dir,
&output_file_path,
question_policy,
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, options.password, options.quiet),
options.output_dir,
&options.output_file_path,
options.question_policy,
)? {
files
} else {
@ -183,18 +185,18 @@ pub fn decompress_file(
#[cfg(feature = "unrar")]
Rar => {
type UnpackResult = crate::Result<usize>;
let unpack_fn: Box<dyn FnOnce(&Path) -> UnpackResult> = if formats.len() > 1 || input_is_stdin {
let unpack_fn: Box<dyn FnOnce(&Path) -> UnpackResult> = if options.formats.len() > 1 || input_is_stdin {
let mut temp_file = tempfile::NamedTempFile::new()?;
io::copy(&mut reader, &mut temp_file)?;
Box::new(move |output_dir| {
crate::archive::rar::unpack_archive(temp_file.path(), output_dir, password, quiet)
crate::archive::rar::unpack_archive(temp_file.path(), output_dir, options.password, options.quiet)
})
} else {
Box::new(|output_dir| crate::archive::rar::unpack_archive(input_file_path, output_dir, password, quiet))
Box::new(|output_dir| crate::archive::rar::unpack_archive(options.input_file_path, output_dir, options.password, options.quiet))
};
if let ControlFlow::Continue(files) =
smart_unpack(unpack_fn, output_dir, &output_file_path, question_policy)?
smart_unpack(unpack_fn, options.output_dir, &options.output_file_path, options.question_policy)?
{
files
} else {
@ -206,13 +208,13 @@ pub fn decompress_file(
return Err(crate::archive::rar_stub::no_support());
}
SevenZip => {
if formats.len() > 1 {
if options.formats.len() > 1 {
// Locking necessary to guarantee that warning and question
// messages stay adjacent
let _locks = lock_and_flush_output_stdio();
warn_user_about_loading_sevenz_in_memory();
if !user_wants_to_continue(input_file_path, question_policy, QuestionAction::Decompression)? {
if !user_wants_to_continue(options.input_file_path, options.question_policy, QuestionAction::Decompression)? {
return Ok(());
}
}
@ -222,11 +224,11 @@ pub fn decompress_file(
if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| {
crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, password, quiet)
crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, options.password, options.quiet)
},
output_dir,
&output_file_path,
question_policy,
options.output_dir,
&options.output_file_path,
options.question_policy,
)? {
files
} else {
@ -241,15 +243,15 @@ pub fn decompress_file(
// about whether the command succeeded without such a message
info_accessible(format!(
"Successfully decompressed archive in {}",
nice_directory_display(output_dir)
nice_directory_display(options.output_dir)
));
info_accessible(format!("Files unpacked: {}", files_unpacked));
if !input_is_stdin && remove {
fs::remove_file(input_file_path)?;
if !input_is_stdin && options.remove {
fs::remove_file(options.input_file_path)?;
info(format!(
"Removed input file {}",
nice_directory_display(input_file_path)
nice_directory_display(options.input_file_path)
));
}

View File

@ -7,6 +7,7 @@ mod list;
use std::{ops::ControlFlow, path::PathBuf};
use bstr::ByteSlice;
use decompress::DecompressOptions;
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use utils::colors;
@ -193,18 +194,18 @@ pub fn run(
path_to_str(file_name),
path_to_str(&output_file_path)
));
decompress_file(
input_path,
decompress_file(DecompressOptions {
input_file_path: input_path,
formats,
&output_dir,
output_dir: &output_dir,
output_file_path,
question_policy,
args.quiet,
args.password.as_deref().map(|str| {
quiet: args.quiet,
password: args.password.as_deref().map(|str| {
<[u8] as ByteSlice>::from_os_str(str).expect("convert password to bytes failed")
}),
remove,
)
})
})
}
Subcommand::List { archives: files, tree } => {