add OutputLine trait for performance improvements

This commit is contained in:
figsoda 2022-10-13 11:31:43 -04:00
parent dd6ab2aa6e
commit 51855948f1
8 changed files with 61 additions and 51 deletions

View File

@ -14,6 +14,7 @@ use crate::{
error::FinalError, error::FinalError,
info, info,
list::FileInArchive, list::FileInArchive,
progress::OutputLine,
utils::{self, Bytes, FileVisibilityPolicy}, utils::{self, Bytes, FileVisibilityPolicy},
}; };
@ -22,7 +23,7 @@ use crate::{
pub fn unpack_archive( pub fn unpack_archive(
reader: Box<dyn Read>, reader: Box<dyn Read>,
output_folder: &Path, output_folder: &Path,
mut log_out: impl Write, mut log_out: impl OutputLine,
) -> crate::Result<Vec<PathBuf>> { ) -> crate::Result<Vec<PathBuf>> {
assert!(output_folder.read_dir().expect("dir exists").count() == 0); assert!(output_folder.read_dir().expect("dir exists").count() == 0);
let mut archive = tar::Archive::new(reader); let mut archive = tar::Archive::new(reader);
@ -90,7 +91,7 @@ pub fn build_archive_from_paths<W, D>(
) -> crate::Result<W> ) -> crate::Result<W>
where where
W: Write, W: Write,
D: Write, D: OutputLine,
{ {
let mut builder = tar::Builder::new(writer); let mut builder = tar::Builder::new(writer);

View File

@ -19,6 +19,7 @@ use crate::{
error::FinalError, error::FinalError,
info, info,
list::FileInArchive, list::FileInArchive,
progress::OutputLine,
utils::{ utils::{
self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, to_utf, Bytes, self, cd_into_same_dir_as, get_invalid_utf8_paths, pretty_format_list_of_paths, strip_cur_dir, to_utf, Bytes,
FileVisibilityPolicy, FileVisibilityPolicy,
@ -34,7 +35,7 @@ pub fn unpack_archive<R, D>(
) -> crate::Result<Vec<PathBuf>> ) -> crate::Result<Vec<PathBuf>>
where where
R: Read + Seek, R: Read + Seek,
D: Write, D: OutputLine,
{ {
assert!(output_folder.read_dir().expect("dir exists").count() == 0); assert!(output_folder.read_dir().expect("dir exists").count() == 0);
@ -141,7 +142,7 @@ pub fn build_archive_from_paths<W, D>(
) -> crate::Result<W> ) -> crate::Result<W>
where where
W: Write + Seek, W: Write + Seek,
D: Write, D: OutputLine,
{ {
let mut writer = zip::ZipWriter::new(writer); let mut writer = zip::ZipWriter::new(writer);
let options = zip::write::FileOptions::default(); let options = zip::write::FileOptions::default();

View File

@ -89,7 +89,7 @@ pub fn compress_files(
} }
Tar => { Tar => {
if is_running_in_accessible_mode() { if is_running_in_accessible_mode() {
archive::tar::build_archive_from_paths(&files, &mut writer, file_visibility_policy, io::stdout())?; archive::tar::build_archive_from_paths(&files, &mut writer, file_visibility_policy, io::stderr())?;
writer.flush()?; writer.flush()?;
} else { } else {
let mut progress = Progress::new(total_input_size, precise, true); let mut progress = Progress::new(total_input_size, precise, true);
@ -111,7 +111,7 @@ pub fn compress_files(
let mut vec_buffer = Cursor::new(vec![]); let mut vec_buffer = Cursor::new(vec![]);
if is_running_in_accessible_mode() { if is_running_in_accessible_mode() {
archive::zip::build_archive_from_paths(&files, &mut vec_buffer, file_visibility_policy, io::stdout())?; archive::zip::build_archive_from_paths(&files, &mut vec_buffer, file_visibility_policy, io::stderr())?;
vec_buffer.rewind()?; vec_buffer.rewind()?;
io::copy(&mut vec_buffer, &mut writer)?; io::copy(&mut vec_buffer, &mut writer)?;
} else { } else {

View File

@ -1,5 +1,5 @@
use std::{ use std::{
io::{self, BufReader, Read, Write}, io::{self, BufReader, Read},
ops::ControlFlow, ops::ControlFlow,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -15,7 +15,7 @@ use crate::{
Extension, Extension,
}, },
info, info,
progress::Progress, progress::{OutputLine, Progress},
utils::{self, nice_directory_display, user_wants_to_continue}, utils::{self, nice_directory_display, user_wants_to_continue},
QuestionAction, QuestionPolicy, BUFFER_CAPACITY, QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
}; };
@ -183,7 +183,7 @@ pub fn decompress_file(
/// output_dir named after the archive (given by `output_file_path`) /// output_dir named after the archive (given by `output_file_path`)
/// Note: This functions assumes that `output_dir` exists /// Note: This functions assumes that `output_dir` exists
fn smart_unpack( fn smart_unpack(
unpack_fn: impl FnOnce(&Path, &mut dyn Write) -> crate::Result<Vec<PathBuf>>, unpack_fn: impl FnOnce(&Path, &mut dyn OutputLine) -> crate::Result<Vec<PathBuf>>,
total_input_size: u64, total_input_size: u64,
output_dir: &Path, output_dir: &Path,
output_file_path: &Path, output_file_path: &Path,
@ -200,7 +200,7 @@ fn smart_unpack(
// unpack the files // unpack the files
let files = if is_running_in_accessible_mode() { let files = if is_running_in_accessible_mode() {
unpack_fn(temp_dir_path, &mut io::stdout()) unpack_fn(temp_dir_path, &mut io::stderr())
} else { } else {
unpack_fn(temp_dir_path, &mut Progress::new(total_input_size, true, false)) unpack_fn(temp_dir_path, &mut Progress::new(total_input_size, true, false))
}?; }?;

View File

@ -5,7 +5,6 @@ mod decompress;
mod list; mod list;
use std::{ use std::{
io::Write,
ops::ControlFlow, ops::ControlFlow,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -19,6 +18,7 @@ use crate::{
extension::{self, flatten_compression_formats, Extension, SUPPORTED_EXTENSIONS}, extension::{self, flatten_compression_formats, Extension, SUPPORTED_EXTENSIONS},
info, info,
list::ListOptions, list::ListOptions,
progress::OutputLine,
utils::{ utils::{
self, dir_is_empty, pretty_format_list_of_paths, to_utf, try_infer_extension, user_wants_to_continue, self, dir_is_empty, pretty_format_list_of_paths, to_utf, try_infer_extension, user_wants_to_continue,
FileVisibilityPolicy, FileVisibilityPolicy,

View File

@ -25,35 +25,26 @@ macro_rules! info {
// Accessible (short/important) info message. // Accessible (short/important) info message.
// Show info message even in ACCESSIBLE mode // Show info message even in ACCESSIBLE mode
(accessible, $($arg:tt)*) => { (accessible, $($arg:tt)*) => {
info!(@::std::io::stdout(), accessible, $($arg)*); info!(@::std::io::stderr(), accessible, $($arg)*);
}; };
(@$log_out: expr, accessible, $($arg:tt)*) => { (@$log_out: expr, accessible, $($arg:tt)*) => {{
let log_out = &mut $log_out;
// if in ACCESSIBLE mode, suppress the "[INFO]" and just print the message // if in ACCESSIBLE mode, suppress the "[INFO]" and just print the message
if !$crate::accessible::is_running_in_accessible_mode() { if !$crate::accessible::is_running_in_accessible_mode() {
$crate::macros::_info_helper(log_out); $log_out.output_line_info(format_args!($($arg)*));
} else {
$log_out.output_line(format_args!($($arg)*));
} }
writeln!(log_out, $($arg)*).unwrap(); }};
};
// Inccessible (long/no important) info message. // Inccessible (long/no important) info message.
// Print info message if ACCESSIBLE is not turned on // Print info message if ACCESSIBLE is not turned on
(inaccessible, $($arg:tt)*) => { (inaccessible, $($arg:tt)*) => {
info!(@::std::io::stdout(), inaccessible, $($arg)*); info!(@::std::io::stderr(), inaccessible, $($arg)*);
}; };
(@$log_out: expr, inaccessible, $($arg:tt)*) => { (@$log_out: expr, inaccessible, $($arg:tt)*) => {{
if !$crate::accessible::is_running_in_accessible_mode() { if !$crate::accessible::is_running_in_accessible_mode() {
let log_out = &mut $log_out; $log_out.output_line_info(format_args!($($arg)*));
$crate::macros::_info_helper(log_out);
writeln!(log_out, $($arg)*).unwrap();
} }
}; }};
}
/// Helper to display "\[INFO\]", colored yellow
pub fn _info_helper(handle: &mut impl std::io::Write) {
use crate::utils::colors::{RESET, YELLOW};
write!(handle, "{}[INFO]{} ", *YELLOW, *RESET).unwrap();
} }
/// Macro that prints \[WARNING\] messages, wraps [`eprintln`]. /// Macro that prints \[WARNING\] messages, wraps [`eprintln`].

View File

@ -1,35 +1,52 @@
//! Module that provides functions to display progress bars for compressing and decompressing files. //! Module that provides functions to display progress bars for compressing and decompressing files.
use std::{ use std::{
io::{self, Read, Write}, fmt::Arguments,
mem, io::{Read, Stderr, Write},
}; };
use indicatif::{ProgressBar, ProgressBarIter, ProgressStyle}; use indicatif::{ProgressBar, ProgressBarIter, ProgressStyle};
use crate::utils::colors::{RESET, YELLOW};
/// Draw a ProgressBar using a function that checks periodically for the progress /// Draw a ProgressBar using a function that checks periodically for the progress
pub struct Progress { pub struct Progress {
bar: ProgressBar, bar: ProgressBar,
buf: Vec<u8>,
} }
impl Write for Progress { pub trait OutputLine {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn output_line(&mut self, args: Arguments);
self.buf.extend(buf); fn output_line_info(&mut self, args: Arguments);
}
if self.buf.last() == Some(&b'\n') { impl OutputLine for Progress {
self.buf.pop(); fn output_line(&mut self, args: Arguments) {
self.flush()?; self.bar.set_message(args.to_string());
} }
Ok(buf.len()) fn output_line_info(&mut self, args: Arguments) {
self.bar.set_message(format!("{}[INFO]{}{args}", *YELLOW, *RESET));
}
}
impl OutputLine for Stderr {
fn output_line(&mut self, args: Arguments) {
self.write_fmt(args).unwrap();
} }
fn flush(&mut self) -> io::Result<()> { fn output_line_info(&mut self, args: Arguments) {
self.bar.set_message( write!(self, "{}[INFO]{} {args}", *YELLOW, *RESET).unwrap();
String::from_utf8(mem::take(&mut self.buf)) self.write_fmt(args).unwrap();
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to parse buffer content as utf8"))?, self.write_all(b"\n").unwrap();
); }
Ok(()) }
impl<T: OutputLine + ?Sized> OutputLine for &mut T {
fn output_line(&mut self, args: Arguments) {
(*self).output_line(args)
}
fn output_line_info(&mut self, args: Arguments) {
(*self).output_line_info(args);
} }
} }
@ -55,7 +72,7 @@ impl Progress {
let bar = ProgressBar::new(total_input_size) let bar = ProgressBar::new(total_input_size)
.with_style(ProgressStyle::with_template(&template).unwrap().progress_chars("#>-")); .with_style(ProgressStyle::with_template(&template).unwrap().progress_chars("#>-"));
Progress { bar, buf: Vec::new() } Progress { bar }
} }
pub(crate) fn wrap_read<R: Read>(&self, read: R) -> ProgressBarIter<R> { pub(crate) fn wrap_read<R: Read>(&self, read: R) -> ProgressBarIter<R> {

View File

@ -3,14 +3,14 @@
use std::{ use std::{
env, env,
fs::ReadDir, fs::ReadDir,
io::{Read, Write}, io::Read,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use fs_err as fs; use fs_err as fs;
use super::{to_utf, user_wants_to_overwrite}; use super::{to_utf, user_wants_to_overwrite};
use crate::{extension::Extension, info, QuestionPolicy}; use crate::{extension::Extension, info, progress::OutputLine, QuestionPolicy};
/// Checks if given path points to an empty directory. /// Checks if given path points to an empty directory.
pub fn dir_is_empty(dir_path: &Path) -> bool { pub fn dir_is_empty(dir_path: &Path) -> bool {