mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-07 12:05:46 +00:00
add OutputLine trait for performance improvements
This commit is contained in:
parent
dd6ab2aa6e
commit
51855948f1
@ -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);
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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 {
|
||||||
|
@ -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))
|
||||||
}?;
|
}?;
|
||||||
|
@ -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,
|
||||||
|
@ -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`].
|
||||||
|
@ -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 flush(&mut self) -> io::Result<()> {
|
fn output_line_info(&mut self, args: Arguments) {
|
||||||
self.bar.set_message(
|
self.bar.set_message(format!("{}[INFO]{}{args}", *YELLOW, *RESET));
|
||||||
String::from_utf8(mem::take(&mut self.buf))
|
}
|
||||||
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to parse buffer content as utf8"))?,
|
}
|
||||||
);
|
|
||||||
Ok(())
|
impl OutputLine for Stderr {
|
||||||
|
fn output_line(&mut self, args: Arguments) {
|
||||||
|
self.write_fmt(args).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn output_line_info(&mut self, args: Arguments) {
|
||||||
|
write!(self, "{}[INFO]{} {args}", *YELLOW, *RESET).unwrap();
|
||||||
|
self.write_fmt(args).unwrap();
|
||||||
|
self.write_all(b"\n").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user