From 7954eb07fdcd13a14416aa9e8dc3179e59429a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Rodrigues=20Miguel?= Date: Sun, 28 Mar 2021 13:56:00 -0300 Subject: [PATCH] decompressors/zip: Add confirmation dialog for file overwriting --- src/decompressors/zip.rs | 47 ++++++++++++++++++++++++---------------- src/dialogs.rs | 47 ++++++++++++++++++++++++++++++++++++++++ src/error.rs | 1 + src/main.rs | 12 ++++++++++ 4 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 src/dialogs.rs diff --git a/src/decompressors/zip.rs b/src/decompressors/zip.rs index 01f8a65..6e414d2 100644 --- a/src/decompressors/zip.rs +++ b/src/decompressors/zip.rs @@ -8,7 +8,7 @@ use colored::Colorize; use zip::{self, read::ZipFile, ZipArchive}; use super::decompressor::{DecompressionResult, Decompressor}; -use crate::{file::File, utils}; +use crate::{dialogs::Confirmation, file::File, utils}; #[cfg(unix)] fn __unix_set_permissions(file_path: &PathBuf, file: &ZipFile) { @@ -41,6 +41,7 @@ impl ZipDecompressor { where T: Read + Seek, { + let confirm = Confirmation::new("Do you want to overwrite 'FILE'?", Some("FILE")); let mut unpacked_files = vec![]; for idx in 0..archive.len() { let mut file = archive.by_index(idx)?; @@ -50,28 +51,36 @@ impl ZipDecompressor { }; let file_path = into.join(file_path); + if file_path.exists() { + let file_path_str = &*file_path.as_path().to_string_lossy(); + if confirm.ask(Some(file_path_str))? { + continue; + } + } Self::check_for_comments(&file); - let is_dir = (&*file.name()).ends_with('/'); - - if is_dir { - println!("File {} extracted to \"{}\"", idx, file_path.display()); - fs::create_dir_all(&file_path)?; - } else { - if let Some(p) = file_path.parent() { - if !p.exists() { - fs::create_dir_all(&p)?; - } + match (&*file.name()).ends_with('/') { + _is_dir @ true => { + println!("File {} extracted to \"{}\"", idx, file_path.display()); + fs::create_dir_all(&file_path)?; + } + _is_file @ false => { + if let Some(path) = file_path.parent() { + if !path.exists() { + fs::create_dir_all(&path)?; + } + } + println!( + "{}: \"{}\" extracted. ({} bytes)", + "info".yellow(), + file_path.display(), + file.size() + ); + + let mut output_file = fs::File::create(&file_path)?; + io::copy(&mut file, &mut output_file)?; } - println!( - "{}: \"{}\" extracted. ({} bytes)", - "info".yellow(), - file_path.display(), - file.size() - ); - let mut outfile = fs::File::create(&file_path)?; - io::copy(&mut file, &mut outfile)?; } #[cfg(unix)] diff --git a/src/dialogs.rs b/src/dialogs.rs new file mode 100644 index 0000000..b603b9a --- /dev/null +++ b/src/dialogs.rs @@ -0,0 +1,47 @@ +use std::io::{self, Write}; + +use colored::Colorize; + +pub struct Confirmation<'a> { + pub prompt: &'a str, + pub placeholder: Option<&'a str>, +} + +#[derive(Debug)] +pub struct Error; + +impl<'a> Confirmation<'a> { + pub fn new(prompt: &'a str, pattern: Option<&'a str>) -> Self { + Self { + prompt, + placeholder: pattern, + } + } + + pub fn ask(&self, substitute: Option<&'a str>) -> crate::Result { + let message = match (self.placeholder, substitute) { + (None, _) => self.prompt.into(), + (Some(_), None) => return Err(crate::Error::InternalError), + (Some(placeholder), Some(subs)) => self.prompt.replace(placeholder, subs), + }; + + loop { + print!("{} [{}/{}] ", message, "Y".bright_green(), "n".bright_red()); + io::stdout().flush()?; + + let mut answer = String::new(); + io::stdin().read_line(&mut answer)?; + let trimmed_answer = answer.trim().to_ascii_lowercase(); + + if trimmed_answer.is_empty() { + return Ok(true); + } + + match trimmed_answer.to_ascii_lowercase().as_ref() { + "y" | "yes" => return Ok(true), + "n" | "no" => return Ok(false), + _ => {} + } + } + } +} diff --git a/src/error.rs b/src/error.rs index 6680600..2b58a5c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -16,6 +16,7 @@ pub enum Error { PermissionDenied, UnsupportedZipArchive(&'static str), InputsMustHaveBeenDecompressible(PathBuf), + InternalError, } pub type Result = std::result::Result; diff --git a/src/main.rs b/src/main.rs index 6902876..a13504f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod cli; mod compressors; mod decompressors; +mod dialogs; mod error; mod evaluator; mod extension; @@ -18,3 +19,14 @@ fn main() -> crate::Result<()> { let command = cli::Command::try_from(matches)?; Evaluator::evaluate(command) } + +// fn main() -> crate::Result<()> { +// let dialog = dialogs::Confirmation::new("Do you want to overwrite 'FILE'?", Some("FILE")); + +// match dialog.ask(Some("file.tar.gz"))? { +// true => println!("deleting"), +// false => println!("keeping") +// }; + +// Ok(()) +// }