Merge branch 'main' into simplify-error-treatment

This commit is contained in:
João Marcos 2024-11-20 04:02:08 -03:00 committed by GitHub
commit c27c55a1e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 54 additions and 72 deletions

View File

@ -11,11 +11,15 @@ pub mod utils;
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use cli::CliArgs; use cli::CliArgs;
use error::{Error, Result};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use utils::{QuestionAction, QuestionPolicy};
use crate::utils::logger::spawn_logger_thread; use self::{
error::{Error, Result},
utils::{
logger::{shutdown_logger_and_wait, spawn_logger_thread},
QuestionAction, QuestionPolicy,
},
};
// Used in BufReader and BufWriter to perform less syscalls // Used in BufReader and BufWriter to perform less syscalls
const BUFFER_CAPACITY: usize = 1024 * 32; const BUFFER_CAPACITY: usize = 1024 * 32;
@ -27,9 +31,9 @@ static CURRENT_DIRECTORY: Lazy<PathBuf> = Lazy::new(|| env::current_dir().unwrap
pub const EXIT_FAILURE: i32 = libc::EXIT_FAILURE; pub const EXIT_FAILURE: i32 = libc::EXIT_FAILURE;
fn main() { fn main() {
let handler = spawn_logger_thread(); spawn_logger_thread();
let result = run(); let result = run();
handler.shutdown_and_wait(); shutdown_logger_and_wait();
if let Err(err) = result { if let Err(err) = result {
eprintln!("{err}"); eprintln!("{err}");

View File

@ -5,10 +5,16 @@ pub use logger_thread::spawn_logger_thread;
use super::colors::{ORANGE, RESET, YELLOW}; use super::colors::{ORANGE, RESET, YELLOW};
use crate::accessible::is_running_in_accessible_mode; use crate::accessible::is_running_in_accessible_mode;
/// Asks logger to shutdown and waits till it flushes all pending messages.
#[track_caller]
pub fn shutdown_logger_and_wait() {
logger_thread::send_shutdown_command_and_wait();
}
/// Asks logger to flush all messages, useful before starting STDIN interaction. /// Asks logger to flush all messages, useful before starting STDIN interaction.
#[track_caller] #[track_caller]
pub fn flush_messages() { pub fn flush_messages() {
logger_thread::send_flush_message_and_wait(); logger_thread::send_flush_command_and_wait();
} }
/// An `[INFO]` log to be displayed if we're not running accessibility mode. /// An `[INFO]` log to be displayed if we're not running accessibility mode.
@ -36,7 +42,7 @@ pub fn info_accessible(contents: String) {
#[track_caller] #[track_caller]
fn info_with_accessibility(contents: String, accessible: bool) { fn info_with_accessibility(contents: String, accessible: bool) {
logger_thread::send_log_message(PrintMessage { logger_thread::send_print_command(PrintMessage {
contents, contents,
accessible, accessible,
level: MessageLevel::Info, level: MessageLevel::Info,
@ -45,7 +51,7 @@ fn info_with_accessibility(contents: String, accessible: bool) {
#[track_caller] #[track_caller]
pub fn warning(contents: String) { pub fn warning(contents: String) {
logger_thread::send_log_message(PrintMessage { logger_thread::send_print_command(PrintMessage {
contents, contents,
// Warnings are important and unlikely to flood, so they should be displayed // Warnings are important and unlikely to flood, so they should be displayed
accessible: true, accessible: true,
@ -57,7 +63,7 @@ pub fn warning(contents: String) {
enum LoggerCommand { enum LoggerCommand {
Print(PrintMessage), Print(PrintMessage),
Flush { finished_barrier: Arc<Barrier> }, Flush { finished_barrier: Arc<Barrier> },
FlushAndShutdown, FlushAndShutdown { finished_barrier: Arc<Barrier> },
} }
/// Message object used for sending logs from worker threads to a logging thread via channels. /// Message object used for sending logs from worker threads to a logging thread via channels.
@ -70,7 +76,7 @@ struct PrintMessage {
} }
impl PrintMessage { impl PrintMessage {
fn to_processed_message(&self) -> Option<String> { fn to_formatted_message(&self) -> Option<String> {
match self.level { match self.level {
MessageLevel::Info => { MessageLevel::Info => {
if self.accessible { if self.accessible {
@ -128,71 +134,44 @@ mod logger_thread {
} }
#[track_caller] #[track_caller]
pub(super) fn send_log_message(msg: PrintMessage) { pub(super) fn send_print_command(msg: PrintMessage) {
get_sender() get_sender()
.send(LoggerCommand::Print(msg)) .send(LoggerCommand::Print(msg))
.expect("Failed to send print message"); .expect("Failed to send print command");
} }
#[track_caller] #[track_caller]
fn send_shutdown_message() { pub(super) fn send_flush_command_and_wait() {
get_sender()
.send(LoggerCommand::FlushAndShutdown)
.expect("Failed to send shutdown message");
}
#[track_caller]
pub(super) fn send_flush_message_and_wait() {
let barrier = Arc::new(Barrier::new(2)); let barrier = Arc::new(Barrier::new(2));
get_sender() get_sender()
.send(LoggerCommand::Flush { .send(LoggerCommand::Flush {
finished_barrier: barrier.clone(), finished_barrier: barrier.clone(),
}) })
.expect("Failed to send shutdown message"); .expect("Failed to send flush command");
barrier.wait(); barrier.wait();
} }
pub struct LoggerThreadHandle { #[track_caller]
shutdown_barrier: Arc<Barrier>, pub(super) fn send_shutdown_command_and_wait() {
let barrier = Arc::new(Barrier::new(2));
get_sender()
.send(LoggerCommand::FlushAndShutdown {
finished_barrier: barrier.clone(),
})
.expect("Failed to send shutdown command");
barrier.wait();
} }
impl LoggerThreadHandle { pub fn spawn_logger_thread() {
/// Tell logger to shutdown and waits till it does.
pub fn shutdown_and_wait(self) {
// Signal the shutdown
send_shutdown_message();
// Wait for confirmation
self.shutdown_barrier.wait();
}
}
#[cfg(test)]
// shutdown_and_wait must be called manually, but to keep 'em clean, in
// case of tests just do it on drop
impl Drop for LoggerThreadHandle {
fn drop(&mut self) {
send_shutdown_message();
self.shutdown_barrier.wait();
}
}
pub fn spawn_logger_thread() -> LoggerThreadHandle {
let log_receiver = setup_channel(); let log_receiver = setup_channel();
rayon::spawn(move || run_logger(log_receiver));
let shutdown_barrier = Arc::new(Barrier::new(2));
let handle = LoggerThreadHandle {
shutdown_barrier: shutdown_barrier.clone(),
};
rayon::spawn(move || run_logger(log_receiver, shutdown_barrier));
handle
} }
fn run_logger(log_receiver: LogReceiver, shutdown_barrier: Arc<Barrier>) { fn run_logger(log_receiver: LogReceiver) {
const FLUSH_TIMEOUT: Duration = Duration::from_millis(200); const FLUSH_TIMEOUT: Duration = Duration::from_millis(200);
let mut buffer = Vec::<String>::with_capacity(16); let mut buffer = Vec::<String>::with_capacity(16);
@ -210,7 +189,7 @@ mod logger_thread {
match msg { match msg {
LoggerCommand::Print(msg) => { LoggerCommand::Print(msg) => {
// Append message to buffer // Append message to buffer
if let Some(msg) = msg.to_processed_message() { if let Some(msg) = msg.to_formatted_message() {
buffer.push(msg); buffer.push(msg);
} }
@ -222,14 +201,13 @@ mod logger_thread {
flush_logs_to_stderr(&mut buffer); flush_logs_to_stderr(&mut buffer);
finished_barrier.wait(); finished_barrier.wait();
} }
LoggerCommand::FlushAndShutdown => { LoggerCommand::FlushAndShutdown { finished_barrier } => {
flush_logs_to_stderr(&mut buffer); flush_logs_to_stderr(&mut buffer);
break; finished_barrier.wait();
return;
} }
} }
} }
shutdown_barrier.wait();
} }
fn flush_logs_to_stderr(buffer: &mut Vec<String>) { fn flush_logs_to_stderr(buffer: &mut Vec<String>) {

View File

@ -2,4 +2,4 @@
source: tests/ui.rs source: tests/ui.rs
expression: "run_ouch(\"ouch compress input output.gz\", dir)" expression: "run_ouch(\"ouch compress input output.gz\", dir)"
--- ---
[INFO] Successfully compressed 'output.gz'. [INFO] Successfully compressed 'output.gz'

View File

@ -2,5 +2,5 @@
source: tests/ui.rs source: tests/ui.rs
expression: "run_ouch(\"ouch compress input output.zip\", dir)" expression: "run_ouch(\"ouch compress input output.zip\", dir)"
--- ---
[INFO] Compressing 'input'. [INFO] Compressing 'input'
[INFO] Successfully compressed 'output.zip'. [INFO] Successfully compressed 'output.zip'

View File

@ -2,5 +2,5 @@
source: tests/ui.rs source: tests/ui.rs
expression: "run_ouch(\"ouch decompress output.zst\", dir)" expression: "run_ouch(\"ouch decompress output.zst\", dir)"
--- ---
[INFO] Successfully decompressed archive in current directory. [INFO] Successfully decompressed archive in current directory
[INFO] Files unpacked: 1 [INFO] Files unpacked: 1

View File

@ -2,5 +2,5 @@
source: tests/ui.rs source: tests/ui.rs
expression: "run_ouch(\"ouch compress input output1 --format tar.gz\", dir)" expression: "run_ouch(\"ouch compress input output1 --format tar.gz\", dir)"
--- ---
[INFO] Compressing 'input'. [INFO] Compressing 'input'
[INFO] Successfully compressed 'output1'. [INFO] Successfully compressed 'output1'

View File

@ -2,5 +2,5 @@
source: tests/ui.rs source: tests/ui.rs
expression: "run_ouch(\"ouch compress input output2 --format .tar.gz\", dir)" expression: "run_ouch(\"ouch compress input output2 --format .tar.gz\", dir)"
--- ---
[INFO] Compressing 'input'. [INFO] Compressing 'input'
[INFO] Successfully compressed 'output2'. [INFO] Successfully compressed 'output2'

View File

@ -2,5 +2,5 @@
source: tests/ui.rs source: tests/ui.rs
expression: "run_ouch(\"ouch compress input output1 --format tar.gz\", dir)" expression: "run_ouch(\"ouch compress input output1 --format tar.gz\", dir)"
--- ---
[INFO] Compressing 'input'. [INFO] Compressing 'input'
[INFO] Successfully compressed 'output1'. [INFO] Successfully compressed 'output1'

View File

@ -2,5 +2,5 @@
source: tests/ui.rs source: tests/ui.rs
expression: "run_ouch(\"ouch compress input output2 --format .tar.gz\", dir)" expression: "run_ouch(\"ouch compress input output2 --format .tar.gz\", dir)"
--- ---
[INFO] Compressing 'input'. [INFO] Compressing 'input'
[INFO] Successfully compressed 'output2'. [INFO] Successfully compressed 'output2'