mirror of
https://github.com/sharkdp/fd.git
synced 2024-11-19 02:10:34 +01:00
Group outputs from exec
This commit is contained in:
parent
718f723d31
commit
1bc58b2fbb
4 changed files with 35 additions and 10 deletions
|
@ -11,6 +11,7 @@ pub fn job(
|
||||||
rx: Arc<Mutex<Receiver<PathBuf>>>,
|
rx: Arc<Mutex<Receiver<PathBuf>>>,
|
||||||
base: Arc<Option<PathBuf>>,
|
base: Arc<Option<PathBuf>>,
|
||||||
cmd: Arc<TokenizedCommand>,
|
cmd: Arc<TokenizedCommand>,
|
||||||
|
out_perm: Arc<Mutex<()>>,
|
||||||
) {
|
) {
|
||||||
// A string buffer that will be re-used in each iteration.
|
// A string buffer that will be re-used in each iteration.
|
||||||
let buffer = &mut String::with_capacity(256);
|
let buffer = &mut String::with_capacity(256);
|
||||||
|
@ -35,6 +36,7 @@ pub fn job(
|
||||||
drop(lock);
|
drop(lock);
|
||||||
// Generate a command to store within the buffer, and execute the command.
|
// Generate a command to store within the buffer, and execute the command.
|
||||||
// Note that the `then_execute()` method will clear the buffer for us.
|
// 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ mod job;
|
||||||
mod paths;
|
mod paths;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use self::paths::{basename, dirname, remove_extension};
|
use self::paths::{basename, dirname, remove_extension};
|
||||||
use self::ticket::CommandTicket;
|
use self::ticket::CommandTicket;
|
||||||
|
@ -102,7 +103,12 @@ impl TokenizedCommand {
|
||||||
/// written into the `command` buffer. Once all tokens have been processed, the mutable
|
/// 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
|
/// reference of the `command` will be wrapped within a `CommandTicket`, which will be
|
||||||
/// responsible for executing the command and clearing the buffer.
|
/// 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<Mutex<()>>,
|
||||||
|
) -> CommandTicket<'a> {
|
||||||
for token in &self.tokens {
|
for token in &self.tokens {
|
||||||
match *token {
|
match *token {
|
||||||
Token::Basename => *command += basename(&input.to_string_lossy()),
|
Token::Basename => *command += basename(&input.to_string_lossy()),
|
||||||
|
@ -116,7 +122,7 @@ impl TokenizedCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandTicket::new(command)
|
CommandTicket::new(command, out_perm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::Command;
|
use std::process::{Command, Stdio};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// On non-Windows systems, the `SHELL` environment variable will be used to determine the
|
/// 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.
|
/// cleared so that a new command can be written to the string in the future.
|
||||||
pub struct CommandTicket<'a> {
|
pub struct CommandTicket<'a> {
|
||||||
command: &'a mut String,
|
command: &'a mut String,
|
||||||
|
out_perm: Arc<Mutex<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CommandTicket<'a> {
|
impl<'a> CommandTicket<'a> {
|
||||||
pub fn new(command: &'a mut String) -> CommandTicket<'a> {
|
pub fn new(command: &'a mut String, out_perm: Arc<Mutex<()>>) -> CommandTicket<'a> {
|
||||||
CommandTicket { command }
|
CommandTicket { command, out_perm }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the command stored within the ticket, and
|
/// Executes the command stored within the ticket, and
|
||||||
|
@ -32,12 +35,22 @@ impl<'a> CommandTicket<'a> {
|
||||||
let cmd = Command::new(COMMAND.0.as_str())
|
let cmd = Command::new(COMMAND.0.as_str())
|
||||||
.arg(COMMAND.1)
|
.arg(COMMAND.1)
|
||||||
.arg(&self.command)
|
.arg(&self.command)
|
||||||
.spawn();
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.output();
|
||||||
|
|
||||||
// Then wait for the command to exit, if it was spawned.
|
// Then wait for the command to exit, if it was spawned.
|
||||||
match cmd {
|
match cmd {
|
||||||
Ok(mut child) => {
|
Ok(output) => {
|
||||||
let _ = child.wait();
|
// 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),
|
Err(why) => eprintln!("fd: exec error: {}", why),
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,9 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
||||||
// This will be set to `Some` if the `--exec` argument was supplied.
|
// This will be set to `Some` if the `--exec` argument was supplied.
|
||||||
if let Some(ref cmd) = rx_config.command {
|
if let Some(ref cmd) = rx_config.command {
|
||||||
let shared_rx = Arc::new(Mutex::new(rx));
|
let shared_rx = Arc::new(Mutex::new(rx));
|
||||||
|
|
||||||
|
let out_perm = Arc::new(Mutex::new(()));
|
||||||
|
|
||||||
let base = Arc::new(if is_absolute { Some(rx_base) } else { None });
|
let base = Arc::new(if is_absolute { Some(rx_base) } else { None });
|
||||||
|
|
||||||
// This is safe because `cmd` will exist beyond the end of this scope.
|
// This is safe because `cmd` will exist beyond the end of this scope.
|
||||||
|
@ -72,9 +75,10 @@ pub fn scan(root: &Path, pattern: Arc<Regex>, base: &Path, config: Arc<FdOptions
|
||||||
let rx = shared_rx.clone();
|
let rx = shared_rx.clone();
|
||||||
let cmd = cmd.clone();
|
let cmd = cmd.clone();
|
||||||
let base = base.clone();
|
let base = base.clone();
|
||||||
|
let out_perm = out_perm.clone();
|
||||||
|
|
||||||
// Spawn a job thread that will listen for and execute inputs.
|
// Spawn a job thread that will listen for and execute inputs.
|
||||||
let handle = thread::spawn(move || exec::job(rx, base, cmd));
|
let handle = thread::spawn(move || exec::job(rx, base, cmd, out_perm));
|
||||||
|
|
||||||
// Push the handle of the spawned thread into the vector for later joining.
|
// Push the handle of the spawned thread into the vector for later joining.
|
||||||
handles.push(handle);
|
handles.push(handle);
|
||||||
|
|
Loading…
Reference in a new issue