Expose exit status from `--exec-batch <cmd>`

closes #333
This commit is contained in:
sharkdp 2019-09-13 22:26:27 +02:00 committed by David Peter
parent 630749f706
commit a0505bd4df
7 changed files with 44 additions and 11 deletions

2
Cargo.lock generated
View File

@ -1,3 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.6.9"

View File

@ -11,8 +11,10 @@ use std::io::Write;
use std::process::Command;
use std::sync::Mutex;
use crate::exit_codes::ExitCode;
/// Executes a command.
pub fn execute_command(mut cmd: Command, out_perm: &Mutex<()>) {
pub fn execute_command(mut cmd: Command, out_perm: &Mutex<()>) -> ExitCode {
// Spawn the supplied command.
let output = cmd.output();
@ -28,12 +30,20 @@ pub fn execute_command(mut cmd: Command, out_perm: &Mutex<()>) {
let _ = stdout.lock().write_all(&output.stdout);
let _ = stderr.lock().write_all(&output.stderr);
if output.status.code() == Some(0) {
ExitCode::Success
} else {
ExitCode::GeneralError
}
}
Err(ref why) if why.kind() == io::ErrorKind::NotFound => {
print_error!("Command not found: {:?}", cmd);
ExitCode::GeneralError
}
Err(why) => {
print_error!("Problem while executing command: {}", why);
ExitCode::GeneralError
}
}
}

View File

@ -7,6 +7,7 @@
// according to those terms.
use super::CommandTemplate;
use crate::exit_codes::ExitCode;
use crate::walk::WorkerResult;
use std::path::PathBuf;
use std::sync::mpsc::Receiver;
@ -45,7 +46,11 @@ pub fn job(
}
}
pub fn batch(rx: Receiver<WorkerResult>, cmd: &CommandTemplate, show_filesystem_errors: bool) {
pub fn batch(
rx: Receiver<WorkerResult>,
cmd: &CommandTemplate,
show_filesystem_errors: bool,
) -> ExitCode {
let paths = rx.iter().filter_map(|value| match value {
WorkerResult::Entry(val) => Some(val),
WorkerResult::Error(err) => {
@ -55,5 +60,5 @@ pub fn batch(rx: Receiver<WorkerResult>, cmd: &CommandTemplate, show_filesystem_
None
}
});
cmd.generate_and_execute_batch(paths);
cmd.generate_and_execute_batch(paths)
}

View File

@ -20,6 +20,8 @@ use std::sync::{Arc, Mutex};
use lazy_static::lazy_static;
use regex::Regex;
use crate::exit_codes::ExitCode;
use self::command::execute_command;
use self::input::{basename, dirname, remove_extension};
pub use self::job::{batch, job};
@ -152,14 +154,14 @@ impl CommandTemplate {
cmd.arg(arg.generate(&input).as_ref());
}
execute_command(cmd, &out_perm)
execute_command(cmd, &out_perm);
}
pub fn in_batch_mode(&self) -> bool {
self.mode == ExecutionMode::Batch
}
pub fn generate_and_execute_batch<I>(&self, paths: I)
pub fn generate_and_execute_batch<I>(&self, paths: I) -> ExitCode
where
I: Iterator<Item = PathBuf>,
{
@ -185,7 +187,9 @@ impl CommandTemplate {
}
if has_path {
execute_command(cmd, &Mutex::new(()));
execute_command(cmd, &Mutex::new(()))
} else {
ExitCode::Success
}
}
}

View File

@ -1,4 +1,5 @@
pub enum ExitCode {
Success,
GeneralError,
KilledBySigint,
}
@ -6,6 +7,7 @@ pub enum ExitCode {
impl Into<i32> for ExitCode {
fn into(self) -> i32 {
match self {
ExitCode::Success => 0,
ExitCode::GeneralError => 1,
ExitCode::KilledBySigint => 130,
}

View File

@ -19,6 +19,7 @@ mod walk;
use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;
use std::time;
@ -250,7 +251,10 @@ fn main() {
.dot_matches_new_line(true)
.build()
{
Ok(re) => walk::scan(&dir_vec, Arc::new(re), Arc::new(config)),
Ok(re) => {
let exit_code = walk::scan(&dir_vec, Arc::new(re), Arc::new(config));
process::exit(exit_code.into());
}
Err(err) => {
print_error_and_exit!(
"{}\nHint: You can use the '--fixed-strings' option to search for a \

View File

@ -47,7 +47,7 @@ pub enum WorkerResult {
/// 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<FdOptions>) {
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) -> ExitCode {
let mut path_iter = path_vec.iter();
let first_path_buf = path_iter
.next()
@ -122,18 +122,20 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) {
spawn_senders(&config, &wants_to_quit, pattern, parallel_walker, tx);
// Wait for the receiver thread to print out all results.
receiver_thread.join().unwrap();
let exit_code = receiver_thread.join().unwrap();
if wants_to_quit.load(Ordering::Relaxed) {
process::exit(ExitCode::KilledBySigint.into());
}
exit_code
}
fn spawn_receiver(
config: &Arc<FdOptions>,
wants_to_quit: &Arc<AtomicBool>,
rx: Receiver<WorkerResult>,
) -> thread::JoinHandle<()> {
) -> thread::JoinHandle<ExitCode> {
let config = Arc::clone(config);
let wants_to_quit = Arc::clone(wants_to_quit);
@ -144,7 +146,7 @@ fn spawn_receiver(
// This will be set to `Some` if the `--exec` argument was supplied.
if let Some(ref cmd) = config.command {
if cmd.in_batch_mode() {
exec::batch(rx, cmd, show_filesystem_errors);
exec::batch(rx, cmd, show_filesystem_errors)
} else {
let shared_rx = Arc::new(Mutex::new(rx));
@ -169,6 +171,8 @@ fn spawn_receiver(
for h in handles {
h.join().unwrap();
}
ExitCode::Success
}
} else {
let start = time::Instant::now();
@ -233,6 +237,8 @@ fn spawn_receiver(
output::print_entry(&mut stdout, &value, &config, &wants_to_quit);
}
}
ExitCode::Success
}
})
}