make logger channel static

This commit is contained in:
João Marcos P. Bezerra 2024-03-15 16:09:48 -03:00 committed by João Marcos
parent bed8ea0276
commit 28daa9e8c4
12 changed files with 76 additions and 120 deletions

View File

@ -4,7 +4,7 @@ use std::path::Path;
use unrar::Archive;
use crate::{error::Error, list::FileInArchive, utils::logger::Logger};
use crate::{error::Error, list::FileInArchive, utils::logger::info};
/// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
/// Assumes that output_folder is empty
@ -18,7 +18,7 @@ pub fn unpack_archive(archive_path: &Path, output_folder: &Path, quiet: bool) ->
let entry = header.entry();
archive = if entry.is_file() {
if !quiet {
logger.info(format!(
info(format!(
"{} extracted. ({})",
entry.filename.display(),
entry.unpacked_size

View File

@ -11,7 +11,11 @@ use same_file::Handle;
use crate::{
error::FinalError,
utils::{self, cd_into_same_dir_as, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
utils::{
self, cd_into_same_dir_as,
logger::{info, warning},
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
},
};
pub fn compress_sevenz<W>(
@ -41,7 +45,7 @@ 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) {
logger.warning(format!(
warning(format!(
"The output file and the input file are the same: `{}`, skipping...",
output_path.display()
));
@ -55,7 +59,7 @@ where
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
}
let metadata = match path.metadata() {
@ -108,7 +112,7 @@ where
if entry.is_directory() {
if !quiet {
logger.info(format!(
info(format!(
"File {} extracted to \"{}\"",
entry.name(),
file_path.display()
@ -119,7 +123,7 @@ where
}
} else {
if !quiet {
logger.info(format!(
info(format!(
"{:?} extracted. ({})",
file_path.display(),
Bytes::new(entry.size())

View File

@ -14,7 +14,11 @@ use same_file::Handle;
use crate::{
error::FinalError,
list::FileInArchive,
utils::{self, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
utils::{
self,
logger::{info, warning},
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
},
};
/// Unpacks the archive given by `archive` into the folder given by `into`.
@ -34,7 +38,7 @@ pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool)
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!(
info(format!(
"{:?} extracted. ({})",
utils::strip_cur_dir(&output_folder.join(file.path()?)),
Bytes::new(file.size()),
@ -104,7 +108,7 @@ 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) {
logger.warning(format!(
warning(format!(
"The output file and the input file are the same: `{}`, skipping...",
output_path.display()
));
@ -118,7 +122,7 @@ where
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
}
if path.is_dir() {

View File

@ -20,8 +20,9 @@ use crate::{
error::FinalError,
list::FileInArchive,
utils::{
self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, Bytes,
EscapedPathDisplay, FileVisibilityPolicy,
self, cd_into_same_dir_as, get_invalid_utf8_paths,
logger::{info, info_accessible, warning},
pretty_format_list_of_paths, strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy,
},
};
@ -53,7 +54,7 @@ where
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!("File {} extracted to \"{}\"", idx, file_path.display()));
info(format!("File {} extracted to \"{}\"", idx, file_path.display()));
}
fs::create_dir_all(&file_path)?;
}
@ -67,7 +68,7 @@ where
// same reason is in _is_dir: long, often not needed text
if !quiet {
logger.info(format!(
info(format!(
"{:?} extracted. ({})",
file_path.display(),
Bytes::new(file.size())
@ -175,7 +176,7 @@ 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) {
logger.warning(format!(
warning(format!(
"The output file and the input file are the same: `{}`, skipping...",
output_path.display()
));
@ -187,7 +188,7 @@ where
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
}
let metadata = match path.metadata() {

View File

@ -11,7 +11,10 @@ use std::{
use crate::{
error::FinalError,
extension::{build_archive_file_suggestion, Extension, PRETTY_SUPPORTED_ALIASES, PRETTY_SUPPORTED_EXTENSIONS},
utils::{pretty_format_list_of_paths, try_infer_extension, user_wants_to_continue, EscapedPathDisplay},
utils::{
logger::{info_accessible, warning},
pretty_format_list_of_paths, try_infer_extension, user_wants_to_continue, EscapedPathDisplay,
},
QuestionAction, QuestionPolicy, Result,
};
@ -53,7 +56,7 @@ pub fn check_mime_type(
.compression_formats
.ends_with(detected_format.compression_formats)
{
logger.warning(format!(
warning(format!(
"The file extension: `{}` differ from the detected extension: `{}`",
outer_ext, detected_format
));

View File

@ -104,7 +104,7 @@ pub fn compress_files(
}
Zip => {
if !formats.is_empty() {
warn_user_about_loading_zip_in_memory(logger.clone());
warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(output_path, question_policy, QuestionAction::Compression)? {
return Ok(false);
@ -132,7 +132,7 @@ pub fn compress_files(
}
SevenZip => {
if !formats.is_empty() {
warn_user_about_loading_sevenz_in_memory(logger.clone());
warn_user_about_loading_sevenz_in_memory();
if !user_wants_to_continue(output_path, question_policy, QuestionAction::Compression)? {
return Ok(false);

View File

@ -13,7 +13,7 @@ use crate::{
CompressionFormat::{self, *},
Extension,
},
utils::{self, nice_directory_display, user_wants_to_continue},
utils::{self, logger::info_accessible, nice_directory_display, user_wants_to_continue},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
};
@ -122,7 +122,7 @@ pub fn decompress_file(
}
Zip => {
if formats.len() > 1 {
warn_user_about_loading_zip_in_memory(logger.clone());
warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(input_file_path, question_policy, QuestionAction::Decompression)? {
return Ok(());
@ -150,10 +150,7 @@ pub fn decompress_file(
let unpack_fn: Box<dyn FnOnce(&Path) -> UnpackResult> = if formats.len() > 1 {
let mut temp_file = tempfile::NamedTempFile::new()?;
io::copy(&mut reader, &mut temp_file)?;
let logger_clone = logger.clone();
Box::new(move |output_dir| {
crate::archive::rar::unpack_archive(temp_file.path(), output_dir, quiet, logger_clone)
})
Box::new(move |output_dir| crate::archive::rar::unpack_archive(temp_file.path(), output_dir, quiet))
} else {
Box::new(|output_dir| crate::archive::rar::unpack_archive(input_file_path, output_dir, quiet))
};
@ -172,7 +169,7 @@ pub fn decompress_file(
}
SevenZip => {
if formats.len() > 1 {
warn_user_about_loading_sevenz_in_memory(logger.clone());
warn_user_about_loading_sevenz_in_memory();
if !user_wants_to_continue(input_file_path, question_policy, QuestionAction::Decompression)? {
return Ok(());

View File

@ -65,7 +65,7 @@ pub fn list_archive_contents(
Tar => Box::new(crate::archive::tar::list_archive(tar::Archive::new(reader))),
Zip => {
if formats.len() > 1 {
warn_user_about_loading_zip_in_memory(logger.clone());
warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
return Ok(());
@ -94,7 +94,7 @@ pub fn list_archive_contents(
}
SevenZip => {
if formats.len() > 1 {
warn_user_about_loading_zip_in_memory(logger.clone());
warn_user_about_loading_zip_in_memory();
if !user_wants_to_continue(archive_path, question_policy, QuestionAction::Decompression)? {
return Ok(());
}

View File

@ -7,7 +7,7 @@ mod list;
use std::{
ops::ControlFlow,
path::PathBuf,
sync::{mpsc, Arc, Condvar, Mutex, OnceLock},
sync::{Arc, Condvar, Mutex},
};
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
@ -22,30 +22,30 @@ use crate::{
list::ListOptions,
utils::{
self,
logger::{map_message, setup_channel, PrintMessage},
logger::{info_accessible, map_message, setup_channel, warning},
to_utf, EscapedPathDisplay, FileVisibilityPolicy,
},
CliArgs, QuestionPolicy,
};
/// Warn the user that (de)compressing this .zip archive might freeze their system.
fn warn_user_about_loading_zip_in_memory(logger: Logger) {
fn warn_user_about_loading_zip_in_memory() {
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!";
logger.warning(ZIP_IN_MEMORY_LIMITATION_WARNING.to_string());
warning(ZIP_IN_MEMORY_LIMITATION_WARNING.to_string());
}
/// Warn the user that (de)compressing this .7z archive might freeze their system.
fn warn_user_about_loading_sevenz_in_memory(logger: Logger) {
fn warn_user_about_loading_sevenz_in_memory() {
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!";
logger.warning(SEVENZ_IN_MEMORY_LIMITATION_WARNING.to_string());
warning(SEVENZ_IN_MEMORY_LIMITATION_WARNING.to_string());
}
/// This function checks what command needs to be run and performs A LOT of ahead-of-time checks
@ -272,7 +272,7 @@ pub fn run(
// Drop our sender so when all threads are done, no clones are left.
// This is needed, otherwise the logging thread will never exit since we would be keeping a
// sender alive here.
drop(logger);
todo!();
// Prevent the main thread from exiting until the background thread handling the
// logging has set `flushed` to true.

View File

@ -5,7 +5,7 @@ use std::{ffi::OsStr, fmt, path::Path};
use bstr::ByteSlice;
use self::CompressionFormat::*;
use crate::{error::Error, utils::logger::Logger};
use crate::{error::Error, utils::logger::warning};
pub const SUPPORTED_EXTENSIONS: &[&str] = &[
"tar",
@ -184,7 +184,7 @@ pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec<Extension
if let Ok(name) = name.to_str() {
let file_stem = name.trim_matches('.');
if SUPPORTED_EXTENSIONS.contains(&file_stem) || SUPPORTED_ALIASES.contains(&file_stem) {
logger.warning(format!(
warning(format!(
"Received a file with name '{file_stem}', but {file_stem} was expected as the extension."
));
}
@ -251,13 +251,9 @@ pub fn build_archive_file_suggestion(path: &Path, suggested_extension: &str) ->
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::logger::PrintMessage;
#[test]
fn test_extensions_from_path() {
let (log_sender, _log_receiver) = std::sync::mpsc::channel::<PrintMessage>();
let logger = Logger::new(log_sender);
let path = Path::new("bolovo.tar.gz");
let extensions: Vec<Extension> = extensions_from_path(path);

View File

@ -9,7 +9,11 @@ use std::{
use fs_err as fs;
use super::user_wants_to_overwrite;
use crate::{extension::Extension, utils::EscapedPathDisplay, QuestionPolicy};
use crate::{
extension::Extension,
utils::{logger::info_accessible, EscapedPathDisplay},
QuestionPolicy,
};
/// Remove `path` asking the user to overwrite if necessary.
///

View File

@ -1,21 +1,21 @@
use std::sync::{
mpsc::{channel, Receiver, Sender},
OnceLock,
};
use std::sync::{mpsc, OnceLock};
use super::colors::{ORANGE, RESET, YELLOW};
use crate::accessible::is_running_in_accessible_mode;
static SENDER: OnceLock<Sender<PrintMessage>> = OnceLock::new();
type Receiver = mpsc::Receiver<PrintMessage>;
type Sender = mpsc::Sender<PrintMessage>;
pub fn setup_channel() -> Receiver<PrintMessage> {
let (tx, rx) = channel();
static SENDER: OnceLock<Sender> = OnceLock::new();
pub fn setup_channel() -> Receiver {
let (tx, rx) = mpsc::channel();
SENDER.set(tx).expect("`setup_channel` should only be called once");
rx
}
#[track_caller]
fn get_sender() -> &'static Sender<PrintMessage> {
fn get_sender() -> &'static Sender {
SENDER.get().expect("No sender, you need to call `setup_channel` first")
}
@ -75,77 +75,20 @@ pub fn info_accessible(contents: String) {
}
fn info_with_accessibility(contents: String, accessible: bool) {
get_sender()
.send(PrintMessage {
contents,
accessible,
level: MessageLevel::Info,
})
.unwrap();
send_log_message(PrintMessage {
contents,
accessible,
level: MessageLevel::Info,
});
}
pub fn warning(contents: String) {
get_sender()
.send(PrintMessage {
contents,
// Warnings are important and unlikely to flood, so they should be displayed
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();
}
#[derive(Clone)]
pub struct Logger {
log_sender: Sender<PrintMessage>,
}
impl Logger {
pub fn new(log_sender: Sender<PrintMessage>) -> Self {
Self { log_sender }
}
/// An `[INFO]` log to be displayed if we're not running accessibility mode.
///
/// Same as `.info_accessible()`, but only displayed if accessibility mode
/// is turned off, which is detected by the function
/// `is_running_in_accessible_mode`.
///
/// Read more about accessibility mode in `accessible.rs`.
pub fn info(&self, contents: String) {
self.info_with_accessibility(contents, false);
}
/// An `[INFO]` log to be displayed.
///
/// Same as `.info()`, but also displays if `is_running_in_accessible_mode`
/// returns `true`.
///
/// Read more about accessibility mode in `accessible.rs`.
pub fn info_accessible(&self, contents: String) {
self.info_with_accessibility(contents, true);
}
fn info_with_accessibility(&self, contents: String, accessible: bool) {
self.log_sender
.send(PrintMessage {
contents,
accessible,
level: MessageLevel::Info,
})
.unwrap();
}
pub fn warning(&self, contents: String) {
self.log_sender
.send(PrintMessage {
contents,
// Warnings are important and unlikely to flood, so they should be displayed
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();
}
send_log_message(PrintMessage {
contents,
// Warnings are important and unlikely to flood, so they should be displayed
accessible: true,
level: MessageLevel::Warning,
});
}
#[derive(Debug, PartialEq)]
@ -153,3 +96,7 @@ pub enum MessageLevel {
Info,
Warning,
}
fn send_log_message(msg: PrintMessage) {
get_sender().send(msg).expect("Failed to send internal message");
}