Proper error handling within walk.rs

This commit is contained in:
sharkdp 2020-04-03 21:18:54 +02:00 committed by David Peter
parent bce95274e3
commit 4590ae8535
5 changed files with 38 additions and 48 deletions

View file

@ -1,10 +1,3 @@
macro_rules! print_error {
($($arg:tt)*) => (eprintln!("[fd error]: {}", format!($($arg)*)))
}
macro_rules! print_error_and_exit {
($($arg:tt)*) => {
print_error!($($arg)*);
::std::process::exit(1);
};
pub fn print_error(msg: impl Into<String>) {
eprintln!("[fd error]: {}", msg.into());
}

View file

@ -3,6 +3,7 @@ use std::io::Write;
use std::process::Command;
use std::sync::Mutex;
use crate::error::print_error;
use crate::exit_codes::ExitCode;
/// Executes a command.
@ -30,11 +31,11 @@ pub fn execute_command(mut cmd: Command, out_perm: &Mutex<()>) -> ExitCode {
}
}
Err(ref why) if why.kind() == io::ErrorKind::NotFound => {
print_error!("Command not found: {:?}", cmd);
print_error(format!("Command not found: {:?}", cmd));
ExitCode::GeneralError
}
Err(why) => {
print_error!("Problem while executing command: {}", why);
print_error(format!("Problem while executing command: {}", why));
ExitCode::GeneralError
}
}

View file

@ -1,10 +1,13 @@
use super::CommandTemplate;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::walk::WorkerResult;
use std::path::PathBuf;
use std::sync::mpsc::Receiver;
use std::sync::{Arc, Mutex};
use crate::error::print_error;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::walk::WorkerResult;
use super::CommandTemplate;
/// An event loop that listens for inputs from the `rx` receiver. Each received input will
/// generate a command with the supplied command template. The generated command will then
/// be executed, and this process will continue until the receiver's sender has closed.
@ -25,7 +28,7 @@ pub fn job(
Ok(WorkerResult::Entry(val)) => val,
Ok(WorkerResult::Error(err)) => {
if show_filesystem_errors {
print_error!("{}", err);
print_error(err.to_string());
}
continue;
}
@ -50,7 +53,7 @@ pub fn batch(
WorkerResult::Entry(val) => Some(val),
WorkerResult::Error(err) => {
if show_filesystem_errors {
print_error!("{}", err);
print_error(err.to_string());
}
None
}

View file

@ -303,9 +303,7 @@ fn run() -> Result<ExitCode> {
)
})?;
let exit_code = walk::scan(&dir_vec, Arc::new(re), Arc::new(config));
Ok(exit_code)
walk::scan(&dir_vec, Arc::new(re), Arc::new(config))
}
fn main() {

View file

@ -1,9 +1,3 @@
use crate::exec;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::filesystem;
use crate::options::Options;
use crate::output;
use std::borrow::Cow;
use std::ffi::OsStr;
use std::fs::{FileType, Metadata};
@ -16,10 +10,18 @@ use std::sync::{Arc, Mutex};
use std::thread;
use std::time;
use anyhow::{anyhow, Result};
use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use regex::bytes::Regex;
use crate::error::print_error;
use crate::exec;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::filesystem;
use crate::options::Options;
use crate::output;
/// The receiver thread can either be buffering results or directly streaming to the console.
enum ReceiverMode {
/// Receiver is still buffering in order to sort the results, if the search finishes fast
@ -44,7 +46,7 @@ pub const MAX_BUFFER_LENGTH: usize = 1000;
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Options>) -> ExitCode {
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Options>) -> Result<ExitCode> {
let mut path_iter = path_vec.iter();
let first_path_buf = path_iter
.next()
@ -54,14 +56,13 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Options>) ->
let mut override_builder = OverrideBuilder::new(first_path_buf.as_path());
for pattern in &config.exclude_patterns {
let res = override_builder.add(pattern);
if res.is_err() {
print_error_and_exit!("Malformed exclude pattern '{}'", pattern);
}
override_builder
.add(pattern)
.map_err(|e| anyhow!("Malformed exclude pattern: {}", e))?;
}
let overrides = override_builder.build().unwrap_or_else(|_| {
print_error_and_exit!("Mismatch in exclude patterns");
});
let overrides = override_builder
.build()
.map_err(|_| anyhow!("Mismatch in exclude patterns"))?;
let mut walker = WalkBuilder::new(first_path_buf.as_path());
walker
@ -86,13 +87,10 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Options>) ->
match result {
Some(ignore::Error::Partial(_)) => (),
Some(err) => {
print_error!(
"{}",
format!(
"Malformed pattern in custom ignore file. {}.",
err.to_string()
)
);
print_error(format!(
"Malformed pattern in custom ignore file. {}.",
err.to_string()
));
}
None => (),
}
@ -131,7 +129,7 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Options>) ->
process::exit(ExitCode::KilledBySigint.into());
}
exit_code
Ok(exit_code)
}
fn spawn_receiver(
@ -231,7 +229,7 @@ fn spawn_receiver(
}
WorkerResult::Error(err) => {
if show_filesystem_errors {
print_error!("{}", err);
print_error(err.to_string());
}
}
}
@ -344,12 +342,9 @@ fn spawn_senders(
let entry_path = entry.path();
let search_str: Cow<OsStr> = if config.search_full_path {
match filesystem::path_absolute_form(entry_path) {
Ok(path_abs_buf) => Cow::Owned(path_abs_buf.as_os_str().to_os_string()),
Err(_) => {
print_error_and_exit!("Unable to retrieve absolute path.");
}
}
let path_abs_buf = filesystem::path_absolute_form(entry_path)
.expect("Retrieving absolute path succeeds");
Cow::Owned(path_abs_buf.as_os_str().to_os_string())
} else {
match entry_path.file_name() {
Some(filename) => Cow::Borrowed(filename),