Add levels and fix output

This commit is contained in:
Antonios Barotsis 2024-03-11 23:00:51 +01:00 committed by João Marcos
parent 93752d5fb5
commit 380893b6df
10 changed files with 185 additions and 45 deletions

View File

@ -4,7 +4,11 @@ use std::{path::Path, sync::mpsc::Sender};
use unrar::Archive; 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`. /// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
/// Assumes that output_folder is empty /// Assumes that output_folder is empty
@ -27,6 +31,7 @@ pub fn unpack_archive(
.send(PrintMessage { .send(PrintMessage {
contents: format!("{} extracted. ({})", entry.filename.display(), entry.unpacked_size), contents: format!("{} extracted. ({})", entry.filename.display(), entry.unpacked_size),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }

View File

@ -12,7 +12,11 @@ use same_file::Handle;
use crate::{ use crate::{
error::FinalError, 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, 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 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 let Ok(handle) = &output_handle {
if matches!(Handle::from_path(path), Ok(x) if &x == handle) { if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
warning!( log_sender
"The output file and the input file are the same: `{}`, skipping...", .send(PrintMessage {
output_path.display() contents: format!(
); "The output file and the input file are the same: `{}`, skipping...",
output_path.display()
),
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();
continue; continue;
} }
} }
@ -61,6 +71,7 @@ where
.send(PrintMessage { .send(PrintMessage {
contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)), contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }
@ -124,6 +135,7 @@ where
.send(PrintMessage { .send(PrintMessage {
contents: format!("File {} extracted to \"{}\"", entry.name(), file_path.display()), contents: format!("File {} extracted to \"{}\"", entry.name(), file_path.display()),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }
@ -136,6 +148,7 @@ where
.send(PrintMessage { .send(PrintMessage {
contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(entry.size()),), contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(entry.size()),),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }

View File

@ -14,7 +14,11 @@ use same_file::Handle;
use crate::{ use crate::{
error::FinalError, error::FinalError,
list::FileInArchive, list::FileInArchive,
utils::{self, message::PrintMessage, Bytes, EscapedPathDisplay, FileVisibilityPolicy}, utils::{
self,
message::{MessageLevel, PrintMessage},
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
},
warning, warning,
}; };
@ -48,6 +52,7 @@ pub fn unpack_archive(
Bytes::new(file.size()), Bytes::new(file.size()),
), ),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .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 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 let Ok(handle) = &output_handle {
if matches!(Handle::from_path(path), Ok(x) if &x == handle) { if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
warning!( log_sender
"The output file and the input file are the same: `{}`, skipping...", .send(PrintMessage {
output_path.display() contents: format!(
); "The output file and the input file are the same: `{}`, skipping...",
output_path.display()
),
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();
continue; continue;
} }
} }
@ -133,6 +145,7 @@ where
.send(PrintMessage { .send(PrintMessage {
contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)), contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }

View File

@ -20,8 +20,9 @@ use crate::{
error::FinalError, error::FinalError,
list::FileInArchive, list::FileInArchive,
utils::{ utils::{
self, cd_into_same_dir_as, get_invalid_utf8_paths, message::PrintMessage, pretty_format_list_of_paths, self, cd_into_same_dir_as, get_invalid_utf8_paths,
strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy, message::{MessageLevel, PrintMessage},
pretty_format_list_of_paths, strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy,
}, },
warning, warning,
}; };
@ -63,6 +64,7 @@ where
.send(PrintMessage { .send(PrintMessage {
contents: format!("File {} extracted to \"{}\"", idx, file_path.display()), contents: format!("File {} extracted to \"{}\"", idx, file_path.display()),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }
@ -82,6 +84,7 @@ where
.send(PrintMessage { .send(PrintMessage {
contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(file.size()),), contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(file.size()),),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .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 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 let Ok(handle) = &output_handle {
if matches!(Handle::from_path(path), Ok(x) if &x == handle) { if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
warning!( log_sender
"The output file and the input file are the same: `{}`, skipping...", .send(PrintMessage {
output_path.display() contents: format!(
); "The output file and the input file are the same: `{}`, skipping...",
output_path.display()
),
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();
continue; continue;
} }
} }
@ -205,6 +215,7 @@ where
.send(PrintMessage { .send(PrintMessage {
contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)), contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)),
accessible: false, accessible: false,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }
@ -273,6 +284,7 @@ fn display_zip_comment_if_exists(file: &ZipFile, log_sender: Sender<PrintMessage
.send(PrintMessage { .send(PrintMessage {
contents: format!("Found comment in {}: {}", file.name(), comment), contents: format!("Found comment in {}: {}", file.name(), comment),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }

View File

@ -13,8 +13,8 @@ use crate::{
error::FinalError, error::FinalError,
extension::{build_archive_file_suggestion, Extension, PRETTY_SUPPORTED_ALIASES, PRETTY_SUPPORTED_EXTENSIONS}, extension::{build_archive_file_suggestion, Extension, PRETTY_SUPPORTED_ALIASES, PRETTY_SUPPORTED_EXTENSIONS},
utils::{ utils::{
message::PrintMessage, pretty_format_list_of_paths, try_infer_extension, user_wants_to_continue, message::{MessageLevel, PrintMessage},
EscapedPathDisplay, pretty_format_list_of_paths, try_infer_extension, user_wants_to_continue, EscapedPathDisplay,
}, },
warning, QuestionAction, QuestionPolicy, Result, warning, QuestionAction, QuestionPolicy, Result,
}; };
@ -41,6 +41,7 @@ pub fn check_mime_type(
.send(PrintMessage { .send(PrintMessage {
contents: format!("Detected file: `{}` extension as `{}`", path.display(), detected_format), contents: format!("Detected file: `{}` extension as `{}`", path.display(), detected_format),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
if user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? { if user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? {
@ -58,11 +59,16 @@ pub fn check_mime_type(
.compression_formats .compression_formats
.ends_with(detected_format.compression_formats) .ends_with(detected_format.compression_formats)
{ {
warning!( log_sender
"The file extension: `{}` differ from the detected extension: `{}`", .send(PrintMessage {
outer_ext, contents: format!(
detected_format "The file extension: `{}` differ from the detected extension: `{}`",
); outer_ext, detected_format
),
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();
if !user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? { if !user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? {
return Ok(ControlFlow::Break(())); return Ok(ControlFlow::Break(()));
} }
@ -77,6 +83,7 @@ pub fn check_mime_type(
path.display() path.display()
), ),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }

View File

@ -14,7 +14,11 @@ use crate::{
CompressionFormat::{self, *}, CompressionFormat::{self, *},
Extension, Extension,
}, },
utils::{self, message::PrintMessage, nice_directory_display, user_wants_to_continue}, utils::{
self,
message::{MessageLevel, PrintMessage},
nice_directory_display, user_wants_to_continue,
},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY, QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
}; };
@ -73,6 +77,7 @@ pub fn decompress_file(
files_unpacked files_unpacked
), ),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
@ -230,12 +235,14 @@ pub fn decompress_file(
nice_directory_display(output_dir) nice_directory_display(output_dir)
), ),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
log_sender log_sender
.send(PrintMessage { .send(PrintMessage {
contents: format!("Files unpacked: {}", files_unpacked), contents: format!("Files unpacked: {}", files_unpacked),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
@ -265,6 +272,7 @@ fn smart_unpack(
nice_directory_display(temp_dir_path) nice_directory_display(temp_dir_path)
), ),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
@ -293,6 +301,7 @@ fn smart_unpack(
nice_directory_display(&correct_path) nice_directory_display(&correct_path)
), ),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} else { } else {
@ -311,6 +320,7 @@ fn smart_unpack(
nice_directory_display(output_file_path) nice_directory_display(output_file_path)
), ),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }

View File

@ -7,41 +7,61 @@ mod list;
use std::{ use std::{
ops::ControlFlow, ops::ControlFlow,
path::PathBuf, path::PathBuf,
sync::{mpsc::channel, Arc, Condvar, Mutex}, sync::{
mpsc::{channel, Sender},
Arc, Condvar, Mutex,
},
}; };
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use utils::colors; use utils::colors;
use crate::{ use crate::{
accessible::is_running_in_accessible_mode,
check, check,
cli::Subcommand, cli::Subcommand,
commands::{compress::compress_files, decompress::decompress_file, list::list_archive_contents}, commands::{compress::compress_files, decompress::decompress_file, list::list_archive_contents},
error::{Error, FinalError}, error::{Error, FinalError},
extension::{self, parse_format}, extension::{self, parse_format},
list::ListOptions, list::ListOptions,
utils::{self, message::PrintMessage, to_utf, EscapedPathDisplay, FileVisibilityPolicy}, utils::{
self,
message::{MessageLevel, PrintMessage},
to_utf, EscapedPathDisplay, FileVisibilityPolicy,
},
warning, CliArgs, QuestionPolicy, warning, CliArgs, QuestionPolicy,
}; };
/// Warn the user that (de)compressing this .zip archive might freeze their system. /// Warn the user that (de)compressing this .zip archive might freeze their system.
fn warn_user_about_loading_zip_in_memory() { fn warn_user_about_loading_zip_in_memory(log_sender: Sender<PrintMessage>) {
const ZIP_IN_MEMORY_LIMITATION_WARNING: &str = "\n\ const ZIP_IN_MEMORY_LIMITATION_WARNING: &str = "\n\
\tThe format '.zip' is limited and cannot be (de)compressed using encoding streams.\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\ \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!"; \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. /// 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<PrintMessage>) {
const SEVENZ_IN_MEMORY_LIMITATION_WARNING: &str = "\n\ const SEVENZ_IN_MEMORY_LIMITATION_WARNING: &str = "\n\
\tThe format '.7z' is limited and cannot be (de)compressed using encoding streams.\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\ \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!"; \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 /// 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 // Log received messages until all senders are dropped
rayon::spawn(move || { rayon::spawn(move || {
use utils::colors::{ORANGE, RESET, YELLOW};
const BUFFER_SIZE: usize = 10; const BUFFER_SIZE: usize = 10;
let mut buffer = Vec::<String>::with_capacity(BUFFER_SIZE); let mut buffer = Vec::<String>::with_capacity(BUFFER_SIZE);
// TODO: Move this out to utils
fn map_message(msg: &PrintMessage) -> Option<String> {
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 { loop {
let msg = log_receiver.recv(); let msg = log_receiver.recv();
@ -71,15 +119,20 @@ pub fn run(
// Print messages if buffer is full otherwise append to it // Print messages if buffer is full otherwise append to it
if buffer.len() == BUFFER_SIZE { if buffer.len() == BUFFER_SIZE {
let mut tmp = buffer.join("\n"); 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); println!("{}", tmp);
buffer.clear(); buffer.clear();
} else { } else if let Some(msg) = map_message(&msg) {
buffer.push(msg.contents); buffer.push(msg);
} }
} else { } else {
// All senders have been dropped // All senders have been dropped
// TODO: Send this to stderr
println!("{}", buffer.join("\n")); println!("{}", buffer.join("\n"));
// Wake up the main thread // Wake up the main thread
@ -111,7 +164,7 @@ pub fn run(
let parsed_formats = parse_format(&formats)?; let parsed_formats = parse_format(&formats)?;
(Some(formats), parsed_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( check::check_invalid_compression_with_non_archive_format(
@ -156,6 +209,7 @@ pub fn run(
.send(PrintMessage { .send(PrintMessage {
contents: format!("Successfully compressed '{}'.", to_utf(&output_path)), contents: format!("Successfully compressed '{}'.", to_utf(&output_path)),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} else { } else {
@ -195,7 +249,8 @@ pub fn run(
} }
} else { } else {
for path in files.iter() { 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(_) = if let ControlFlow::Break(_) =
check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())? check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())?
@ -246,7 +301,7 @@ pub fn run(
} }
} else { } else {
for path in files.iter() { 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(_) = if let ControlFlow::Break(_) =
check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())? check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())?

View File

@ -1,11 +1,15 @@
//! Our representation of all the supported compression formats. //! 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 bstr::ByteSlice;
use self::CompressionFormat::*; use self::CompressionFormat::*;
use crate::{error::Error, warning}; use crate::{
error::Error,
utils::message::{MessageLevel, PrintMessage},
warning,
};
pub const SUPPORTED_EXTENSIONS: &[&str] = &[ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
"tar", "tar",
@ -169,7 +173,7 @@ pub fn parse_format(fmt: &OsStr) -> crate::Result<Vec<Extension>> {
/// Extracts extensions from a path. /// Extracts extensions from a path.
/// ///
/// Returns both the remaining path and the list of extension objects /// Returns both the remaining path and the list of extension objects
pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec<Extension>) { pub fn separate_known_extensions_from_name(path: &Path, log_sender: Sender<PrintMessage>) -> (&Path, Vec<Extension>) {
let mut extensions = vec![]; let mut extensions = vec![];
let Some(mut name) = path.file_name().and_then(<[u8] as ByteSlice>::from_os_str) else { 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<Extension
if let Ok(name) = name.to_str() { if let Ok(name) = name.to_str() {
let file_stem = name.trim_matches('.'); let file_stem = name.trim_matches('.');
if SUPPORTED_EXTENSIONS.contains(&file_stem) || SUPPORTED_ALIASES.contains(&file_stem) { if SUPPORTED_EXTENSIONS.contains(&file_stem) || SUPPORTED_ALIASES.contains(&file_stem) {
warning!("Received a file with name '{file_stem}', but {file_stem} was expected as the extension."); log_sender
.send(PrintMessage {
contents: format!(
"Received a file with name '{file_stem}', but {file_stem} was expected as the extension."
),
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();
} }
} }
@ -192,8 +204,8 @@ pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec<Extension
} }
/// Extracts extensions from a path, return only the list of extension objects /// Extracts extensions from a path, return only the list of extension objects
pub fn extensions_from_path(path: &Path) -> Vec<Extension> { pub fn extensions_from_path(path: &Path, log_sender: Sender<PrintMessage>) -> Vec<Extension> {
let (_, extensions) = separate_known_extensions_from_name(path); let (_, extensions) = separate_known_extensions_from_name(path, log_sender);
extensions extensions
} }
@ -252,9 +264,11 @@ mod tests {
#[test] #[test]
fn test_extensions_from_path() { fn test_extensions_from_path() {
let (log_sender, _log_receiver) = std::sync::mpsc::channel::<PrintMessage>();
let path = Path::new("bolovo.tar.gz"); let path = Path::new("bolovo.tar.gz");
let extensions: Vec<Extension> = extensions_from_path(path); let extensions: Vec<Extension> = extensions_from_path(path, log_sender);
let formats: Vec<CompressionFormat> = flatten_compression_formats(&extensions); let formats: Vec<CompressionFormat> = flatten_compression_formats(&extensions);
assert_eq!(formats, vec![Tar, Gzip]); assert_eq!(formats, vec![Tar, Gzip]);

View File

@ -9,7 +9,10 @@ use std::{
use fs_err as fs; 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}; use crate::{extension::Extension, utils::EscapedPathDisplay, QuestionPolicy};
/// Remove `path` asking the user to overwrite if necessary. /// 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<PrintMessage>)
.send(PrintMessage { .send(PrintMessage {
contents: format!("Directory {} created.", EscapedPathDisplay::new(path)), contents: format!("Directory {} created.", EscapedPathDisplay::new(path)),
accessible: true, accessible: true,
level: MessageLevel::Info,
}) })
.unwrap(); .unwrap();
} }

View File

@ -19,4 +19,11 @@
pub struct PrintMessage { pub struct PrintMessage {
pub contents: String, pub contents: String,
pub accessible: bool, pub accessible: bool,
pub level: MessageLevel,
}
#[derive(Debug, PartialEq)]
pub enum MessageLevel {
Info,
Warning,
} }