From 1bc58b2fbb3d1a6b8219db980f7c37ed5cd48be4 Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Sat, 14 Oct 2017 17:59:36 -0400 Subject: [PATCH] Group outputs from exec --- src/exec/job.rs | 4 +++- src/exec/mod.rs | 10 ++++++++-- src/exec/ticket.rs | 25 +++++++++++++++++++------ src/walk.rs | 6 +++++- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/exec/job.rs b/src/exec/job.rs index 65dc2c1..bd87230 100644 --- a/src/exec/job.rs +++ b/src/exec/job.rs @@ -11,6 +11,7 @@ pub fn job( rx: Arc>>, base: Arc>, cmd: Arc, + out_perm: Arc>, ) { // A string buffer that will be re-used in each iteration. let buffer = &mut String::with_capacity(256); @@ -35,6 +36,7 @@ pub fn job( drop(lock); // Generate a command to store within the buffer, and execute the command. // Note that the `then_execute()` method will clear the buffer for us. - cmd.generate(buffer, &value).then_execute(); + cmd.generate(buffer, &value, out_perm.clone()) + .then_execute(); } } diff --git a/src/exec/mod.rs b/src/exec/mod.rs index e061256..bec9712 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -5,6 +5,7 @@ mod job; mod paths; use std::path::Path; +use std::sync::{Arc, Mutex}; use self::paths::{basename, dirname, remove_extension}; use self::ticket::CommandTicket; @@ -102,7 +103,12 @@ impl TokenizedCommand { /// written into the `command` buffer. Once all tokens have been processed, the mutable /// reference of the `command` will be wrapped within a `CommandTicket`, which will be /// responsible for executing the command and clearing the buffer. - pub fn generate<'a>(&self, command: &'a mut String, input: &Path) -> CommandTicket<'a> { + pub fn generate<'a>( + &self, + command: &'a mut String, + input: &Path, + out_perm: Arc>, + ) -> CommandTicket<'a> { for token in &self.tokens { match *token { Token::Basename => *command += basename(&input.to_string_lossy()), @@ -116,7 +122,7 @@ impl TokenizedCommand { } } - CommandTicket::new(command) + CommandTicket::new(command, out_perm) } } diff --git a/src/exec/ticket.rs b/src/exec/ticket.rs index 9493e3f..5a2ca9e 100644 --- a/src/exec/ticket.rs +++ b/src/exec/ticket.rs @@ -1,5 +1,7 @@ use std::env; -use std::process::Command; +use std::process::{Command, Stdio}; +use std::sync::{Arc, Mutex}; +use std::io::{self, Write}; lazy_static! { /// On non-Windows systems, the `SHELL` environment variable will be used to determine the @@ -18,11 +20,12 @@ lazy_static! { /// cleared so that a new command can be written to the string in the future. pub struct CommandTicket<'a> { command: &'a mut String, + out_perm: Arc>, } impl<'a> CommandTicket<'a> { - pub fn new(command: &'a mut String) -> CommandTicket<'a> { - CommandTicket { command } + pub fn new(command: &'a mut String, out_perm: Arc>) -> CommandTicket<'a> { + CommandTicket { command, out_perm } } /// Executes the command stored within the ticket, and @@ -32,12 +35,22 @@ impl<'a> CommandTicket<'a> { let cmd = Command::new(COMMAND.0.as_str()) .arg(COMMAND.1) .arg(&self.command) - .spawn(); + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .output(); // Then wait for the command to exit, if it was spawned. match cmd { - Ok(mut child) => { - let _ = child.wait(); + Ok(output) => { + // While this lock is active, this thread will be the only thread allowed + // to write it's outputs. + let _lock = self.out_perm.lock().unwrap(); + + let stdout = io::stdout(); + let stderr = io::stderr(); + + let _ = stdout.lock().write_all(&output.stdout); + let _ = stderr.lock().write_all(&output.stderr); } Err(why) => eprintln!("fd: exec error: {}", why), } diff --git a/src/walk.rs b/src/walk.rs index e6ce571..b260625 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -60,6 +60,9 @@ pub fn scan(root: &Path, pattern: Arc, base: &Path, config: Arc, base: &Path, config: Arc