mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 11:35:45 +00:00
Introduce new type for policy on how to handle questions
This commit is contained in:
parent
a46fa1fb38
commit
10f7462b8b
@ -11,13 +11,13 @@ use walkdir::WalkDir;
|
||||
|
||||
use crate::{
|
||||
info,
|
||||
utils::{self, Bytes},
|
||||
utils::{self, Bytes, QuestionPolicy},
|
||||
};
|
||||
|
||||
pub fn unpack_archive(
|
||||
reader: Box<dyn Read>,
|
||||
output_folder: &Path,
|
||||
skip_questions_positively: Option<bool>,
|
||||
question_policy: QuestionPolicy,
|
||||
) -> crate::Result<Vec<PathBuf>> {
|
||||
let mut archive = tar::Archive::new(reader);
|
||||
|
||||
@ -26,7 +26,7 @@ pub fn unpack_archive(
|
||||
let mut file = file?;
|
||||
|
||||
let file_path = output_folder.join(file.path()?);
|
||||
if file_path.exists() && !utils::user_wants_to_overwrite(&file_path, skip_questions_positively)? {
|
||||
if file_path.exists() && !utils::user_wants_to_overwrite(&file_path, question_policy)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use zip::{self, read::ZipFile, ZipArchive};
|
||||
|
||||
use crate::{
|
||||
info,
|
||||
utils::{self, dir_is_empty,strip_cur_dir, Bytes},
|
||||
utils::{self, dir_is_empty, strip_cur_dir, Bytes, QuestionPolicy},
|
||||
};
|
||||
|
||||
use self::utf8::get_invalid_utf8_paths;
|
||||
@ -20,7 +20,7 @@ use self::utf8::get_invalid_utf8_paths;
|
||||
pub fn unpack_archive<R>(
|
||||
mut archive: ZipArchive<R>,
|
||||
into: &Path,
|
||||
skip_questions_positively: Option<bool>,
|
||||
question_policy: QuestionPolicy,
|
||||
) -> crate::Result<Vec<PathBuf>>
|
||||
where
|
||||
R: Read + Seek,
|
||||
@ -34,7 +34,7 @@ where
|
||||
};
|
||||
|
||||
let file_path = into.join(file_path);
|
||||
if file_path.exists() && !utils::user_wants_to_overwrite(&file_path, skip_questions_positively)? {
|
||||
if file_path.exists() && !utils::user_wants_to_overwrite(&file_path, question_policy)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ use std::{
|
||||
|
||||
use clap::{Parser, ValueHint};
|
||||
|
||||
pub use crate::utils::QuestionPolicy;
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
@ -53,18 +54,18 @@ pub enum Subcommand {
|
||||
impl Opts {
|
||||
/// A helper method that calls `clap::Parser::parse` and then translates relative paths to absolute.
|
||||
/// Also determines if the user wants to skip questions or not
|
||||
pub fn parse_args() -> crate::Result<(Self, Option<bool>)> {
|
||||
pub fn parse_args() -> crate::Result<(Self, QuestionPolicy)> {
|
||||
let mut opts: Self = Self::parse();
|
||||
|
||||
let (Subcommand::Compress { files, .. } | Subcommand::Decompress { files, .. }) = &mut opts.cmd;
|
||||
*files = canonicalize_files(files)?;
|
||||
|
||||
let skip_questions_positively = if opts.yes {
|
||||
Some(true)
|
||||
QuestionPolicy::AlwaysYes
|
||||
} else if opts.no {
|
||||
Some(false)
|
||||
QuestionPolicy::AlwaysNo
|
||||
} else {
|
||||
None
|
||||
QuestionPolicy::Ask
|
||||
};
|
||||
|
||||
Ok((opts, skip_questions_positively))
|
||||
|
@ -21,7 +21,7 @@ use crate::{
|
||||
info,
|
||||
utils::nice_directory_display,
|
||||
utils::to_utf,
|
||||
utils::{self, dir_is_empty},
|
||||
utils::{self, dir_is_empty, QuestionPolicy},
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -38,7 +38,7 @@ fn represents_several_files(files: &[PathBuf]) -> bool {
|
||||
files.iter().any(is_non_empty_dir) || files.len() > 1
|
||||
}
|
||||
|
||||
pub fn run(args: Opts, skip_questions_positively: Option<bool>) -> crate::Result<()> {
|
||||
pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> {
|
||||
match args.cmd {
|
||||
Subcommand::Compress { files, output: output_path } => {
|
||||
// Formats from path extension, like "file.tar.gz.xz" -> vec![Tar, Gzip, Lzma]
|
||||
@ -94,7 +94,7 @@ pub fn run(args: Opts, skip_questions_positively: Option<bool>) -> crate::Result
|
||||
return Err(Error::with_reason(reason));
|
||||
}
|
||||
|
||||
if output_path.exists() && !utils::user_wants_to_overwrite(&output_path, skip_questions_positively)? {
|
||||
if output_path.exists() && !utils::user_wants_to_overwrite(&output_path, question_policy)? {
|
||||
// User does not want to overwrite this file
|
||||
return Ok(());
|
||||
}
|
||||
@ -176,7 +176,7 @@ pub fn run(args: Opts, skip_questions_positively: Option<bool>) -> crate::Result
|
||||
let output_folder = output_folder.as_ref().map(|path| path.as_ref());
|
||||
|
||||
for ((input_path, formats), file_name) in files.iter().zip(formats).zip(output_paths) {
|
||||
decompress_file(input_path, formats, output_folder, file_name, skip_questions_positively)?;
|
||||
decompress_file(input_path, formats, output_folder, file_name, question_policy)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -289,7 +289,7 @@ fn decompress_file(
|
||||
formats: Vec<extension::CompressionFormat>,
|
||||
output_folder: Option<&Path>,
|
||||
file_name: &Path,
|
||||
skip_questions_positively: Option<bool>,
|
||||
question_policy: QuestionPolicy,
|
||||
) -> crate::Result<()> {
|
||||
// TODO: improve error message
|
||||
let reader = fs::File::open(&input_file_path)?;
|
||||
@ -311,7 +311,7 @@ fn decompress_file(
|
||||
if let [Zip] = *formats.as_slice() {
|
||||
utils::create_dir_if_non_existent(output_folder)?;
|
||||
let zip_archive = zip::ZipArchive::new(reader)?;
|
||||
let _files = crate::archive::zip::unpack_archive(zip_archive, output_folder, skip_questions_positively)?;
|
||||
let _files = crate::archive::zip::unpack_archive(zip_archive, output_folder, question_policy)?;
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder));
|
||||
return Ok(());
|
||||
}
|
||||
@ -349,27 +349,27 @@ fn decompress_file(
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_path));
|
||||
}
|
||||
Tar => {
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, skip_questions_positively)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?;
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder));
|
||||
}
|
||||
Tgz => {
|
||||
let reader = chain_reader_decoder(&Gzip, reader)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, skip_questions_positively)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?;
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder));
|
||||
}
|
||||
Tbz => {
|
||||
let reader = chain_reader_decoder(&Bzip, reader)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, skip_questions_positively)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?;
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder));
|
||||
}
|
||||
Tlzma => {
|
||||
let reader = chain_reader_decoder(&Lzma, reader)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, skip_questions_positively)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?;
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder));
|
||||
}
|
||||
Tzst => {
|
||||
let reader = chain_reader_decoder(&Zstd, reader)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, skip_questions_positively)?;
|
||||
let _ = crate::archive::tar::unpack_archive(reader, output_folder, question_policy)?;
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder));
|
||||
}
|
||||
Zip => {
|
||||
@ -384,7 +384,7 @@ fn decompress_file(
|
||||
io::copy(&mut reader, &mut vec)?;
|
||||
let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?;
|
||||
|
||||
let _ = crate::archive::zip::unpack_archive(zip_archive, output_folder, skip_questions_positively)?;
|
||||
let _ = crate::archive::zip::unpack_archive(zip_archive, output_folder, question_policy)?;
|
||||
|
||||
info!("Successfully decompressed archive in {}.", nice_directory_display(output_folder));
|
||||
}
|
||||
|
21
src/utils.rs
21
src/utils.rs
@ -43,11 +43,11 @@ pub fn cd_into_same_dir_as(filename: &Path) -> crate::Result<PathBuf> {
|
||||
Ok(previous_location)
|
||||
}
|
||||
|
||||
pub fn user_wants_to_overwrite(path: &Path, skip_questions_positively: Option<bool>) -> crate::Result<bool> {
|
||||
match skip_questions_positively {
|
||||
Some(true) => Ok(true),
|
||||
Some(false) => Ok(false),
|
||||
None => {
|
||||
pub fn user_wants_to_overwrite(path: &Path, question_policy: QuestionPolicy) -> crate::Result<bool> {
|
||||
match question_policy {
|
||||
QuestionPolicy::AlwaysYes => Ok(true),
|
||||
QuestionPolicy::AlwaysNo => Ok(false),
|
||||
QuestionPolicy::Ask => {
|
||||
let path = to_utf(strip_cur_dir(path));
|
||||
let path = Some(path.as_str());
|
||||
let placeholder = Some("FILE");
|
||||
@ -126,6 +126,17 @@ impl std::fmt::Display for Bytes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
/// How overwrite questions should be handled
|
||||
pub enum QuestionPolicy {
|
||||
/// Ask ever time
|
||||
Ask,
|
||||
/// Skip overwrite questions positively
|
||||
AlwaysYes,
|
||||
/// Skip overwrite questions negatively
|
||||
AlwaysNo,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -8,7 +8,7 @@ use std::{
|
||||
};
|
||||
|
||||
use ouch::{
|
||||
cli::{Opts, Subcommand},
|
||||
cli::{Opts, QuestionPolicy, Subcommand},
|
||||
commands::run,
|
||||
};
|
||||
use rand::{rngs::SmallRng, RngCore, SeedableRng};
|
||||
@ -183,7 +183,7 @@ fn extract_files(archive_path: &Path) -> Vec<PathBuf> {
|
||||
output: Some(extraction_output_folder.clone()),
|
||||
},
|
||||
};
|
||||
run(command, None).expect("Failed to extract");
|
||||
run(command, QuestionPolicy::Ask).expect("Failed to extract");
|
||||
|
||||
fs::read_dir(extraction_output_folder).unwrap().map(Result::unwrap).map(|entry| entry.path()).collect()
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use std::{
|
||||
};
|
||||
|
||||
use ouch::{
|
||||
cli::{Opts, Subcommand},
|
||||
cli::{Opts, QuestionPolicy, Subcommand},
|
||||
commands::run,
|
||||
};
|
||||
|
||||
@ -30,7 +30,7 @@ pub fn compress_files(at: &Path, paths_to_compress: &[PathBuf], format: &str) ->
|
||||
no: false,
|
||||
cmd: Subcommand::Compress { files: paths_to_compress.to_vec(), output: archive_path.clone() },
|
||||
};
|
||||
run(command, None).expect("Failed to compress test dummy files");
|
||||
run(command, QuestionPolicy::Ask).expect("Failed to compress test dummy files");
|
||||
|
||||
archive_path
|
||||
}
|
||||
@ -55,7 +55,7 @@ pub fn extract_files(archive_path: &Path) -> Vec<PathBuf> {
|
||||
output: Some(extraction_output_folder.clone()),
|
||||
},
|
||||
};
|
||||
run(command, None).expect("Failed to extract");
|
||||
run(command, QuestionPolicy::Ask).expect("Failed to extract");
|
||||
|
||||
fs::read_dir(extraction_output_folder).unwrap().map(Result::unwrap).map(|entry| entry.path()).collect()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user