create Logger::info_accessible

This commit is contained in:
João Marcos P. Bezerra 2024-03-15 15:23:22 -03:00 committed by João Marcos
parent 1e56bb8f1f
commit bed8ea0276
12 changed files with 189 additions and 180 deletions

View File

@ -8,7 +8,7 @@ use crate::{error::Error, list::FileInArchive, utils::logger::Logger};
/// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
/// Assumes that output_folder is empty
pub fn unpack_archive(archive_path: &Path, output_folder: &Path, quiet: bool, logger: Logger) -> crate::Result<usize> {
pub fn unpack_archive(archive_path: &Path, output_folder: &Path, quiet: bool) -> crate::Result<usize> {
assert!(output_folder.read_dir().expect("dir exists").count() == 0);
let mut archive = Archive::new(archive_path).open_for_processing()?;
@ -18,10 +18,11 @@ pub fn unpack_archive(archive_path: &Path, output_folder: &Path, quiet: bool, lo
let entry = header.entry();
archive = if entry.is_file() {
if !quiet {
logger.info(
format!("{} extracted. ({})", entry.filename.display(), entry.unpacked_size),
false,
);
logger.info(format!(
"{} extracted. ({})",
entry.filename.display(),
entry.unpacked_size
));
}
unpacked += 1;
header.extract_with_base(output_folder)?

View File

@ -11,7 +11,7 @@ use same_file::Handle;
use crate::{
error::FinalError,
utils::{self, cd_into_same_dir_as, logger::Logger, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
utils::{self, cd_into_same_dir_as, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
};
pub fn compress_sevenz<W>(
@ -20,7 +20,6 @@ pub fn compress_sevenz<W>(
writer: W,
file_visibility_policy: FileVisibilityPolicy,
quiet: bool,
logger: Logger,
) -> crate::Result<W>
where
W: Write + Seek,
@ -56,7 +55,7 @@ where
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)), false);
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
}
let metadata = match path.metadata() {
@ -93,7 +92,7 @@ where
Ok(bytes)
}
pub fn decompress_sevenz<R>(reader: R, output_path: &Path, quiet: bool, logger: Logger) -> crate::Result<usize>
pub fn decompress_sevenz<R>(reader: R, output_path: &Path, quiet: bool) -> crate::Result<usize>
where
R: Read + Seek,
{
@ -109,20 +108,22 @@ where
if entry.is_directory() {
if !quiet {
logger.info(
format!("File {} extracted to \"{}\"", entry.name(), file_path.display()),
false,
);
logger.info(format!(
"File {} extracted to \"{}\"",
entry.name(),
file_path.display()
));
}
if !path.exists() {
fs::create_dir_all(path)?;
}
} else {
if !quiet {
logger.info(
format!("{:?} extracted. ({})", file_path.display(), Bytes::new(entry.size())),
false,
);
logger.info(format!(
"{:?} extracted. ({})",
file_path.display(),
Bytes::new(entry.size())
));
}
if let Some(parent) = path.parent() {

View File

@ -14,17 +14,12 @@ use same_file::Handle;
use crate::{
error::FinalError,
list::FileInArchive,
utils::{self, logger::Logger, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
utils::{self, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
};
/// Unpacks the archive given by `archive` into the folder given by `into`.
/// Assumes that output_folder is empty
pub fn unpack_archive(
reader: Box<dyn Read>,
output_folder: &Path,
quiet: bool,
logger: Logger,
) -> crate::Result<usize> {
pub fn unpack_archive(reader: Box<dyn Read>, output_folder: &Path, quiet: bool) -> crate::Result<usize> {
assert!(output_folder.read_dir().expect("dir exists").count() == 0);
let mut archive = tar::Archive::new(reader);
@ -39,14 +34,11 @@ pub fn unpack_archive(
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(
format!(
"{:?} extracted. ({})",
utils::strip_cur_dir(&output_folder.join(file.path()?)),
Bytes::new(file.size()),
),
false,
);
logger.info(format!(
"{:?} extracted. ({})",
utils::strip_cur_dir(&output_folder.join(file.path()?)),
Bytes::new(file.size()),
));
files_unpacked += 1;
}
@ -91,7 +83,6 @@ pub fn build_archive_from_paths<W>(
writer: W,
file_visibility_policy: FileVisibilityPolicy,
quiet: bool,
logger: Logger,
) -> crate::Result<W>
where
W: Write,
@ -127,7 +118,7 @@ where
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)), false);
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
}
if path.is_dir() {

View File

@ -20,19 +20,14 @@ use crate::{
error::FinalError,
list::FileInArchive,
utils::{
self, cd_into_same_dir_as, get_invalid_utf8_paths, logger::Logger, pretty_format_list_of_paths, strip_cur_dir,
Bytes, EscapedPathDisplay, FileVisibilityPolicy,
self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, Bytes,
EscapedPathDisplay, FileVisibilityPolicy,
},
};
/// Unpacks the archive given by `archive` into the folder given by `output_folder`.
/// Assumes that output_folder is empty
pub fn unpack_archive<R>(
mut archive: ZipArchive<R>,
output_folder: &Path,
quiet: bool,
logger: Logger,
) -> crate::Result<usize>
pub fn unpack_archive<R>(mut archive: ZipArchive<R>, output_folder: &Path, quiet: bool) -> crate::Result<usize>
where
R: Read + Seek,
{
@ -49,7 +44,7 @@ where
let file_path = output_folder.join(file_path);
display_zip_comment_if_exists(&file, logger.clone());
display_zip_comment_if_exists(&file);
match file.name().ends_with('/') {
_is_dir @ true => {
@ -58,7 +53,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()), false);
logger.info(format!("File {} extracted to \"{}\"", idx, file_path.display()));
}
fs::create_dir_all(&file_path)?;
}
@ -72,10 +67,11 @@ where
// same reason is in _is_dir: long, often not needed text
if !quiet {
logger.info(
format!("{:?} extracted. ({})", file_path.display(), Bytes::new(file.size())),
false,
);
logger.info(format!(
"{:?} extracted. ({})",
file_path.display(),
Bytes::new(file.size())
));
}
let mut output_file = fs::File::create(file_path)?;
@ -138,7 +134,6 @@ pub fn build_archive_from_paths<W>(
writer: W,
file_visibility_policy: FileVisibilityPolicy,
quiet: bool,
logger: Logger,
) -> crate::Result<W>
where
W: Write + Seek,
@ -192,7 +187,7 @@ where
// spoken text for users using screen readers, braille displays
// and so on
if !quiet {
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)), false);
logger.info(format!("Compressing '{}'.", EscapedPathDisplay::new(path)));
}
let metadata = match path.metadata() {
@ -242,7 +237,7 @@ where
Ok(bytes)
}
fn display_zip_comment_if_exists(file: &ZipFile, logger: Logger) {
fn display_zip_comment_if_exists(file: &ZipFile) {
let comment = file.comment();
if !comment.is_empty() {
// Zip file comments seem to be pretty rare, but if they are used,
@ -255,7 +250,7 @@ fn display_zip_comment_if_exists(file: &ZipFile, logger: Logger) {
// the future, maybe asking the user if he wants to display the comment
// (informing him of its size) would be sensible for both normal and
// accessibility mode..
logger.info(format!("Found comment in {}: {}", file.name(), comment), true);
info_accessible(format!("Found comment in {}: {}", file.name(), comment));
}
}

View File

@ -11,9 +11,7 @@ use std::{
use crate::{
error::FinalError,
extension::{build_archive_file_suggestion, Extension, PRETTY_SUPPORTED_ALIASES, PRETTY_SUPPORTED_EXTENSIONS},
utils::{
logger::Logger, pretty_format_list_of_paths, try_infer_extension, user_wants_to_continue, EscapedPathDisplay,
},
utils::{pretty_format_list_of_paths, try_infer_extension, user_wants_to_continue, EscapedPathDisplay},
QuestionAction, QuestionPolicy, Result,
};
@ -27,7 +25,6 @@ pub fn check_mime_type(
path: &Path,
formats: &mut Vec<Extension>,
question_policy: QuestionPolicy,
logger: Logger,
) -> Result<ControlFlow<()>> {
if formats.is_empty() {
// File with no extension
@ -35,10 +32,11 @@ pub fn check_mime_type(
if let Some(detected_format) = try_infer_extension(path) {
// Inferring the file extension can have unpredicted consequences (e.g. the user just
// mistyped, ...) which we should always inform the user about.
logger.info(
format!("Detected file: `{}` extension as `{}`", path.display(), detected_format),
true,
);
info_accessible(format!(
"Detected file: `{}` extension as `{}`",
path.display(),
detected_format
));
if user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? {
formats.push(detected_format);
@ -67,13 +65,10 @@ pub fn check_mime_type(
} else {
// NOTE: If this actually produces no false positives, we can upgrade it in the future
// to a warning and ask the user if he wants to continue decompressing.
logger.info(
format!(
"Failed to confirm the format of `{}` by sniffing the contents, file might be misnamed",
path.display()
),
true,
);
info_accessible(format!(
"Failed to confirm the format of `{}` by sniffing the contents, file might be misnamed",
path.display()
));
}
Ok(ControlFlow::Continue(()))
}

View File

@ -10,7 +10,7 @@ use crate::{
archive,
commands::warn_user_about_loading_zip_in_memory,
extension::{split_first_compression_format, CompressionFormat::*, Extension},
utils::{logger::Logger, user_wants_to_continue, FileVisibilityPolicy},
utils::{user_wants_to_continue, FileVisibilityPolicy},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
};
@ -34,7 +34,6 @@ pub fn compress_files(
question_policy: QuestionPolicy,
file_visibility_policy: FileVisibilityPolicy,
level: Option<i16>,
logger: Logger,
) -> crate::Result<bool> {
// If the input files contain a directory, then the total size will be underestimated
let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file);
@ -100,14 +99,7 @@ pub fn compress_files(
io::copy(&mut reader, &mut writer)?;
}
Tar => {
archive::tar::build_archive_from_paths(
&files,
output_path,
&mut writer,
file_visibility_policy,
quiet,
logger.clone(),
)?;
archive::tar::build_archive_from_paths(&files, output_path, &mut writer, file_visibility_policy, quiet)?;
writer.flush()?;
}
Zip => {
@ -127,7 +119,6 @@ pub fn compress_files(
&mut vec_buffer,
file_visibility_policy,
quiet,
logger.clone(),
)?;
vec_buffer.rewind()?;
io::copy(&mut vec_buffer, &mut writer)?;
@ -149,14 +140,7 @@ pub fn compress_files(
}
let mut vec_buffer = Cursor::new(vec![]);
archive::sevenz::compress_sevenz(
&files,
output_path,
&mut vec_buffer,
file_visibility_policy,
quiet,
logger.clone(),
)?;
archive::sevenz::compress_sevenz(&files, output_path, &mut vec_buffer, file_visibility_policy, quiet)?;
vec_buffer.rewind()?;
io::copy(&mut vec_buffer, &mut writer)?;
}

View File

@ -13,7 +13,7 @@ use crate::{
CompressionFormat::{self, *},
Extension,
},
utils::{self, logger::Logger, nice_directory_display, user_wants_to_continue},
utils::{self, nice_directory_display, user_wants_to_continue},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
};
@ -30,7 +30,6 @@ pub fn decompress_file(
output_file_path: PathBuf,
question_policy: QuestionPolicy,
quiet: bool,
logger: Logger,
) -> crate::Result<()> {
assert!(output_dir.exists());
let reader = fs::File::open(input_file_path)?;
@ -49,11 +48,10 @@ pub fn decompress_file(
{
let zip_archive = zip::ZipArchive::new(reader)?;
let files_unpacked = if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet, logger.clone()),
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet),
output_dir,
&output_file_path,
question_policy,
logger.clone(),
)? {
files
} else {
@ -64,14 +62,11 @@ pub fn decompress_file(
// having a final status message is important especially in an accessibility context
// as screen readers may not read a commands exit code, making it hard to reason
// about whether the command succeeded without such a message
logger.info(
format!(
"Successfully decompressed archive in {} ({} files).",
nice_directory_display(output_dir),
files_unpacked
),
true,
);
info_accessible(format!(
"Successfully decompressed archive in {} ({} files).",
nice_directory_display(output_dir),
files_unpacked
));
return Ok(());
}
@ -115,11 +110,10 @@ pub fn decompress_file(
}
Tar => {
if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::tar::unpack_archive(reader, output_dir, quiet, logger.clone()),
|output_dir| crate::archive::tar::unpack_archive(reader, output_dir, quiet),
output_dir,
&output_file_path,
question_policy,
logger.clone(),
)? {
files
} else {
@ -140,11 +134,10 @@ pub fn decompress_file(
let zip_archive = zip::ZipArchive::new(io::Cursor::new(vec))?;
if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet, logger.clone()),
|output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet),
output_dir,
&output_file_path,
question_policy,
logger.clone(),
)? {
files
} else {
@ -162,18 +155,12 @@ pub fn decompress_file(
crate::archive::rar::unpack_archive(temp_file.path(), output_dir, quiet, logger_clone)
})
} else {
Box::new(|output_dir| {
crate::archive::rar::unpack_archive(input_file_path, output_dir, quiet, logger.clone())
})
Box::new(|output_dir| crate::archive::rar::unpack_archive(input_file_path, output_dir, quiet))
};
if let ControlFlow::Continue(files) = smart_unpack(
unpack_fn,
output_dir,
&output_file_path,
question_policy,
logger.clone(),
)? {
if let ControlFlow::Continue(files) =
smart_unpack(unpack_fn, output_dir, &output_file_path, question_policy)?
{
files
} else {
return Ok(());
@ -196,13 +183,10 @@ pub fn decompress_file(
io::copy(&mut reader, &mut vec)?;
if let ControlFlow::Continue(files) = smart_unpack(
|output_dir| {
crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, quiet, logger.clone())
},
|output_dir| crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, quiet),
output_dir,
&output_file_path,
question_policy,
logger.clone(),
)? {
files
} else {
@ -215,14 +199,11 @@ pub fn decompress_file(
// having a final status message is important especially in an accessibility context
// as screen readers may not read a commands exit code, making it hard to reason
// about whether the command succeeded without such a message
logger.info(
format!(
"Successfully decompressed archive in {}.",
nice_directory_display(output_dir)
),
true,
);
logger.info(format!("Files unpacked: {}", files_unpacked), true);
info_accessible(format!(
"Successfully decompressed archive in {}.",
nice_directory_display(output_dir)
));
info_accessible(format!("Files unpacked: {}", files_unpacked));
Ok(())
}
@ -237,19 +218,15 @@ fn smart_unpack(
output_dir: &Path,
output_file_path: &Path,
question_policy: QuestionPolicy,
logger: Logger,
) -> crate::Result<ControlFlow<(), usize>> {
assert!(output_dir.exists());
let temp_dir = tempfile::tempdir_in(output_dir)?;
let temp_dir_path = temp_dir.path();
logger.info(
format!(
"Created temporary directory {} to hold decompressed elements.",
nice_directory_display(temp_dir_path)
),
true,
);
info_accessible(format!(
"Created temporary directory {} to hold decompressed elements.",
nice_directory_display(temp_dir_path)
));
let files = unpack_fn(temp_dir_path)?;
@ -268,14 +245,11 @@ fn smart_unpack(
}
fs::rename(&file_path, &correct_path)?;
logger.info(
format!(
"Successfully moved {} to {}.",
nice_directory_display(&file_path),
nice_directory_display(&correct_path)
),
true,
);
info_accessible(format!(
"Successfully moved {} to {}.",
nice_directory_display(&file_path),
nice_directory_display(&correct_path)
));
} else {
// Multiple files in the root directory, so:
// Rename the temporary directory to the archive name, which is output_file_path
@ -284,14 +258,11 @@ fn smart_unpack(
return Ok(ControlFlow::Break(()));
}
fs::rename(temp_dir_path, output_file_path)?;
logger.info(
format!(
"Successfully moved {} to {}.",
nice_directory_display(temp_dir_path),
nice_directory_display(output_file_path)
),
true,
);
info_accessible(format!(
"Successfully moved {} to {}.",
nice_directory_display(temp_dir_path),
nice_directory_display(output_file_path)
));
}
Ok(ControlFlow::Continue(files))

View File

@ -9,7 +9,7 @@ use crate::{
commands::warn_user_about_loading_zip_in_memory,
extension::CompressionFormat::{self, *},
list::{self, FileInArchive, ListOptions},
utils::{logger::Logger, user_wants_to_continue},
utils::user_wants_to_continue,
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
};
@ -20,7 +20,6 @@ pub fn list_archive_contents(
formats: Vec<CompressionFormat>,
list_options: ListOptions,
question_policy: QuestionPolicy,
logger: Logger,
) -> crate::Result<()> {
let reader = fs::File::open(archive_path)?;

View File

@ -7,7 +7,7 @@ mod list;
use std::{
ops::ControlFlow,
path::PathBuf,
sync::{mpsc::channel, Arc, Condvar, Mutex},
sync::{mpsc, Arc, Condvar, Mutex, OnceLock},
};
use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
@ -22,7 +22,7 @@ use crate::{
list::ListOptions,
utils::{
self,
logger::{map_message, Logger, PrintMessage},
logger::{map_message, setup_channel, PrintMessage},
to_utf, EscapedPathDisplay, FileVisibilityPolicy,
},
CliArgs, QuestionPolicy,
@ -57,8 +57,7 @@ pub fn run(
question_policy: QuestionPolicy,
file_visibility_policy: FileVisibilityPolicy,
) -> crate::Result<()> {
let (log_sender, log_receiver) = channel::<PrintMessage>();
let logger = Logger::new(log_sender);
let log_receiver = setup_channel();
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = Arc::clone(&pair);
@ -119,7 +118,7 @@ pub fn run(
let parsed_formats = parse_format(&formats)?;
(Some(formats), parsed_formats)
}
None => (None, extension::extensions_from_path(&output_path, logger.clone())),
None => (None, extension::extensions_from_path(&output_path)),
};
check::check_invalid_compression_with_non_archive_format(
@ -152,7 +151,6 @@ pub fn run(
question_policy,
file_visibility_policy,
level,
logger.clone(),
);
if let Ok(true) = compress_result {
@ -160,7 +158,7 @@ pub fn run(
// having a final status message is important especially in an accessibility context
// as screen readers may not read a commands exit code, making it hard to reason
// about whether the command succeeded without such a message
logger.info(format!("Successfully compressed '{}'.", to_utf(&output_path)), true);
info_accessible(format!("Successfully compressed '{}'.", to_utf(&output_path)));
} else {
// If Ok(false) or Err() occurred, delete incomplete file at `output_path`
//
@ -198,12 +196,9 @@ pub fn run(
}
} else {
for path in files.iter() {
let (pathbase, mut file_formats) =
extension::separate_known_extensions_from_name(path, logger.clone());
let (pathbase, mut file_formats) = extension::separate_known_extensions_from_name(path);
if let ControlFlow::Break(_) =
check::check_mime_type(path, &mut file_formats, question_policy, logger.clone())?
{
if let ControlFlow::Break(_) = check::check_mime_type(path, &mut file_formats, question_policy)? {
return Ok(());
}
@ -217,7 +212,7 @@ pub fn run(
// The directory that will contain the output files
// We default to the current directory if the user didn't specify an output directory with --dir
let output_dir = if let Some(dir) = output_dir {
utils::create_dir_if_non_existent(&dir, logger.clone())?;
utils::create_dir_if_non_existent(&dir)?;
dir
} else {
PathBuf::from(".")
@ -236,7 +231,6 @@ pub fn run(
output_file_path,
question_policy,
args.quiet,
logger.clone(),
)
})?;
}
@ -250,11 +244,9 @@ pub fn run(
}
} else {
for path in files.iter() {
let mut file_formats = extension::extensions_from_path(path, logger.clone());
let mut file_formats = extension::extensions_from_path(path);
if let ControlFlow::Break(_) =
check::check_mime_type(path, &mut file_formats, question_policy, logger.clone())?
{
if let ControlFlow::Break(_) = check::check_mime_type(path, &mut file_formats, question_policy)? {
return Ok(());
}
@ -272,7 +264,7 @@ pub fn run(
println!();
}
let formats = extension::flatten_compression_formats(&formats);
list_archive_contents(archive_path, formats, list_options, question_policy, logger.clone())?;
list_archive_contents(archive_path, formats, list_options, question_policy)?;
}
}
}

View File

@ -169,7 +169,7 @@ pub fn parse_format(fmt: &OsStr) -> crate::Result<Vec<Extension>> {
/// 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, logger: Logger) -> (&Path, Vec<Extension>) {
pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec<Extension>) {
let mut extensions = vec![];
let Some(mut name) = path.file_name().and_then(<[u8] as ByteSlice>::from_os_str) else {
@ -194,8 +194,8 @@ pub fn separate_known_extensions_from_name(path: &Path, logger: Logger) -> (&Pat
}
/// Extracts extensions from a path, return only the list of extension objects
pub fn extensions_from_path(path: &Path, logger: Logger) -> Vec<Extension> {
let (_, extensions) = separate_known_extensions_from_name(path, logger);
pub fn extensions_from_path(path: &Path) -> Vec<Extension> {
let (_, extensions) = separate_known_extensions_from_name(path);
extensions
}
@ -260,7 +260,7 @@ mod tests {
let path = Path::new("bolovo.tar.gz");
let extensions: Vec<Extension> = extensions_from_path(path, logger);
let extensions: Vec<Extension> = extensions_from_path(path);
let formats: Vec<CompressionFormat> = flatten_compression_formats(&extensions);
assert_eq!(formats, vec![Tar, Gzip]);

View File

@ -8,7 +8,7 @@ use std::{
use fs_err as fs;
use super::{logger::Logger, user_wants_to_overwrite};
use super::user_wants_to_overwrite;
use crate::{extension::Extension, utils::EscapedPathDisplay, QuestionPolicy};
/// Remove `path` asking the user to overwrite if necessary.
@ -36,12 +36,12 @@ pub fn remove_file_or_dir(path: &Path) -> crate::Result<()> {
}
/// Creates a directory at the path, if there is nothing there.
pub fn create_dir_if_non_existent(path: &Path, logger: Logger) -> crate::Result<()> {
pub fn create_dir_if_non_existent(path: &Path) -> crate::Result<()> {
if !path.exists() {
fs::create_dir_all(path)?;
// creating a directory is an important change to the file system we
// should always inform the user about
logger.info(format!("Directory {} created.", EscapedPathDisplay::new(path)), true);
info_accessible(format!("Directory {} created.", EscapedPathDisplay::new(path)));
}
Ok(())
}

View File

@ -1,10 +1,26 @@
use std::sync::mpsc::Sender;
use std::sync::{
mpsc::{channel, Receiver, Sender},
OnceLock,
};
use super::colors::{ORANGE, RESET, YELLOW};
use crate::accessible::is_running_in_accessible_mode;
static SENDER: OnceLock<Sender<PrintMessage>> = OnceLock::new();
pub fn setup_channel() -> Receiver<PrintMessage> {
let (tx, rx) = channel();
SENDER.set(tx).expect("`setup_channel` should only be called once");
rx
}
#[track_caller]
fn get_sender() -> &'static Sender<PrintMessage> {
SENDER.get().expect("No sender, you need to call `setup_channel` first")
}
/// Message object used for sending logs from worker threads to a logging thread via channels.
/// See <https://github.com/ouch-org/ouch/issues/632>
/// See <https://github.com/ouch-org/ouch/issues/643>
#[derive(Debug)]
pub struct PrintMessage {
contents: String,
@ -37,6 +53,48 @@ pub fn map_message(msg: &PrintMessage) -> Option<String> {
}
}
/// 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(contents: String) {
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(contents: String) {
info_with_accessibility(contents, true);
}
fn info_with_accessibility(contents: String, accessible: bool) {
get_sender()
.send(PrintMessage {
contents,
accessible,
level: MessageLevel::Info,
})
.unwrap();
}
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>,
@ -47,7 +105,28 @@ impl Logger {
Self { log_sender }
}
pub fn info(&self, contents: String, accessible: bool) {
/// 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,
@ -61,7 +140,8 @@ impl Logger {
self.log_sender
.send(PrintMessage {
contents,
accessible: true, // does not matter
// Warnings are important and unlikely to flood, so they should be displayed
accessible: true,
level: MessageLevel::Warning,
})
.unwrap();