Introduce new type for policy on how to handle questions

This commit is contained in:
Anton Hermann 2021-10-21 23:16:01 +02:00
parent a46fa1fb38
commit 10f7462b8b
7 changed files with 44 additions and 32 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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))

View File

@ -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));
}

View File

@ -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::*;

View File

@ -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()
}

View File

@ -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()
}