mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 11:35:45 +00:00
Make all info logs use the new system
This commit is contained in:
parent
e989db7a3a
commit
e2ac5c4c9b
@ -1,14 +1,19 @@
|
|||||||
//! Contains RAR-specific building and unpacking functions
|
//! Contains RAR-specific building and unpacking functions
|
||||||
|
|
||||||
use std::path::Path;
|
use std::{path::Path, sync::mpsc::Sender};
|
||||||
|
|
||||||
use unrar::{self, Archive};
|
use unrar::Archive;
|
||||||
|
|
||||||
use crate::{error::Error, info, list::FileInArchive};
|
use crate::{error::Error, list::FileInArchive, utils::message::PrintMessage};
|
||||||
|
|
||||||
/// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
|
/// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
|
||||||
/// Assumes that output_folder is empty
|
/// Assumes that output_folder is empty
|
||||||
pub fn unpack_archive(archive_path: &Path, output_folder: &Path, quiet: bool) -> crate::Result<usize> {
|
pub fn unpack_archive(
|
||||||
|
archive_path: &Path,
|
||||||
|
output_folder: &Path,
|
||||||
|
quiet: bool,
|
||||||
|
log_sender: Sender<PrintMessage>,
|
||||||
|
) -> crate::Result<usize> {
|
||||||
assert!(output_folder.read_dir().expect("dir exists").count() == 0);
|
assert!(output_folder.read_dir().expect("dir exists").count() == 0);
|
||||||
|
|
||||||
let mut archive = Archive::new(archive_path).open_for_processing()?;
|
let mut archive = Archive::new(archive_path).open_for_processing()?;
|
||||||
@ -18,12 +23,12 @@ pub fn unpack_archive(archive_path: &Path, output_folder: &Path, quiet: bool) ->
|
|||||||
let entry = header.entry();
|
let entry = header.entry();
|
||||||
archive = if entry.is_file() {
|
archive = if entry.is_file() {
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(
|
log_sender
|
||||||
inaccessible,
|
.send(PrintMessage {
|
||||||
"{} extracted. ({})",
|
contents: format!("{} extracted. ({})", entry.filename.display(), entry.unpacked_size),
|
||||||
entry.filename.display(),
|
accessible: false,
|
||||||
entry.unpacked_size
|
})
|
||||||
);
|
.unwrap();
|
||||||
}
|
}
|
||||||
unpacked += 1;
|
unpacked += 1;
|
||||||
header.extract_with_base(output_folder)?
|
header.extract_with_base(output_folder)?
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
//! SevenZip archive format compress function
|
//! SevenZip archive format compress function
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env, io,
|
env,
|
||||||
io::{Read, Seek, Write},
|
io::{self, Read, Seek, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
sync::mpsc::Sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
@ -11,8 +12,7 @@ use same_file::Handle;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::FinalError,
|
error::FinalError,
|
||||||
info,
|
utils::{self, cd_into_same_dir_as, message::PrintMessage, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
|
||||||
utils::{self, cd_into_same_dir_as, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
|
|
||||||
warning,
|
warning,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -22,6 +22,7 @@ pub fn compress_sevenz<W>(
|
|||||||
writer: W,
|
writer: W,
|
||||||
file_visibility_policy: FileVisibilityPolicy,
|
file_visibility_policy: FileVisibilityPolicy,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
|
log_sender: Sender<PrintMessage>,
|
||||||
) -> crate::Result<W>
|
) -> crate::Result<W>
|
||||||
where
|
where
|
||||||
W: Write + Seek,
|
W: Write + Seek,
|
||||||
@ -56,7 +57,12 @@ where
|
|||||||
// spoken text for users using screen readers, braille displays
|
// spoken text for users using screen readers, braille displays
|
||||||
// and so on
|
// and so on
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path));
|
log_sender
|
||||||
|
.send(PrintMessage {
|
||||||
|
contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)),
|
||||||
|
accessible: false,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadata = match path.metadata() {
|
let metadata = match path.metadata() {
|
||||||
@ -93,7 +99,12 @@ where
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decompress_sevenz<R>(reader: R, output_path: &Path, quiet: bool) -> crate::Result<usize>
|
pub fn decompress_sevenz<R>(
|
||||||
|
reader: R,
|
||||||
|
output_path: &Path,
|
||||||
|
quiet: bool,
|
||||||
|
log_sender: Sender<PrintMessage>,
|
||||||
|
) -> crate::Result<usize>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
@ -109,24 +120,24 @@ where
|
|||||||
|
|
||||||
if entry.is_directory() {
|
if entry.is_directory() {
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(
|
log_sender
|
||||||
inaccessible,
|
.send(PrintMessage {
|
||||||
"File {} extracted to \"{}\"",
|
contents: format!("File {} extracted to \"{}\"", entry.name(), file_path.display()),
|
||||||
entry.name(),
|
accessible: false,
|
||||||
file_path.display()
|
})
|
||||||
);
|
.unwrap();
|
||||||
}
|
}
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
fs::create_dir_all(path)?;
|
fs::create_dir_all(path)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(
|
log_sender
|
||||||
inaccessible,
|
.send(PrintMessage {
|
||||||
"{:?} extracted. ({})",
|
contents: format!("{:?} extracted. ({})", file_path.display(), Bytes::new(entry.size()),),
|
||||||
file_path.display(),
|
accessible: false,
|
||||||
Bytes::new(entry.size()),
|
})
|
||||||
);
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
|
@ -13,9 +13,8 @@ use same_file::Handle;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::FinalError,
|
error::FinalError,
|
||||||
info,
|
|
||||||
list::FileInArchive,
|
list::FileInArchive,
|
||||||
utils::{self, io::PrintMessage, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
|
utils::{self, message::PrintMessage, Bytes, EscapedPathDisplay, FileVisibilityPolicy},
|
||||||
warning,
|
warning,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,6 +94,7 @@ pub fn build_archive_from_paths<W>(
|
|||||||
writer: W,
|
writer: W,
|
||||||
file_visibility_policy: FileVisibilityPolicy,
|
file_visibility_policy: FileVisibilityPolicy,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
|
log_sender: Sender<PrintMessage>,
|
||||||
) -> crate::Result<W>
|
) -> crate::Result<W>
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
@ -129,7 +129,12 @@ where
|
|||||||
// spoken text for users using screen readers, braille displays
|
// spoken text for users using screen readers, braille displays
|
||||||
// and so on
|
// and so on
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path));
|
log_sender
|
||||||
|
.send(PrintMessage {
|
||||||
|
contents: format!("Compressing '{}'.", EscapedPathDisplay::new(path)),
|
||||||
|
accessible: false,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
|
@ -14,15 +14,13 @@ use filetime_creation::{set_file_mtime, FileTime};
|
|||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
use same_file::Handle;
|
use same_file::Handle;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use zip::{self, read::ZipFile, DateTime, ZipArchive};
|
use zip::{read::ZipFile, DateTime, ZipArchive};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::FinalError,
|
error::FinalError,
|
||||||
info,
|
|
||||||
list::FileInArchive,
|
list::FileInArchive,
|
||||||
utils::{
|
utils::{
|
||||||
self, cd_into_same_dir_as, get_invalid_utf8_paths, io::PrintMessage, pretty_format_list_of_paths,
|
self, cd_into_same_dir_as, get_invalid_utf8_paths, message::PrintMessage, pretty_format_list_of_paths, strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy
|
||||||
strip_cur_dir, Bytes, EscapedPathDisplay, FileVisibilityPolicy,
|
|
||||||
},
|
},
|
||||||
warning,
|
warning,
|
||||||
};
|
};
|
||||||
@ -51,7 +49,7 @@ where
|
|||||||
|
|
||||||
let file_path = output_folder.join(file_path);
|
let file_path = output_folder.join(file_path);
|
||||||
|
|
||||||
display_zip_comment_if_exists(&file);
|
display_zip_comment_if_exists(&file, log_sender.clone());
|
||||||
|
|
||||||
match file.name().ends_with('/') {
|
match file.name().ends_with('/') {
|
||||||
_is_dir @ true => {
|
_is_dir @ true => {
|
||||||
@ -147,6 +145,7 @@ pub fn build_archive_from_paths<W>(
|
|||||||
writer: W,
|
writer: W,
|
||||||
file_visibility_policy: FileVisibilityPolicy,
|
file_visibility_policy: FileVisibilityPolicy,
|
||||||
quiet: bool,
|
quiet: bool,
|
||||||
|
log_sender: Sender<PrintMessage>
|
||||||
) -> crate::Result<W>
|
) -> crate::Result<W>
|
||||||
where
|
where
|
||||||
W: Write + Seek,
|
W: Write + Seek,
|
||||||
@ -201,7 +200,14 @@ where
|
|||||||
// spoken text for users using screen readers, braille displays
|
// spoken text for users using screen readers, braille displays
|
||||||
// and so on
|
// and so on
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(inaccessible, "Compressing '{}'.", EscapedPathDisplay::new(path));
|
log_sender
|
||||||
|
.send(PrintMessage {
|
||||||
|
contents: format!(
|
||||||
|
"Compressing '{}'.",
|
||||||
|
EscapedPathDisplay::new(path)
|
||||||
|
),
|
||||||
|
accessible: false,
|
||||||
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadata = match path.metadata() {
|
let metadata = match path.metadata() {
|
||||||
@ -251,7 +257,7 @@ where
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_zip_comment_if_exists(file: &ZipFile) {
|
fn display_zip_comment_if_exists(file: &ZipFile, log_sender: Sender<PrintMessage>) {
|
||||||
let comment = file.comment();
|
let comment = file.comment();
|
||||||
if !comment.is_empty() {
|
if !comment.is_empty() {
|
||||||
// Zip file comments seem to be pretty rare, but if they are used,
|
// Zip file comments seem to be pretty rare, but if they are used,
|
||||||
@ -264,7 +270,12 @@ fn display_zip_comment_if_exists(file: &ZipFile) {
|
|||||||
// the future, maybe asking the user if he wants to display the comment
|
// 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
|
// (informing him of its size) would be sensible for both normal and
|
||||||
// accessibility mode..
|
// accessibility mode..
|
||||||
info!(accessible, "Found comment in {}: {}", file.name(), comment);
|
log_sender
|
||||||
|
.send(PrintMessage {
|
||||||
|
contents: format!("Found comment in {}: {}", file.name(), comment),
|
||||||
|
accessible: true,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
34
src/check.rs
34
src/check.rs
@ -5,14 +5,13 @@
|
|||||||
use std::{
|
use std::{
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
ops::ControlFlow,
|
ops::ControlFlow,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf}, sync::mpsc::Sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::FinalError,
|
error::FinalError,
|
||||||
extension::{build_archive_file_suggestion, Extension, PRETTY_SUPPORTED_ALIASES, PRETTY_SUPPORTED_EXTENSIONS},
|
extension::{build_archive_file_suggestion, Extension, PRETTY_SUPPORTED_ALIASES, PRETTY_SUPPORTED_EXTENSIONS},
|
||||||
info,
|
utils::{message::PrintMessage, 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},
|
|
||||||
warning, QuestionAction, QuestionPolicy, Result,
|
warning, QuestionAction, QuestionPolicy, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,6 +25,7 @@ pub fn check_mime_type(
|
|||||||
path: &Path,
|
path: &Path,
|
||||||
formats: &mut Vec<Extension>,
|
formats: &mut Vec<Extension>,
|
||||||
question_policy: QuestionPolicy,
|
question_policy: QuestionPolicy,
|
||||||
|
log_sender: Sender<PrintMessage>
|
||||||
) -> Result<ControlFlow<()>> {
|
) -> Result<ControlFlow<()>> {
|
||||||
if formats.is_empty() {
|
if formats.is_empty() {
|
||||||
// File with no extension
|
// File with no extension
|
||||||
@ -33,12 +33,15 @@ pub fn check_mime_type(
|
|||||||
if let Some(detected_format) = try_infer_extension(path) {
|
if let Some(detected_format) = try_infer_extension(path) {
|
||||||
// Inferring the file extension can have unpredicted consequences (e.g. the user just
|
// Inferring the file extension can have unpredicted consequences (e.g. the user just
|
||||||
// mistyped, ...) which we should always inform the user about.
|
// mistyped, ...) which we should always inform the user about.
|
||||||
info!(
|
log_sender
|
||||||
accessible,
|
.send(PrintMessage {
|
||||||
"Detected file: `{}` extension as `{}`",
|
contents: format!(
|
||||||
path.display(),
|
"Detected file: `{}` extension as `{}`",
|
||||||
detected_format
|
path.display(),
|
||||||
);
|
detected_format
|
||||||
|
),
|
||||||
|
accessible: true,
|
||||||
|
}).unwrap();
|
||||||
if user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? {
|
if user_wants_to_continue(path, question_policy, QuestionAction::Decompression)? {
|
||||||
formats.push(detected_format);
|
formats.push(detected_format);
|
||||||
} else {
|
} else {
|
||||||
@ -66,11 +69,14 @@ pub fn check_mime_type(
|
|||||||
} else {
|
} else {
|
||||||
// NOTE: If this actually produces no false positives, we can upgrade it in the future
|
// 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.
|
// to a warning and ask the user if he wants to continue decompressing.
|
||||||
info!(
|
log_sender
|
||||||
accessible,
|
.send(PrintMessage {
|
||||||
"Failed to confirm the format of `{}` by sniffing the contents, file might be misnamed",
|
contents: format!(
|
||||||
path.display()
|
"Failed to confirm the format of `{}` by sniffing the contents, file might be misnamed",
|
||||||
);
|
path.display()
|
||||||
|
),
|
||||||
|
accessible: true,
|
||||||
|
}).unwrap();
|
||||||
}
|
}
|
||||||
Ok(ControlFlow::Continue(()))
|
Ok(ControlFlow::Continue(()))
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ mod args;
|
|||||||
use std::{
|
use std::{
|
||||||
io,
|
io,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
vec::Vec,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{self, BufWriter, Cursor, Seek, Write},
|
io::{self, BufWriter, Cursor, Seek, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
sync::mpsc::Sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
@ -10,7 +11,7 @@ use crate::{
|
|||||||
archive,
|
archive,
|
||||||
commands::warn_user_about_loading_zip_in_memory,
|
commands::warn_user_about_loading_zip_in_memory,
|
||||||
extension::{split_first_compression_format, CompressionFormat::*, Extension},
|
extension::{split_first_compression_format, CompressionFormat::*, Extension},
|
||||||
utils::{user_wants_to_continue, FileVisibilityPolicy},
|
utils::{message::PrintMessage, user_wants_to_continue, FileVisibilityPolicy},
|
||||||
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ pub fn compress_files(
|
|||||||
question_policy: QuestionPolicy,
|
question_policy: QuestionPolicy,
|
||||||
file_visibility_policy: FileVisibilityPolicy,
|
file_visibility_policy: FileVisibilityPolicy,
|
||||||
level: Option<i16>,
|
level: Option<i16>,
|
||||||
|
log_sender: Sender<PrintMessage>,
|
||||||
) -> crate::Result<bool> {
|
) -> crate::Result<bool> {
|
||||||
// If the input files contain a directory, then the total size will be underestimated
|
// If the input files contain a directory, then the total size will be underestimated
|
||||||
let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file);
|
let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file);
|
||||||
@ -99,7 +101,14 @@ pub fn compress_files(
|
|||||||
io::copy(&mut reader, &mut writer)?;
|
io::copy(&mut reader, &mut writer)?;
|
||||||
}
|
}
|
||||||
Tar => {
|
Tar => {
|
||||||
archive::tar::build_archive_from_paths(&files, output_path, &mut writer, file_visibility_policy, quiet)?;
|
archive::tar::build_archive_from_paths(
|
||||||
|
&files,
|
||||||
|
output_path,
|
||||||
|
&mut writer,
|
||||||
|
file_visibility_policy,
|
||||||
|
quiet,
|
||||||
|
log_sender.clone(),
|
||||||
|
)?;
|
||||||
writer.flush()?;
|
writer.flush()?;
|
||||||
}
|
}
|
||||||
Zip => {
|
Zip => {
|
||||||
@ -119,6 +128,7 @@ pub fn compress_files(
|
|||||||
&mut vec_buffer,
|
&mut vec_buffer,
|
||||||
file_visibility_policy,
|
file_visibility_policy,
|
||||||
quiet,
|
quiet,
|
||||||
|
log_sender.clone()
|
||||||
)?;
|
)?;
|
||||||
vec_buffer.rewind()?;
|
vec_buffer.rewind()?;
|
||||||
io::copy(&mut vec_buffer, &mut writer)?;
|
io::copy(&mut vec_buffer, &mut writer)?;
|
||||||
@ -140,7 +150,14 @@ pub fn compress_files(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut vec_buffer = Cursor::new(vec![]);
|
let mut vec_buffer = Cursor::new(vec![]);
|
||||||
archive::sevenz::compress_sevenz(&files, output_path, &mut vec_buffer, file_visibility_policy, quiet)?;
|
archive::sevenz::compress_sevenz(
|
||||||
|
&files,
|
||||||
|
output_path,
|
||||||
|
&mut vec_buffer,
|
||||||
|
file_visibility_policy,
|
||||||
|
quiet,
|
||||||
|
log_sender.clone(),
|
||||||
|
)?;
|
||||||
vec_buffer.rewind()?;
|
vec_buffer.rewind()?;
|
||||||
io::copy(&mut vec_buffer, &mut writer)?;
|
io::copy(&mut vec_buffer, &mut writer)?;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@ use crate::{
|
|||||||
CompressionFormat::{self, *},
|
CompressionFormat::{self, *},
|
||||||
Extension,
|
Extension,
|
||||||
},
|
},
|
||||||
info,
|
utils::{self, message::PrintMessage, nice_directory_display, user_wants_to_continue},
|
||||||
utils::{self, io::PrintMessage, nice_directory_display, user_wants_to_continue},
|
|
||||||
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
QuestionAction, QuestionPolicy, BUFFER_CAPACITY,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -161,9 +160,14 @@ pub fn decompress_file(
|
|||||||
let unpack_fn: Box<dyn FnOnce(&Path) -> UnpackResult> = if formats.len() > 1 {
|
let unpack_fn: Box<dyn FnOnce(&Path) -> UnpackResult> = if formats.len() > 1 {
|
||||||
let mut temp_file = tempfile::NamedTempFile::new()?;
|
let mut temp_file = tempfile::NamedTempFile::new()?;
|
||||||
io::copy(&mut reader, &mut temp_file)?;
|
io::copy(&mut reader, &mut temp_file)?;
|
||||||
Box::new(move |output_dir| crate::archive::rar::unpack_archive(temp_file.path(), output_dir, quiet))
|
let log_sender_clone = log_sender.clone();
|
||||||
|
Box::new(move |output_dir| {
|
||||||
|
crate::archive::rar::unpack_archive(temp_file.path(), output_dir, quiet, log_sender_clone)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Box::new(|output_dir| crate::archive::rar::unpack_archive(input_file_path, output_dir, quiet))
|
Box::new(|output_dir| {
|
||||||
|
crate::archive::rar::unpack_archive(input_file_path, output_dir, quiet, log_sender.clone())
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
if let ControlFlow::Continue(files) = smart_unpack(
|
if let ControlFlow::Continue(files) = smart_unpack(
|
||||||
@ -195,7 +199,14 @@ pub fn decompress_file(
|
|||||||
io::copy(&mut reader, &mut vec)?;
|
io::copy(&mut reader, &mut vec)?;
|
||||||
|
|
||||||
if let ControlFlow::Continue(files) = smart_unpack(
|
if let ControlFlow::Continue(files) = smart_unpack(
|
||||||
|output_dir| crate::archive::sevenz::decompress_sevenz(io::Cursor::new(vec), output_dir, quiet),
|
|output_dir| {
|
||||||
|
crate::archive::sevenz::decompress_sevenz(
|
||||||
|
io::Cursor::new(vec),
|
||||||
|
output_dir,
|
||||||
|
quiet,
|
||||||
|
log_sender.clone(),
|
||||||
|
)
|
||||||
|
},
|
||||||
output_dir,
|
output_dir,
|
||||||
&output_file_path,
|
&output_file_path,
|
||||||
question_policy,
|
question_policy,
|
||||||
|
@ -21,7 +21,7 @@ use crate::{
|
|||||||
extension::{self, parse_format},
|
extension::{self, parse_format},
|
||||||
info,
|
info,
|
||||||
list::ListOptions,
|
list::ListOptions,
|
||||||
utils::{self, io::PrintMessage, to_utf, EscapedPathDisplay, FileVisibilityPolicy},
|
utils::{self, message::PrintMessage, to_utf, EscapedPathDisplay, FileVisibilityPolicy},
|
||||||
warning, CliArgs, QuestionPolicy,
|
warning, CliArgs, QuestionPolicy,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,6 +54,45 @@ pub fn run(
|
|||||||
question_policy: QuestionPolicy,
|
question_policy: QuestionPolicy,
|
||||||
file_visibility_policy: FileVisibilityPolicy,
|
file_visibility_policy: FileVisibilityPolicy,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
|
let (log_sender, log_receiver) = channel::<PrintMessage>();
|
||||||
|
|
||||||
|
let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
let pair2 = Arc::clone(&pair);
|
||||||
|
|
||||||
|
// Log received messages until all senders are dropped
|
||||||
|
rayon::spawn(move || {
|
||||||
|
const BUFFER_SIZE: usize = 10;
|
||||||
|
let mut buffer = Vec::<String>::with_capacity(BUFFER_SIZE);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let msg = log_receiver.recv();
|
||||||
|
|
||||||
|
// Senders are still active
|
||||||
|
if let Ok(msg) = msg {
|
||||||
|
// Print messages if buffer is full otherwise append to it
|
||||||
|
if buffer.len() == BUFFER_SIZE {
|
||||||
|
let mut tmp = buffer.join("\n");
|
||||||
|
tmp.push_str(&msg.contents);
|
||||||
|
|
||||||
|
println!("{}", tmp);
|
||||||
|
buffer.clear();
|
||||||
|
} else {
|
||||||
|
buffer.push(msg.contents);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// All senders have been dropped
|
||||||
|
println!("{}", buffer.join("\n"));
|
||||||
|
|
||||||
|
// Wake up the main thread
|
||||||
|
let (lock, cvar) = &*pair2;
|
||||||
|
let mut flushed = lock.lock().unwrap();
|
||||||
|
*flushed = true;
|
||||||
|
cvar.notify_one();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
match args.cmd {
|
match args.cmd {
|
||||||
Subcommand::Compress {
|
Subcommand::Compress {
|
||||||
files,
|
files,
|
||||||
@ -106,6 +145,7 @@ pub fn run(
|
|||||||
question_policy,
|
question_policy,
|
||||||
file_visibility_policy,
|
file_visibility_policy,
|
||||||
level,
|
level,
|
||||||
|
log_sender.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(true) = compress_result {
|
if let Ok(true) = compress_result {
|
||||||
@ -113,7 +153,12 @@ pub fn run(
|
|||||||
// having a final status message is important especially in an accessibility context
|
// 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
|
// as screen readers may not read a commands exit code, making it hard to reason
|
||||||
// about whether the command succeeded without such a message
|
// about whether the command succeeded without such a message
|
||||||
info!(accessible, "Successfully compressed '{}'.", to_utf(&output_path));
|
log_sender
|
||||||
|
.send(PrintMessage {
|
||||||
|
contents: format!("Successfully compressed '{}'.", to_utf(&output_path)),
|
||||||
|
accessible: true,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
// If Ok(false) or Err() occurred, delete incomplete file at `output_path`
|
// If Ok(false) or Err() occurred, delete incomplete file at `output_path`
|
||||||
//
|
//
|
||||||
@ -153,7 +198,7 @@ pub fn run(
|
|||||||
for path in files.iter() {
|
for path in files.iter() {
|
||||||
let (pathbase, mut file_formats) = extension::separate_known_extensions_from_name(path);
|
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)? {
|
if let ControlFlow::Break(_) = check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,43 +212,12 @@ pub fn run(
|
|||||||
// The directory that will contain the output files
|
// 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
|
// 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 {
|
let output_dir = if let Some(dir) = output_dir {
|
||||||
utils::create_dir_if_non_existent(&dir)?;
|
utils::create_dir_if_non_existent(&dir, log_sender.clone())?;
|
||||||
dir
|
dir
|
||||||
} else {
|
} else {
|
||||||
PathBuf::from(".")
|
PathBuf::from(".")
|
||||||
};
|
};
|
||||||
|
|
||||||
let (log_sender, log_receiver) = channel::<PrintMessage>();
|
|
||||||
|
|
||||||
let pair = Arc::new((Mutex::new(false), Condvar::new()));
|
|
||||||
let pair2 = Arc::clone(&pair);
|
|
||||||
|
|
||||||
// Log received messages until all senders are dropped
|
|
||||||
rayon::spawn(move || {
|
|
||||||
let mut buffer = Vec::<String>::with_capacity(10);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let msg = log_receiver.recv();
|
|
||||||
if let Ok(msg) = msg {
|
|
||||||
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;
|
|
||||||
cvar.notify_one();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
files
|
files
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.zip(formats)
|
.zip(formats)
|
||||||
@ -220,17 +234,6 @@ pub fn run(
|
|||||||
log_sender.clone(),
|
log_sender.clone(),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Subcommand::List { archives: files, tree } => {
|
Subcommand::List { archives: files, tree } => {
|
||||||
let mut formats = vec![];
|
let mut formats = vec![];
|
||||||
@ -244,7 +247,7 @@ pub fn run(
|
|||||||
for path in files.iter() {
|
for path in files.iter() {
|
||||||
let mut file_formats = extension::extensions_from_path(path);
|
let mut file_formats = extension::extensions_from_path(path);
|
||||||
|
|
||||||
if let ControlFlow::Break(_) = check::check_mime_type(path, &mut file_formats, question_policy)? {
|
if let ControlFlow::Break(_) = check::check_mime_type(path, &mut file_formats, question_policy, log_sender.clone())? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,5 +269,15 @@ pub fn run(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop our sender 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 guard = lock.lock().unwrap();
|
||||||
|
let _flushed = cvar.wait(guard).unwrap();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -248,8 +248,6 @@ pub fn build_archive_file_suggestion(path: &Path, suggested_extension: &str) ->
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -78,7 +78,6 @@ mod tree {
|
|||||||
use std::{
|
use std::{
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
io::Write,
|
io::Write,
|
||||||
iter::FromIterator,
|
|
||||||
path,
|
path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,12 +4,13 @@ use std::{
|
|||||||
env,
|
env,
|
||||||
io::Read,
|
io::Read,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
sync::mpsc::Sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
use fs_err as fs;
|
use fs_err as fs;
|
||||||
|
|
||||||
use super::user_wants_to_overwrite;
|
use super::{message::PrintMessage, user_wants_to_overwrite};
|
||||||
use crate::{extension::Extension, info, utils::EscapedPathDisplay, QuestionPolicy};
|
use crate::{extension::Extension, utils::EscapedPathDisplay, QuestionPolicy};
|
||||||
|
|
||||||
/// Remove `path` asking the user to overwrite if necessary.
|
/// Remove `path` asking the user to overwrite if necessary.
|
||||||
///
|
///
|
||||||
@ -36,12 +37,17 @@ pub fn remove_file_or_dir(path: &Path) -> crate::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a directory at the path, if there is nothing there.
|
/// Creates a directory at the path, if there is nothing there.
|
||||||
pub fn create_dir_if_non_existent(path: &Path) -> crate::Result<()> {
|
pub fn create_dir_if_non_existent(path: &Path, log_sender: Sender<PrintMessage>) -> crate::Result<()> {
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
fs::create_dir_all(path)?;
|
fs::create_dir_all(path)?;
|
||||||
// creating a directory is an important change to the file system we
|
// creating a directory is an important change to the file system we
|
||||||
// should always inform the user about
|
// should always inform the user about
|
||||||
info!(accessible, "directory {} created.", EscapedPathDisplay::new(path));
|
log_sender
|
||||||
|
.send(PrintMessage {
|
||||||
|
contents: format!("Directory {} created.", EscapedPathDisplay::new(path)),
|
||||||
|
accessible: true,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
#[derive(Debug)]
|
|
||||||
pub struct PrintMessage {
|
|
||||||
pub contents: String,
|
|
||||||
pub accessible: bool,
|
|
||||||
}
|
|
22
src/utils/message.rs
Normal file
22
src/utils/message.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/// Message object used for sending logs from worker threads to a logging thread via channels.
|
||||||
|
/// See <https://github.com/ouch-org/ouch/issues/632>
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```rs
|
||||||
|
/// // This is already done in the main thread in src/commands/mod.rs
|
||||||
|
/// // Functions that want to log anything just need to have
|
||||||
|
/// // `log_sender: Sender<PrintMessage>` as an argument.
|
||||||
|
/// let (log_sender, log_receiver) = channel::<PrintMessage>();
|
||||||
|
///
|
||||||
|
/// log_sender
|
||||||
|
/// .send(PrintMessage {
|
||||||
|
/// contents: "Hello, world!".to_string(),
|
||||||
|
/// accessible: true,
|
||||||
|
/// }).unwrap();
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PrintMessage {
|
||||||
|
pub contents: String,
|
||||||
|
pub accessible: bool,
|
||||||
|
}
|
@ -7,7 +7,7 @@ pub mod colors;
|
|||||||
mod file_visibility;
|
mod file_visibility;
|
||||||
mod formatting;
|
mod formatting;
|
||||||
mod fs;
|
mod fs;
|
||||||
pub mod io;
|
pub mod message;
|
||||||
mod question;
|
mod question;
|
||||||
|
|
||||||
pub use file_visibility::FileVisibilityPolicy;
|
pub use file_visibility::FileVisibilityPolicy;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user