diff --git a/src/archive/rar.rs b/src/archive/rar.rs index 7b59bba..16c5737 100644 --- a/src/archive/rar.rs +++ b/src/archive/rar.rs @@ -4,7 +4,11 @@ use std::{path::Path, sync::mpsc::Sender}; use unrar::Archive; -use crate::{error::Error, list::FileInArchive, utils::message::PrintMessage}; +use crate::{ + error::Error, + list::FileInArchive, + utils::message::{MessageLevel, PrintMessage}, +}; /// Unpacks the archive given by `archive_path` into the folder given by `output_folder`. /// Assumes that output_folder is empty @@ -27,6 +31,7 @@ pub fn unpack_archive( .send(PrintMessage { contents: format!("{} extracted. ({})", entry.filename.display(), entry.unpacked_size), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } diff --git a/src/archive/sevenz.rs b/src/archive/sevenz.rs index 56a6650..2c5135a 100644 --- a/src/archive/sevenz.rs +++ b/src/archive/sevenz.rs @@ -12,7 +12,11 @@ use same_file::Handle; use crate::{ error::FinalError, - utils::{self, cd_into_same_dir_as, message::PrintMessage, Bytes, EscapedPathDisplay, FileVisibilityPolicy}, + utils::{ + self, cd_into_same_dir_as, + message::{MessageLevel, PrintMessage}, + Bytes, EscapedPathDisplay, FileVisibilityPolicy, + }, warning, }; @@ -44,10 +48,16 @@ where // If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion) if let Ok(handle) = &output_handle { if matches!(Handle::from_path(path), Ok(x) if &x == handle) { - warning!( - "The output file and the input file are the same: `{}`, skipping...", - output_path.display() - ); + log_sender + .send(PrintMessage { + contents: format!( + "The output file and the input file are the same: `{}`, skipping...", + output_path.display() + ), + accessible: true, + level: MessageLevel::Warning, + }) + .unwrap(); continue; } } @@ -61,6 +71,7 @@ where .send(PrintMessage { contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } @@ -124,6 +135,7 @@ where .send(PrintMessage { contents: format!("File {} extracted to \"{}\"", entry.name(), file_path.display()), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } @@ -136,6 +148,7 @@ where .send(PrintMessage { contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(entry.size()),), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } diff --git a/src/archive/tar.rs b/src/archive/tar.rs index 4c41b7f..c89db5d 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -14,7 +14,11 @@ use same_file::Handle; use crate::{ error::FinalError, list::FileInArchive, - utils::{self, message::PrintMessage, Bytes, EscapedPathDisplay, FileVisibilityPolicy}, + utils::{ + self, + message::{MessageLevel, PrintMessage}, + Bytes, EscapedPathDisplay, FileVisibilityPolicy, + }, warning, }; @@ -48,6 +52,7 @@ pub fn unpack_archive( Bytes::new(file.size()), ), accessible: false, + level: MessageLevel::Info, }) .unwrap(); @@ -116,10 +121,17 @@ where // If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion) if let Ok(handle) = &output_handle { if matches!(Handle::from_path(path), Ok(x) if &x == handle) { - warning!( - "The output file and the input file are the same: `{}`, skipping...", - output_path.display() - ); + log_sender + .send(PrintMessage { + contents: format!( + "The output file and the input file are the same: `{}`, skipping...", + output_path.display() + ), + accessible: true, + level: MessageLevel::Warning, + }) + .unwrap(); + continue; } } @@ -133,6 +145,7 @@ where .send(PrintMessage { contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 0439c6e..0df03ce 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -20,8 +20,9 @@ use crate::{ error::FinalError, list::FileInArchive, utils::{ - self, cd_into_same_dir_as, get_invalid_utf8_paths, message::PrintMessage, pretty_format_list_of_paths, - strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy, + self, cd_into_same_dir_as, get_invalid_utf8_paths, + message::{MessageLevel, PrintMessage}, + pretty_format_list_of_paths, strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy, }, warning, }; @@ -63,6 +64,7 @@ where .send(PrintMessage { contents: format!("File {} extracted to \"{}\"", idx, file_path.display()), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } @@ -82,6 +84,7 @@ where .send(PrintMessage { contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(file.size()),), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } @@ -188,10 +191,17 @@ where // If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion) if let Ok(handle) = &output_handle { if matches!(Handle::from_path(path), Ok(x) if &x == handle) { - warning!( - "The output file and the input file are the same: `{}`, skipping...", - output_path.display() - ); + log_sender + .send(PrintMessage { + contents: format!( + "The output file and the input file are the same: `{}`, skipping...", + output_path.display() + ), + accessible: true, + level: MessageLevel::Warning, + }) + .unwrap(); + continue; } } @@ -205,6 +215,7 @@ where .send(PrintMessage { contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)), accessible: false, + level: MessageLevel::Info, }) .unwrap(); } @@ -273,6 +284,7 @@ fn display_zip_comment_if_exists(file: &ZipFile, log_sender: Sender) { const ZIP_IN_MEMORY_LIMITATION_WARNING: &str = "\n\ \tThe format '.zip' is limited and cannot be (de)compressed using encoding streams.\n\ \tWhen using '.zip' with other formats, (de)compression must be done in-memory\n\ \tCareful, you might run out of RAM if the archive is too large!"; - warning!("{}", ZIP_IN_MEMORY_LIMITATION_WARNING); + log_sender + .send(PrintMessage { + contents: format!("{}", ZIP_IN_MEMORY_LIMITATION_WARNING), + accessible: true, + level: MessageLevel::Warning, + }) + .unwrap(); } /// Warn the user that (de)compressing this .7z archive might freeze their system. -fn warn_user_about_loading_sevenz_in_memory() { +fn warn_user_about_loading_sevenz_in_memory(log_sender: Sender) { const SEVENZ_IN_MEMORY_LIMITATION_WARNING: &str = "\n\ \tThe format '.7z' is limited and cannot be (de)compressed using encoding streams.\n\ \tWhen using '.7z' with other formats, (de)compression must be done in-memory\n\ \tCareful, you might run out of RAM if the archive is too large!"; - warning!("{}", SEVENZ_IN_MEMORY_LIMITATION_WARNING); + log_sender + .send(PrintMessage { + contents: format!("{}", SEVENZ_IN_MEMORY_LIMITATION_WARNING), + accessible: true, + level: MessageLevel::Warning, + }) + .unwrap(); } /// This function checks what command needs to be run and performs A LOT of ahead-of-time checks @@ -60,9 +80,37 @@ pub fn run( // Log received messages until all senders are dropped rayon::spawn(move || { + use utils::colors::{ORANGE, RESET, YELLOW}; + const BUFFER_SIZE: usize = 10; let mut buffer = Vec::::with_capacity(BUFFER_SIZE); + // TODO: Move this out to utils + fn map_message(msg: &PrintMessage) -> Option { + match msg.level { + MessageLevel::Info => { + if msg.accessible { + if is_running_in_accessible_mode() { + Some(format!("{}Info:{} {}", *YELLOW, *RESET, msg.contents)) + } else { + Some(format!("{}[INFO]{} {}", *YELLOW, *RESET, msg.contents)) + } + } else if !is_running_in_accessible_mode() { + Some(format!("{}[INFO]{} {}", *YELLOW, *RESET, msg.contents)) + } else { + None + } + } + MessageLevel::Warning => { + if is_running_in_accessible_mode() { + Some(format!("{}Warning:{} ", *ORANGE, *RESET)) + } else { + Some(format!("{}[WARNING]{} ", *ORANGE, *RESET)) + } + } + } + } + loop { let msg = log_receiver.recv(); @@ -71,15 +119,20 @@ pub fn run( // Print messages if buffer is full otherwise append to it if buffer.len() == BUFFER_SIZE { let mut tmp = buffer.join("\n"); - tmp.push_str(&msg.contents); + if let Some(msg) = map_message(&msg) { + tmp.push_str(&msg); + } + + // TODO: Send this to stderr println!("{}", tmp); buffer.clear(); - } else { - buffer.push(msg.contents); + } else if let Some(msg) = map_message(&msg) { + buffer.push(msg); } } else { // All senders have been dropped + // TODO: Send this to stderr println!("{}", buffer.join("\n")); // Wake up the main thread @@ -111,7 +164,7 @@ pub fn run( let parsed_formats = parse_format(&formats)?; (Some(formats), parsed_formats) } - None => (None, extension::extensions_from_path(&output_path)), + None => (None, extension::extensions_from_path(&output_path, log_sender.clone())), }; check::check_invalid_compression_with_non_archive_format( @@ -156,6 +209,7 @@ pub fn run( .send(PrintMessage { contents: format!("Successfully compressed '{}'.", to_utf(&output_path)), accessible: true, + level: MessageLevel::Info, }) .unwrap(); } else { @@ -195,7 +249,8 @@ pub fn run( } } else { for path in files.iter() { - let (pathbase, mut file_formats) = extension::separate_known_extensions_from_name(path); + let (pathbase, mut file_formats) = + extension::separate_known_extensions_from_name(path, log_sender.clone()); if let ControlFlow::Break(_) = check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())? @@ -246,7 +301,7 @@ pub fn run( } } else { for path in files.iter() { - let mut file_formats = extension::extensions_from_path(path); + let mut file_formats = extension::extensions_from_path(path, log_sender.clone()); if let ControlFlow::Break(_) = check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())? diff --git a/src/extension.rs b/src/extension.rs index d374ee1..782edf2 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -1,11 +1,15 @@ //! Our representation of all the supported compression formats. -use std::{ffi::OsStr, fmt, path::Path}; +use std::{ffi::OsStr, fmt, path::Path, sync::mpsc::Sender}; use bstr::ByteSlice; use self::CompressionFormat::*; -use crate::{error::Error, warning}; +use crate::{ + error::Error, + utils::message::{MessageLevel, PrintMessage}, + warning, +}; pub const SUPPORTED_EXTENSIONS: &[&str] = &[ "tar", @@ -169,7 +173,7 @@ pub fn parse_format(fmt: &OsStr) -> crate::Result> { /// Extracts extensions from a path. /// /// Returns both the remaining path and the list of extension objects -pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec) { +pub fn separate_known_extensions_from_name(path: &Path, log_sender: Sender) -> (&Path, Vec) { let mut extensions = vec![]; let Some(mut name) = path.file_name().and_then(<[u8] as ByteSlice>::from_os_str) else { @@ -184,7 +188,15 @@ pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec (&Path, Vec Vec { - let (_, extensions) = separate_known_extensions_from_name(path); +pub fn extensions_from_path(path: &Path, log_sender: Sender) -> Vec { + let (_, extensions) = separate_known_extensions_from_name(path, log_sender); extensions } @@ -252,9 +264,11 @@ mod tests { #[test] fn test_extensions_from_path() { + let (log_sender, _log_receiver) = std::sync::mpsc::channel::(); + let path = Path::new("bolovo.tar.gz"); - let extensions: Vec = extensions_from_path(path); + let extensions: Vec = extensions_from_path(path, log_sender); let formats: Vec = flatten_compression_formats(&extensions); assert_eq!(formats, vec![Tar, Gzip]); diff --git a/src/utils/fs.rs b/src/utils/fs.rs index e0c077b..6704cf7 100644 --- a/src/utils/fs.rs +++ b/src/utils/fs.rs @@ -9,7 +9,10 @@ use std::{ use fs_err as fs; -use super::{message::PrintMessage, user_wants_to_overwrite}; +use super::{ + message::{MessageLevel, PrintMessage}, + user_wants_to_overwrite, +}; use crate::{extension::Extension, utils::EscapedPathDisplay, QuestionPolicy}; /// Remove `path` asking the user to overwrite if necessary. @@ -46,6 +49,7 @@ pub fn create_dir_if_non_existent(path: &Path, log_sender: Sender) .send(PrintMessage { contents: format!("Directory {} created.", EscapedPathDisplay::new(path)), accessible: true, + level: MessageLevel::Info, }) .unwrap(); } diff --git a/src/utils/message.rs b/src/utils/message.rs index 582dae7..f5dfac0 100644 --- a/src/utils/message.rs +++ b/src/utils/message.rs @@ -19,4 +19,11 @@ pub struct PrintMessage { pub contents: String, pub accessible: bool, + pub level: MessageLevel, +} + +#[derive(Debug, PartialEq)] +pub enum MessageLevel { + Info, + Warning, }