From e989db7a3a4f205cfadf4cd7c9c3a92a88b4ed37 Mon Sep 17 00:00:00 2001 From: Antonios Barotsis Date: Thu, 7 Mar 2024 21:29:15 +0100 Subject: [PATCH] Added buffering --- src/archive/tar.rs | 25 +++++--- src/archive/zip.rs | 32 +++++++---- src/commands/decompress.rs | 113 +++++++++++++++++++++---------------- src/commands/mod.rs | 36 ++++++++---- src/utils/io.rs | 4 +- 5 files changed, 129 insertions(+), 81 deletions(-) diff --git a/src/archive/tar.rs b/src/archive/tar.rs index b8f01f9..b4fffa5 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -21,7 +21,12 @@ use crate::{ /// Unpacks the archive given by `archive` into the folder given by `into`. /// Assumes that output_folder is empty -pub fn unpack_archive(reader: Box, output_folder: &Path, quiet: bool, log_sender: Sender) -> crate::Result { +pub fn unpack_archive( + reader: Box, + output_folder: &Path, + quiet: bool, + log_sender: Sender, +) -> crate::Result { assert!(output_folder.read_dir().expect("dir exists").count() == 0); let mut archive = tar::Archive::new(reader); @@ -36,14 +41,16 @@ pub fn unpack_archive(reader: Box, output_folder: &Path, quiet: bool, // spoken text for users using screen readers, braille displays // and so on if !quiet { - log_sender.send(PrintMessage { - contents: format!( - "{:?} extracted. ({})", - utils::strip_cur_dir(&output_folder.join(file.path()?)), - Bytes::new(file.size()), - ), - accessible: false - }).unwrap(); + log_sender + .send(PrintMessage { + contents: format!( + "{:?} extracted. ({})", + utils::strip_cur_dir(&output_folder.join(file.path()?)), + Bytes::new(file.size()), + ), + accessible: false, + }) + .unwrap(); files_unpacked += 1; } diff --git a/src/archive/zip.rs b/src/archive/zip.rs index e9bde15..8cb48ce 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -6,7 +6,7 @@ use std::{ env, io::{self, prelude::*}, path::{Path, PathBuf}, - sync::mpsc, + sync::mpsc::{self, Sender}, thread, }; @@ -21,15 +21,20 @@ use crate::{ info, 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, io::PrintMessage, pretty_format_list_of_paths, + strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy, }, warning, }; /// Unpacks the archive given by `archive` into the folder given by `output_folder`. /// Assumes that output_folder is empty -pub fn unpack_archive(mut archive: ZipArchive, output_folder: &Path, quiet: bool) -> crate::Result +pub fn unpack_archive( + mut archive: ZipArchive, + output_folder: &Path, + quiet: bool, + log_sender: Sender, +) -> crate::Result where R: Read + Seek, { @@ -55,7 +60,12 @@ where // spoken text for users using screen readers, braille displays // and so on if !quiet { - info!(inaccessible, "File {} extracted to \"{}\"", idx, file_path.display()); + log_sender + .send(PrintMessage { + contents: format!("File {} extracted to \"{}\"", idx, file_path.display()), + accessible: false, + }) + .unwrap(); } fs::create_dir_all(&file_path)?; } @@ -69,12 +79,12 @@ where // same reason is in _is_dir: long, often not needed text if !quiet { - info!( - inaccessible, - "{:?} extracted. ({})", - file_path.display(), - Bytes::new(file.size()), - ); + log_sender + .send(PrintMessage { + contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(file.size()),), + accessible: false, + }) + .unwrap(); } let mut output_file = fs::File::create(file_path)?; diff --git a/src/commands/decompress.rs b/src/commands/decompress.rs index ed17f43..0db9eae 100644 --- a/src/commands/decompress.rs +++ b/src/commands/decompress.rs @@ -1,7 +1,8 @@ use std::{ io::{self, BufReader, Read}, ops::ControlFlow, - path::{Path, PathBuf}, sync::mpsc::Sender, + path::{Path, PathBuf}, + sync::mpsc::Sender, }; use fs_err as fs; @@ -50,7 +51,7 @@ 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), + |output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet, log_sender.clone()), output_dir, &output_file_path, question_policy, @@ -65,14 +66,16 @@ 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 - log_sender.send(PrintMessage { - contents: format!( - "Successfully decompressed archive in {} ({} files).", - nice_directory_display(output_dir), - files_unpacked - ), - accessible: true - }).unwrap(); + log_sender + .send(PrintMessage { + contents: format!( + "Successfully decompressed archive in {} ({} files).", + nice_directory_display(output_dir), + files_unpacked + ), + accessible: true, + }) + .unwrap(); return Ok(()); } @@ -141,7 +144,7 @@ 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), + |output_dir| crate::archive::zip::unpack_archive(zip_archive, output_dir, quiet, log_sender.clone()), output_dir, &output_file_path, question_policy, @@ -163,9 +166,13 @@ pub fn decompress_file( 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, log_sender.clone())? - { + if let ControlFlow::Continue(files) = smart_unpack( + unpack_fn, + output_dir, + &output_file_path, + question_policy, + log_sender.clone(), + )? { files } else { return Ok(()); @@ -205,17 +212,21 @@ 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 - log_sender.send(PrintMessage { - contents: format!( - "Successfully decompressed archive in {}.", - nice_directory_display(output_dir) - ), - accessible: true - }).unwrap(); - log_sender.send(PrintMessage { - contents: format!("Files unpacked: {}", files_unpacked), - accessible: true - }).unwrap(); + log_sender + .send(PrintMessage { + contents: format!( + "Successfully decompressed archive in {}.", + nice_directory_display(output_dir) + ), + accessible: true, + }) + .unwrap(); + log_sender + .send(PrintMessage { + contents: format!("Files unpacked: {}", files_unpacked), + accessible: true, + }) + .unwrap(); Ok(()) } @@ -236,13 +247,15 @@ fn smart_unpack( let temp_dir = tempfile::tempdir_in(output_dir)?; let temp_dir_path = temp_dir.path(); - log_sender.send(PrintMessage { - contents: format!( - "Created temporary directory {} to hold decompressed elements.", - nice_directory_display(temp_dir_path) - ), - accessible: true - }).unwrap(); + log_sender + .send(PrintMessage { + contents: format!( + "Created temporary directory {} to hold decompressed elements.", + nice_directory_display(temp_dir_path) + ), + accessible: true, + }) + .unwrap(); let files = unpack_fn(temp_dir_path)?; @@ -261,14 +274,16 @@ fn smart_unpack( } fs::rename(&file_path, &correct_path)?; - log_sender.send(PrintMessage { - contents: format!( - "Successfully moved {} to {}.", - nice_directory_display(&file_path), - nice_directory_display(&correct_path) - ), - accessible: true - }).unwrap(); + log_sender + .send(PrintMessage { + contents: format!( + "Successfully moved {} to {}.", + nice_directory_display(&file_path), + nice_directory_display(&correct_path) + ), + accessible: true, + }) + .unwrap(); } else { // Multiple files in the root directory, so: // Rename the temporary directory to the archive name, which is output_file_path @@ -277,14 +292,16 @@ fn smart_unpack( return Ok(ControlFlow::Break(())); } fs::rename(temp_dir_path, output_file_path)?; - log_sender.send(PrintMessage { - contents: format!( - "Successfully moved {} to {}.", - nice_directory_display(temp_dir_path), - nice_directory_display(output_file_path) - ), - accessible: true - }).unwrap(); + log_sender + .send(PrintMessage { + contents: format!( + "Successfully moved {} to {}.", + nice_directory_display(temp_dir_path), + nice_directory_display(output_file_path) + ), + accessible: true, + }) + .unwrap(); } Ok(ControlFlow::Continue(files)) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index c0f751d..ce35cf7 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -4,7 +4,11 @@ mod compress; mod decompress; mod list; -use std::{ops::ControlFlow, path::PathBuf, sync::{mpsc::channel, Arc, Condvar, Mutex}}; +use std::{ + ops::ControlFlow, + path::PathBuf, + sync::{mpsc::channel, Arc, Condvar, Mutex}, +}; use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use utils::colors; @@ -176,11 +180,21 @@ pub fn run( // Log received messages until all senders are dropped rayon::spawn(move || { + let mut buffer = Vec::::with_capacity(10); + loop { let msg = log_receiver.recv(); if let Ok(msg) = msg { - println!("{}", msg.contents); + if buffer.len() == 10 { + let mut tmp = buffer.join("\n"); + tmp.push_str(&msg.contents); + println!("{}", tmp); + buffer.clear(); + } else { + buffer.push(msg.contents); + } } else { + println!("{}", buffer.join("\n")); let (lock, cvar) = &*pair2; let mut flushed = lock.lock().unwrap(); *flushed = true; @@ -207,16 +221,16 @@ pub fn run( ) })?; - // Drop our sender clones so when all threads are done, no clones are left - drop(log_sender); + // Drop our sender clones so when all threads are done, no clones are left + drop(log_sender); - // Prevent the main thread from exiting until the background thread handling the - // logging has set `flushed` to true. - let (lock, cvar) = &*pair; - let mut flushed = lock.lock().unwrap(); - while !*flushed { - flushed = cvar.wait(flushed).unwrap(); - } + // Prevent the main thread from exiting until the background thread handling the + // logging has set `flushed` to true. + let (lock, cvar) = &*pair; + let mut flushed = lock.lock().unwrap(); + while !*flushed { + flushed = cvar.wait(flushed).unwrap(); + } } Subcommand::List { archives: files, tree } => { let mut formats = vec![]; diff --git a/src/utils/io.rs b/src/utils/io.rs index 618077f..b8adc87 100644 --- a/src/utils/io.rs +++ b/src/utils/io.rs @@ -1,5 +1,5 @@ #[derive(Debug)] pub struct PrintMessage { - pub contents: String, - pub accessible: bool, + pub contents: String, + pub accessible: bool, }