mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 19:45:29 +00:00
intro merge action in decompression
Signed-off-by: tommady <tommady@users.noreply.github.com>
This commit is contained in:
parent
267ce7672e
commit
dd81c0c449
@ -18,8 +18,6 @@ pub fn unpack_archive(
|
|||||||
password: Option<&[u8]>,
|
password: Option<&[u8]>,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
) -> crate::Result<usize> {
|
) -> crate::Result<usize> {
|
||||||
assert!(output_folder.read_dir().expect("dir exists").next().is_none());
|
|
||||||
|
|
||||||
let archive = match password {
|
let archive = match password {
|
||||||
Some(password) => Archive::with_password(archive_path, password),
|
Some(password) => Archive::with_password(archive_path, password),
|
||||||
None => Archive::new(archive_path),
|
None => Archive::new(archive_path),
|
||||||
|
@ -24,7 +24,6 @@ use crate::{
|
|||||||
/// Unpacks the archive given by `archive` into the folder given by `into`.
|
/// Unpacks the archive given by `archive` into the folder given by `into`.
|
||||||
/// Assumes that output_folder is empty
|
/// Assumes that output_folder is empty
|
||||||
pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool) -> crate::Result<usize> {
|
pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool) -> crate::Result<usize> {
|
||||||
assert!(output_folder.read_dir().expect("dir exists").next().is_none());
|
|
||||||
let mut archive = tar::Archive::new(reader);
|
let mut archive = tar::Archive::new(reader);
|
||||||
|
|
||||||
let mut files_unpacked = 0;
|
let mut files_unpacked = 0;
|
||||||
|
@ -37,8 +37,6 @@ pub fn unpack_archive<R>(
|
|||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
assert!(output_folder.read_dir().expect("dir exists").next().is_none());
|
|
||||||
|
|
||||||
let mut unpacked_files = 0;
|
let mut unpacked_files = 0;
|
||||||
|
|
||||||
for idx in 0..archive.len() {
|
for idx in 0..archive.len() {
|
||||||
|
@ -137,7 +137,11 @@ pub fn decompress_file(options: DecompressOptions) -> crate::Result<()> {
|
|||||||
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
|
Gzip | Bzip | Bzip3 | Lz4 | Lzma | Snappy | Zstd | Brotli => {
|
||||||
reader = chain_reader_decoder(&first_extension, reader)?;
|
reader = chain_reader_decoder(&first_extension, reader)?;
|
||||||
|
|
||||||
let mut writer = match utils::ask_to_create_file(&options.output_file_path, options.question_policy)? {
|
let mut writer = match utils::ask_to_create_file(
|
||||||
|
&options.output_file_path,
|
||||||
|
options.question_policy,
|
||||||
|
QuestionAction::Decompression,
|
||||||
|
)? {
|
||||||
Some(file) => file,
|
Some(file) => file,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
@ -318,7 +322,7 @@ fn unpack(
|
|||||||
let output_dir_cleaned = if is_valid_output_dir {
|
let output_dir_cleaned = if is_valid_output_dir {
|
||||||
output_dir.to_owned()
|
output_dir.to_owned()
|
||||||
} else {
|
} else {
|
||||||
match utils::resolve_path_conflict(output_dir, question_policy)? {
|
match utils::resolve_path_conflict(output_dir, question_policy, QuestionAction::Decompression)? {
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => return Ok(ControlFlow::Break(())),
|
None => return Ok(ControlFlow::Break(())),
|
||||||
}
|
}
|
||||||
@ -374,7 +378,7 @@ fn smart_unpack(
|
|||||||
|
|
||||||
// Before moving, need to check if a file with the same name already exists
|
// Before moving, need to check if a file with the same name already exists
|
||||||
// If it does, need to ask the user what to do
|
// If it does, need to ask the user what to do
|
||||||
new_path = match utils::resolve_path_conflict(&new_path, question_policy)? {
|
new_path = match utils::resolve_path_conflict(&new_path, question_policy, QuestionAction::Decompression)? {
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => return Ok(ControlFlow::Break(())),
|
None => return Ok(ControlFlow::Break(())),
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,7 @@ use crate::{
|
|||||||
list::ListOptions,
|
list::ListOptions,
|
||||||
utils::{
|
utils::{
|
||||||
self, colors::*, is_path_stdin, logger::info_accessible, path_to_str, EscapedPathDisplay, FileVisibilityPolicy,
|
self, colors::*, is_path_stdin, logger::info_accessible, path_to_str, EscapedPathDisplay, FileVisibilityPolicy,
|
||||||
|
QuestionAction,
|
||||||
},
|
},
|
||||||
CliArgs, QuestionPolicy,
|
CliArgs, QuestionPolicy,
|
||||||
};
|
};
|
||||||
@ -91,10 +92,11 @@ pub fn run(
|
|||||||
)?;
|
)?;
|
||||||
check::check_archive_formats_position(&formats, &output_path)?;
|
check::check_archive_formats_position(&formats, &output_path)?;
|
||||||
|
|
||||||
let output_file = match utils::ask_to_create_file(&output_path, question_policy)? {
|
let output_file =
|
||||||
Some(writer) => writer,
|
match utils::ask_to_create_file(&output_path, question_policy, QuestionAction::Compression)? {
|
||||||
None => return Ok(()),
|
Some(writer) => writer,
|
||||||
};
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
let level = if fast {
|
let level = if fast {
|
||||||
Some(1) // Lowest level of compression
|
Some(1) // Lowest level of compression
|
||||||
|
@ -11,7 +11,7 @@ use fs_err as fs;
|
|||||||
use super::{question::FileConflitOperation, user_wants_to_overwrite};
|
use super::{question::FileConflitOperation, user_wants_to_overwrite};
|
||||||
use crate::{
|
use crate::{
|
||||||
extension::Extension,
|
extension::Extension,
|
||||||
utils::{logger::info_accessible, EscapedPathDisplay},
|
utils::{logger::info_accessible, EscapedPathDisplay, QuestionAction},
|
||||||
QuestionPolicy,
|
QuestionPolicy,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,9 +26,13 @@ pub fn is_path_stdin(path: &Path) -> bool {
|
|||||||
/// * `Ok(None)` means the user wants to cancel the operation
|
/// * `Ok(None)` means the user wants to cancel the operation
|
||||||
/// * `Ok(Some(path))` returns a valid PathBuf without any another file or directory with the same name
|
/// * `Ok(Some(path))` returns a valid PathBuf without any another file or directory with the same name
|
||||||
/// * `Err(_)` is an error
|
/// * `Err(_)` is an error
|
||||||
pub fn resolve_path_conflict(path: &Path, question_policy: QuestionPolicy) -> crate::Result<Option<PathBuf>> {
|
pub fn resolve_path_conflict(
|
||||||
|
path: &Path,
|
||||||
|
question_policy: QuestionPolicy,
|
||||||
|
question_action: QuestionAction,
|
||||||
|
) -> crate::Result<Option<PathBuf>> {
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
match user_wants_to_overwrite(path, question_policy)? {
|
match user_wants_to_overwrite(path, question_policy, question_action)? {
|
||||||
FileConflitOperation::Cancel => Ok(None),
|
FileConflitOperation::Cancel => Ok(None),
|
||||||
FileConflitOperation::Overwrite => {
|
FileConflitOperation::Overwrite => {
|
||||||
remove_file_or_dir(path)?;
|
remove_file_or_dir(path)?;
|
||||||
@ -38,6 +42,7 @@ pub fn resolve_path_conflict(path: &Path, question_policy: QuestionPolicy) -> cr
|
|||||||
let renamed_path = rename_for_available_filename(path);
|
let renamed_path = rename_for_available_filename(path);
|
||||||
Ok(Some(renamed_path))
|
Ok(Some(renamed_path))
|
||||||
}
|
}
|
||||||
|
FileConflitOperation::Merge => Ok(Some(path.to_path_buf())),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(path.to_path_buf()))
|
Ok(Some(path.to_path_buf()))
|
||||||
|
@ -48,49 +48,71 @@ pub enum FileConflitOperation {
|
|||||||
/// Rename the file
|
/// Rename the file
|
||||||
/// It'll be put "_1" at the end of the filename or "_2","_3","_4".. if already exists
|
/// It'll be put "_1" at the end of the filename or "_2","_3","_4".. if already exists
|
||||||
Rename,
|
Rename,
|
||||||
|
/// Merge duplicated files
|
||||||
|
Merge,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if QuestionPolicy flags were set, otherwise, ask user if they want to overwrite.
|
/// Check if QuestionPolicy flags were set, otherwise, ask user if they want to overwrite.
|
||||||
pub fn user_wants_to_overwrite(path: &Path, question_policy: QuestionPolicy) -> crate::Result<FileConflitOperation> {
|
pub fn user_wants_to_overwrite(
|
||||||
|
path: &Path,
|
||||||
|
question_policy: QuestionPolicy,
|
||||||
|
question_action: QuestionAction,
|
||||||
|
) -> crate::Result<FileConflitOperation> {
|
||||||
use FileConflitOperation as Op;
|
use FileConflitOperation as Op;
|
||||||
|
|
||||||
match question_policy {
|
match question_policy {
|
||||||
QuestionPolicy::AlwaysYes => Ok(Op::Overwrite),
|
QuestionPolicy::AlwaysYes => Ok(Op::Overwrite),
|
||||||
QuestionPolicy::AlwaysNo => Ok(Op::Cancel),
|
QuestionPolicy::AlwaysNo => Ok(Op::Cancel),
|
||||||
QuestionPolicy::Ask => ask_file_conflict_operation(path),
|
QuestionPolicy::Ask => ask_file_conflict_operation(path, question_action),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask the user if they want to overwrite or rename the &Path
|
/// Ask the user if they want to overwrite or rename the &Path
|
||||||
pub fn ask_file_conflict_operation(path: &Path) -> Result<FileConflitOperation> {
|
pub fn ask_file_conflict_operation(path: &Path, question_action: QuestionAction) -> Result<FileConflitOperation> {
|
||||||
use FileConflitOperation as Op;
|
use FileConflitOperation as Op;
|
||||||
|
|
||||||
let path = path_to_str(strip_cur_dir(path));
|
let path = path_to_str(strip_cur_dir(path));
|
||||||
|
match question_action {
|
||||||
ChoicePrompt::new(
|
QuestionAction::Compression => ChoicePrompt::new(
|
||||||
format!("Do you want to overwrite {path}?"),
|
format!("Do you want to overwrite {path}?"),
|
||||||
[
|
[
|
||||||
("yes", Op::Overwrite, *colors::GREEN),
|
("yes", Op::Overwrite, *colors::GREEN),
|
||||||
("no", Op::Cancel, *colors::RED),
|
("no", Op::Cancel, *colors::RED),
|
||||||
("rename", Op::Rename, *colors::BLUE),
|
("rename", Op::Rename, *colors::BLUE),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.ask()
|
.ask(),
|
||||||
|
QuestionAction::Decompression => ChoicePrompt::new(
|
||||||
|
format!("Do you want to overwrite {path}?"),
|
||||||
|
[
|
||||||
|
("yes", Op::Overwrite, *colors::GREEN),
|
||||||
|
("no", Op::Cancel, *colors::RED),
|
||||||
|
("rename", Op::Rename, *colors::BLUE),
|
||||||
|
("merge", Op::Merge, *colors::ORANGE),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.ask(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create the file if it doesn't exist and if it does then ask to overwrite it.
|
/// Create the file if it doesn't exist and if it does then ask to overwrite it.
|
||||||
/// If the user doesn't want to overwrite then we return [`Ok(None)`]
|
/// If the user doesn't want to overwrite then we return [`Ok(None)`]
|
||||||
pub fn ask_to_create_file(path: &Path, question_policy: QuestionPolicy) -> Result<Option<fs::File>> {
|
pub fn ask_to_create_file(
|
||||||
|
path: &Path,
|
||||||
|
question_policy: QuestionPolicy,
|
||||||
|
question_action: QuestionAction,
|
||||||
|
) -> Result<Option<fs::File>> {
|
||||||
match fs::OpenOptions::new().write(true).create_new(true).open(path) {
|
match fs::OpenOptions::new().write(true).create_new(true).open(path) {
|
||||||
Ok(w) => Ok(Some(w)),
|
Ok(w) => Ok(Some(w)),
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
|
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
|
||||||
let action = match question_policy {
|
let action = match question_policy {
|
||||||
QuestionPolicy::AlwaysYes => FileConflitOperation::Overwrite,
|
QuestionPolicy::AlwaysYes => FileConflitOperation::Overwrite,
|
||||||
QuestionPolicy::AlwaysNo => FileConflitOperation::Cancel,
|
QuestionPolicy::AlwaysNo => FileConflitOperation::Cancel,
|
||||||
QuestionPolicy::Ask => ask_file_conflict_operation(path)?,
|
QuestionPolicy::Ask => ask_file_conflict_operation(path, question_action)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
|
FileConflitOperation::Merge => Ok(Some(fs::File::create(path)?)),
|
||||||
FileConflitOperation::Overwrite => {
|
FileConflitOperation::Overwrite => {
|
||||||
utils::remove_file_or_dir(path)?;
|
utils::remove_file_or_dir(path)?;
|
||||||
Ok(Some(fs::File::create(path)?))
|
Ok(Some(fs::File::create(path)?))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user