mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
feat: Add flag '--no-smart-unpack' to disable smart unpack (#809)
This commit is contained in:
parent
2b9da1e441
commit
c97bb6a2d6
@ -21,6 +21,7 @@ Categories Used:
|
|||||||
## [Unreleased](https://github.com/ouch-org/ouch/compare/0.6.1...HEAD)
|
## [Unreleased](https://github.com/ouch-org/ouch/compare/0.6.1...HEAD)
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
- Add `--no-smart-unpack` flag to decompression command to disable smart unpack [\#809](https://github.com/ouch-org/ouch/pull/809) ([talis-fb](https://github.com/talis-fb))
|
||||||
### Improvements
|
### Improvements
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
### Tweaks
|
### Tweaks
|
||||||
|
@ -100,6 +100,10 @@ pub enum Subcommand {
|
|||||||
/// Remove the source file after successful decompression
|
/// Remove the source file after successful decompression
|
||||||
#[arg(short = 'r', long)]
|
#[arg(short = 'r', long)]
|
||||||
remove: bool,
|
remove: bool,
|
||||||
|
|
||||||
|
/// Disable Smart Unpack
|
||||||
|
#[arg(long)]
|
||||||
|
no_smart_unpack: bool,
|
||||||
},
|
},
|
||||||
/// List contents of an archive
|
/// List contents of an archive
|
||||||
#[command(visible_aliases = ["l", "ls"])]
|
#[command(visible_aliases = ["l", "ls"])]
|
||||||
@ -156,6 +160,7 @@ mod tests {
|
|||||||
files: vec!["\x00\x11\x22".into()],
|
files: vec!["\x00\x11\x22".into()],
|
||||||
output_dir: None,
|
output_dir: None,
|
||||||
remove: false,
|
remove: false,
|
||||||
|
no_smart_unpack: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,6 +174,7 @@ mod tests {
|
|||||||
files: to_paths(["file.tar.gz"]),
|
files: to_paths(["file.tar.gz"]),
|
||||||
output_dir: None,
|
output_dir: None,
|
||||||
remove: false,
|
remove: false,
|
||||||
|
no_smart_unpack: false,
|
||||||
},
|
},
|
||||||
..mock_cli_args()
|
..mock_cli_args()
|
||||||
}
|
}
|
||||||
@ -180,6 +186,7 @@ mod tests {
|
|||||||
files: to_paths(["file.tar.gz"]),
|
files: to_paths(["file.tar.gz"]),
|
||||||
output_dir: None,
|
output_dir: None,
|
||||||
remove: false,
|
remove: false,
|
||||||
|
no_smart_unpack: false,
|
||||||
},
|
},
|
||||||
..mock_cli_args()
|
..mock_cli_args()
|
||||||
}
|
}
|
||||||
@ -191,6 +198,7 @@ mod tests {
|
|||||||
files: to_paths(["a", "b", "c"]),
|
files: to_paths(["a", "b", "c"]),
|
||||||
output_dir: None,
|
output_dir: None,
|
||||||
remove: false,
|
remove: false,
|
||||||
|
no_smart_unpack: false,
|
||||||
},
|
},
|
||||||
..mock_cli_args()
|
..mock_cli_args()
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ pub struct DecompressOptions<'a> {
|
|||||||
pub output_dir: &'a Path,
|
pub output_dir: &'a Path,
|
||||||
pub output_file_path: PathBuf,
|
pub output_file_path: PathBuf,
|
||||||
pub is_output_dir_provided: bool,
|
pub is_output_dir_provided: bool,
|
||||||
|
pub is_smart_unpack: bool,
|
||||||
pub question_policy: QuestionPolicy,
|
pub question_policy: QuestionPolicy,
|
||||||
pub quiet: bool,
|
pub quiet: bool,
|
||||||
pub password: Option<&'a [u8]>,
|
pub password: Option<&'a [u8]>,
|
||||||
@ -75,6 +76,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
|||||||
&options.output_file_path,
|
&options.output_file_path,
|
||||||
options.question_policy,
|
options.question_policy,
|
||||||
options.is_output_dir_provided,
|
options.is_output_dir_provided,
|
||||||
|
options.is_smart_unpack,
|
||||||
)? {
|
)? {
|
||||||
files
|
files
|
||||||
} else {
|
} else {
|
||||||
@ -153,6 +155,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
|||||||
&options.output_file_path,
|
&options.output_file_path,
|
||||||
options.question_policy,
|
options.question_policy,
|
||||||
options.is_output_dir_provided,
|
options.is_output_dir_provided,
|
||||||
|
options.is_smart_unpack,
|
||||||
)? {
|
)? {
|
||||||
files
|
files
|
||||||
} else {
|
} else {
|
||||||
@ -187,6 +190,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
|||||||
&options.output_file_path,
|
&options.output_file_path,
|
||||||
options.question_policy,
|
options.question_policy,
|
||||||
options.is_output_dir_provided,
|
options.is_output_dir_provided,
|
||||||
|
options.is_smart_unpack,
|
||||||
)? {
|
)? {
|
||||||
files
|
files
|
||||||
} else {
|
} else {
|
||||||
@ -219,6 +223,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
|||||||
&options.output_file_path,
|
&options.output_file_path,
|
||||||
options.question_policy,
|
options.question_policy,
|
||||||
options.is_output_dir_provided,
|
options.is_output_dir_provided,
|
||||||
|
options.is_smart_unpack,
|
||||||
)? {
|
)? {
|
||||||
files
|
files
|
||||||
} else {
|
} else {
|
||||||
@ -261,6 +266,7 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
|||||||
&options.output_file_path,
|
&options.output_file_path,
|
||||||
options.question_policy,
|
options.question_policy,
|
||||||
options.is_output_dir_provided,
|
options.is_output_dir_provided,
|
||||||
|
options.is_smart_unpack,
|
||||||
)? {
|
)? {
|
||||||
files
|
files
|
||||||
} else {
|
} else {
|
||||||
@ -296,12 +302,19 @@ fn execute_decompression(
|
|||||||
output_file_path: &Path,
|
output_file_path: &Path,
|
||||||
question_policy: QuestionPolicy,
|
question_policy: QuestionPolicy,
|
||||||
is_output_dir_provided: bool,
|
is_output_dir_provided: bool,
|
||||||
|
is_smart_unpack: bool,
|
||||||
) -> crate::Result<ControlFlow<(), usize>> {
|
) -> crate::Result<ControlFlow<(), usize>> {
|
||||||
if is_output_dir_provided {
|
if is_smart_unpack {
|
||||||
unpack(unpack_fn, output_dir, question_policy)
|
return smart_unpack(unpack_fn, output_dir, output_file_path, question_policy);
|
||||||
} else {
|
|
||||||
smart_unpack(unpack_fn, output_dir, output_file_path, question_policy)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let target_output_dir = if is_output_dir_provided {
|
||||||
|
output_dir
|
||||||
|
} else {
|
||||||
|
output_file_path
|
||||||
|
};
|
||||||
|
|
||||||
|
unpack(unpack_fn, target_output_dir, question_policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unpacks an archive creating the output directory, this function will create the output_dir
|
/// Unpacks an archive creating the output directory, this function will create the output_dir
|
||||||
|
@ -148,6 +148,7 @@ pub fn run(
|
|||||||
files,
|
files,
|
||||||
output_dir,
|
output_dir,
|
||||||
remove,
|
remove,
|
||||||
|
no_smart_unpack,
|
||||||
} => {
|
} => {
|
||||||
let mut output_paths = vec![];
|
let mut output_paths = vec![];
|
||||||
let mut formats = vec![];
|
let mut formats = vec![];
|
||||||
@ -176,9 +177,11 @@ pub fn run(
|
|||||||
|
|
||||||
check::check_missing_formats_when_decompressing(&files, &formats)?;
|
check::check_missing_formats_when_decompressing(&files, &formats)?;
|
||||||
|
|
||||||
|
let is_output_dir_provided = output_dir.is_some();
|
||||||
|
let is_smart_unpack = !is_output_dir_provided && !no_smart_unpack;
|
||||||
|
|
||||||
// The directory that will contain the output files
|
// The directory that will contain the output files
|
||||||
// We default to the current directory if the user didn't specify an output directory with --dir
|
// We default to the current directory if the user didn't specify an output directory with --dir
|
||||||
let is_output_dir_provided = output_dir.is_some();
|
|
||||||
let output_dir = if let Some(dir) = output_dir {
|
let output_dir = if let Some(dir) = output_dir {
|
||||||
utils::create_dir_if_non_existent(&dir)?;
|
utils::create_dir_if_non_existent(&dir)?;
|
||||||
dir
|
dir
|
||||||
@ -200,9 +203,10 @@ pub fn run(
|
|||||||
decompress_file(DecompressOptions {
|
decompress_file(DecompressOptions {
|
||||||
input_file_path: input_path,
|
input_file_path: input_path,
|
||||||
formats,
|
formats,
|
||||||
|
is_output_dir_provided,
|
||||||
output_dir: &output_dir,
|
output_dir: &output_dir,
|
||||||
output_file_path,
|
output_file_path,
|
||||||
is_output_dir_provided,
|
is_smart_unpack,
|
||||||
question_policy,
|
question_policy,
|
||||||
quiet: args.quiet,
|
quiet: args.quiet,
|
||||||
password: args.password.as_deref().map(|str| {
|
password: args.password.as_deref().map(|str| {
|
||||||
|
@ -367,6 +367,201 @@ fn multiple_files_with_conflict_and_choice_to_rename_with_already_a_renamed(
|
|||||||
assert_same_directory(src_files_path, dest_files_path_renamed.join("src_files"), false);
|
assert_same_directory(src_files_path, dest_files_path_renamed.join("src_files"), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proptest(cases = 25)]
|
||||||
|
fn smart_unpack_with_single_file(
|
||||||
|
ext: DirectoryExtension,
|
||||||
|
#[any(size_range(0..1).lift())] extra_extensions: Vec<FileExtension>,
|
||||||
|
) {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let root_path = temp_dir.path();
|
||||||
|
|
||||||
|
let src_files_path = root_path.join("src_files");
|
||||||
|
fs::create_dir_all(&src_files_path).unwrap();
|
||||||
|
|
||||||
|
let files_path = ["file1.txt"]
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| src_files_path.join(f))
|
||||||
|
.inspect(|path| {
|
||||||
|
let mut file = fs::File::create(path).unwrap();
|
||||||
|
file.write_all("Some content".as_bytes()).unwrap();
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let archive = &root_path.join(format!("archive.{}", merge_extensions(&ext, extra_extensions)));
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.arg("compress")
|
||||||
|
.args(files_path)
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
let output_file = root_path.join("file1.txt");
|
||||||
|
assert!(!output_file.exists());
|
||||||
|
|
||||||
|
// Decompress the archive with Smart Unpack
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.current_dir(root_path)
|
||||||
|
.arg("decompress")
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
assert!(output_file.exists());
|
||||||
|
|
||||||
|
let output_content = fs::read_to_string(&output_file).unwrap();
|
||||||
|
assert_eq!(output_content, "Some content");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proptest(cases = 25)]
|
||||||
|
fn smart_unpack_with_multiple_files(
|
||||||
|
ext: DirectoryExtension,
|
||||||
|
#[any(size_range(0..1).lift())] extra_extensions: Vec<FileExtension>,
|
||||||
|
) {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let root_path = temp_dir.path();
|
||||||
|
|
||||||
|
let src_files_path = root_path.join("src_files");
|
||||||
|
fs::create_dir_all(&src_files_path).unwrap();
|
||||||
|
|
||||||
|
["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| src_files_path.join(f))
|
||||||
|
.for_each(|path| {
|
||||||
|
let mut file = fs::File::create(&path).unwrap();
|
||||||
|
file.write_all("Some content".as_bytes()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let input_files = src_files_path
|
||||||
|
.read_dir()
|
||||||
|
.unwrap()
|
||||||
|
.map(|entry| entry.unwrap().path())
|
||||||
|
.collect::<Vec<PathBuf>>();
|
||||||
|
|
||||||
|
let archive = &root_path.join(format!("archive.{}", merge_extensions(&ext, extra_extensions)));
|
||||||
|
|
||||||
|
let output_path = root_path.join("archive");
|
||||||
|
assert!(!output_path.exists());
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.arg("compress")
|
||||||
|
.args(input_files)
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.current_dir(root_path)
|
||||||
|
.arg("decompress")
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
assert!(output_path.exists(), "Output directory does not exist");
|
||||||
|
|
||||||
|
assert_same_directory(src_files_path, output_path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proptest(cases = 25)]
|
||||||
|
fn no_smart_unpack_with_single_file(
|
||||||
|
ext: DirectoryExtension,
|
||||||
|
#[any(size_range(0..1).lift())] extra_extensions: Vec<FileExtension>,
|
||||||
|
) {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let root_path = temp_dir.path();
|
||||||
|
|
||||||
|
let src_files_path = root_path.join("src_files");
|
||||||
|
fs::create_dir_all(&src_files_path).unwrap();
|
||||||
|
|
||||||
|
["file1.txt"]
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| src_files_path.join(f))
|
||||||
|
.for_each(|path| {
|
||||||
|
let mut file = fs::File::create(&path).unwrap();
|
||||||
|
file.write_all("Some content".as_bytes()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let input_files = src_files_path
|
||||||
|
.read_dir()
|
||||||
|
.unwrap()
|
||||||
|
.map(|entry| entry.unwrap().path())
|
||||||
|
.collect::<Vec<PathBuf>>();
|
||||||
|
|
||||||
|
let archive = &root_path.join(format!("archive.{}", merge_extensions(&ext, extra_extensions)));
|
||||||
|
|
||||||
|
let output_path = root_path.join("archive");
|
||||||
|
assert!(!output_path.exists());
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.arg("compress")
|
||||||
|
.args(input_files)
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.current_dir(root_path)
|
||||||
|
.arg("decompress")
|
||||||
|
.arg("--no-smart-unpack")
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
assert!(output_path.exists(), "Output directory does not exist");
|
||||||
|
|
||||||
|
assert_same_directory(src_files_path, output_path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proptest(cases = 25)]
|
||||||
|
fn no_smart_unpack_with_multiple_files(
|
||||||
|
ext: DirectoryExtension,
|
||||||
|
#[any(size_range(0..1).lift())] extra_extensions: Vec<FileExtension>,
|
||||||
|
) {
|
||||||
|
let temp_dir = tempdir().unwrap();
|
||||||
|
let root_path = temp_dir.path();
|
||||||
|
|
||||||
|
let src_files_path = root_path.join("src_files");
|
||||||
|
fs::create_dir_all(&src_files_path).unwrap();
|
||||||
|
|
||||||
|
["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| src_files_path.join(f))
|
||||||
|
.for_each(|path| {
|
||||||
|
let mut file = fs::File::create(&path).unwrap();
|
||||||
|
file.write_all("Some content".as_bytes()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let input_files = src_files_path
|
||||||
|
.read_dir()
|
||||||
|
.unwrap()
|
||||||
|
.map(|entry| entry.unwrap().path())
|
||||||
|
.collect::<Vec<PathBuf>>();
|
||||||
|
|
||||||
|
let archive = &root_path.join(format!("archive.{}", merge_extensions(&ext, extra_extensions)));
|
||||||
|
|
||||||
|
let output_path = root_path.join("archive");
|
||||||
|
assert!(!output_path.exists());
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.arg("compress")
|
||||||
|
.args(input_files)
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
crate::utils::cargo_bin()
|
||||||
|
.current_dir(root_path)
|
||||||
|
.arg("decompress")
|
||||||
|
.arg("--no-smart-unpack")
|
||||||
|
.arg(archive)
|
||||||
|
.assert()
|
||||||
|
.success();
|
||||||
|
|
||||||
|
assert!(output_path.exists(), "Output directory does not exist");
|
||||||
|
|
||||||
|
assert_same_directory(src_files_path, output_path, false);
|
||||||
|
}
|
||||||
|
|
||||||
#[proptest(cases = 25)]
|
#[proptest(cases = 25)]
|
||||||
fn multiple_files_with_disabled_smart_unpack_by_dir(
|
fn multiple_files_with_disabled_smart_unpack_by_dir(
|
||||||
ext: DirectoryExtension,
|
ext: DirectoryExtension,
|
||||||
@ -490,10 +685,9 @@ fn symlink_pack_and_unpack(
|
|||||||
let mut files_path = ["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
|
let mut files_path = ["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|f| src_files_path.join(f))
|
.map(|f| src_files_path.join(f))
|
||||||
.map(|path| {
|
.inspect(|path| {
|
||||||
let mut file = fs::File::create(&path).unwrap();
|
let mut file = fs::File::create(path).unwrap();
|
||||||
file.write_all("Some content".as_bytes()).unwrap();
|
file.write_all("Some content".as_bytes()).unwrap();
|
||||||
path
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user