mirror of https://github.com/sharkdp/fd.git
parent
45f490a407
commit
0aee9b0fd9
|
@ -53,7 +53,7 @@ once_cell = "1.9.0"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "3.1"
|
version = "3.1"
|
||||||
features = ["suggestions", "color", "wrap_help", "cargo"]
|
features = ["suggestions", "color", "wrap_help", "cargo", "unstable-grouped"]
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
users = "0.11.0"
|
users = "0.11.0"
|
||||||
|
|
|
@ -386,6 +386,7 @@ pub fn build_app() -> Command<'static> {
|
||||||
.long("exec")
|
.long("exec")
|
||||||
.short('x')
|
.short('x')
|
||||||
.min_values(1)
|
.min_values(1)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.allow_hyphen_values(true)
|
.allow_hyphen_values(true)
|
||||||
.value_terminator(";")
|
.value_terminator(";")
|
||||||
.value_name("cmd")
|
.value_name("cmd")
|
||||||
|
@ -417,6 +418,7 @@ pub fn build_app() -> Command<'static> {
|
||||||
.long("exec-batch")
|
.long("exec-batch")
|
||||||
.short('X')
|
.short('X')
|
||||||
.min_values(1)
|
.min_values(1)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.allow_hyphen_values(true)
|
.allow_hyphen_values(true)
|
||||||
.value_terminator(";")
|
.value_terminator(";")
|
||||||
.value_name("cmd")
|
.value_name("cmd")
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::{path::PathBuf, sync::Arc, time::Duration};
|
||||||
use lscolors::LsColors;
|
use lscolors::LsColors;
|
||||||
use regex::bytes::RegexSet;
|
use regex::bytes::RegexSet;
|
||||||
|
|
||||||
use crate::exec::CommandTemplate;
|
use crate::exec::CommandSet;
|
||||||
use crate::filetypes::FileTypes;
|
use crate::filetypes::FileTypes;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use crate::filter::OwnerFilter;
|
use crate::filter::OwnerFilter;
|
||||||
|
@ -83,7 +83,7 @@ pub struct Config {
|
||||||
pub extensions: Option<RegexSet>,
|
pub extensions: Option<RegexSet>,
|
||||||
|
|
||||||
/// If a value is supplied, each item found will be used to generate and execute commands.
|
/// If a value is supplied, each item found will be used to generate and execute commands.
|
||||||
pub command: Option<Arc<CommandTemplate>>,
|
pub command: Option<Arc<CommandSet>>,
|
||||||
|
|
||||||
/// Maximum number of search results to pass to each `command`. If zero, the number is
|
/// Maximum number of search results to pass to each `command`. If zero, the number is
|
||||||
/// unlimited.
|
/// unlimited.
|
||||||
|
|
|
@ -6,14 +6,14 @@ use crate::error::print_error;
|
||||||
use crate::exit_codes::{merge_exitcodes, ExitCode};
|
use crate::exit_codes::{merge_exitcodes, ExitCode};
|
||||||
use crate::walk::WorkerResult;
|
use crate::walk::WorkerResult;
|
||||||
|
|
||||||
use super::CommandTemplate;
|
use super::CommandSet;
|
||||||
|
|
||||||
/// An event loop that listens for inputs from the `rx` receiver. Each received input will
|
/// 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
|
/// 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.
|
/// be executed, and this process will continue until the receiver's sender has closed.
|
||||||
pub fn job(
|
pub fn job(
|
||||||
rx: Arc<Mutex<Receiver<WorkerResult>>>,
|
rx: Arc<Mutex<Receiver<WorkerResult>>>,
|
||||||
cmd: Arc<CommandTemplate>,
|
cmd: Arc<CommandSet>,
|
||||||
out_perm: Arc<Mutex<()>>,
|
out_perm: Arc<Mutex<()>>,
|
||||||
show_filesystem_errors: bool,
|
show_filesystem_errors: bool,
|
||||||
buffer_output: bool,
|
buffer_output: bool,
|
||||||
|
@ -39,7 +39,7 @@ pub fn job(
|
||||||
// Drop the lock so that other threads can read from the receiver.
|
// Drop the lock so that other threads can read from the receiver.
|
||||||
drop(lock);
|
drop(lock);
|
||||||
// Generate a command, execute it and store its exit code.
|
// Generate a command, execute it and store its exit code.
|
||||||
results.push(cmd.generate_and_execute(&value, Arc::clone(&out_perm), buffer_output))
|
results.push(cmd.execute(&value, Arc::clone(&out_perm), buffer_output))
|
||||||
}
|
}
|
||||||
// Returns error in case of any error.
|
// Returns error in case of any error.
|
||||||
merge_exitcodes(results)
|
merge_exitcodes(results)
|
||||||
|
@ -47,7 +47,7 @@ pub fn job(
|
||||||
|
|
||||||
pub fn batch(
|
pub fn batch(
|
||||||
rx: Receiver<WorkerResult>,
|
rx: Receiver<WorkerResult>,
|
||||||
cmd: &CommandTemplate,
|
cmd: &CommandSet,
|
||||||
show_filesystem_errors: bool,
|
show_filesystem_errors: bool,
|
||||||
buffer_output: bool,
|
buffer_output: bool,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
|
@ -63,14 +63,14 @@ pub fn batch(
|
||||||
});
|
});
|
||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
// no limit
|
// no limit
|
||||||
return cmd.generate_and_execute_batch(paths, buffer_output);
|
return cmd.execute_batch(paths, buffer_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut exit_codes = Vec::new();
|
let mut exit_codes = Vec::new();
|
||||||
let mut peekable = paths.peekable();
|
let mut peekable = paths.peekable();
|
||||||
while peekable.peek().is_some() {
|
while peekable.peek().is_some() {
|
||||||
let limited = peekable.by_ref().take(limit);
|
let limited = peekable.by_ref().take(limit);
|
||||||
let exit_code = cmd.generate_and_execute_batch(limited, buffer_output);
|
let exit_code = cmd.execute_batch(limited, buffer_output);
|
||||||
exit_codes.push(exit_code);
|
exit_codes.push(exit_code);
|
||||||
}
|
}
|
||||||
merge_exitcodes(exit_codes)
|
merge_exitcodes(exit_codes)
|
||||||
|
|
255
src/exec/mod.rs
255
src/exec/mod.rs
|
@ -29,44 +29,101 @@ pub enum ExecutionMode {
|
||||||
Batch,
|
Batch,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct CommandSet {
|
||||||
|
mode: ExecutionMode,
|
||||||
|
path_separator: Option<String>,
|
||||||
|
commands: Vec<CommandTemplate>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandSet {
|
||||||
|
pub fn new<I, S>(input: I, path_separator: Option<String>) -> CommandSet
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Vec<S>>,
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
CommandSet {
|
||||||
|
mode: ExecutionMode::OneByOne,
|
||||||
|
path_separator,
|
||||||
|
commands: input.into_iter().map(CommandTemplate::new).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_batch<I, S>(input: I, path_separator: Option<String>) -> Result<CommandSet>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = Vec<S>>,
|
||||||
|
S: AsRef<str>,
|
||||||
|
{
|
||||||
|
Ok(CommandSet {
|
||||||
|
mode: ExecutionMode::Batch,
|
||||||
|
path_separator,
|
||||||
|
commands: input
|
||||||
|
.into_iter()
|
||||||
|
.map(|args| {
|
||||||
|
let cmd = CommandTemplate::new(args);
|
||||||
|
if cmd.number_of_tokens() > 1 {
|
||||||
|
return Err(anyhow!("Only one placeholder allowed for batch commands"));
|
||||||
|
}
|
||||||
|
if cmd.args[0].has_tokens() {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"First argument of exec-batch is expected to be a fixed executable"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(cmd)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>>>()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn in_batch_mode(&self) -> bool {
|
||||||
|
self.mode == ExecutionMode::Batch
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(
|
||||||
|
&self,
|
||||||
|
input: &Path,
|
||||||
|
mut out_perm: Arc<Mutex<()>>,
|
||||||
|
buffer_output: bool,
|
||||||
|
) -> ExitCode {
|
||||||
|
let path_separator = self.path_separator.as_deref();
|
||||||
|
for cmd in &self.commands {
|
||||||
|
let exit =
|
||||||
|
cmd.generate_and_execute(input, path_separator, &mut out_perm, buffer_output);
|
||||||
|
if exit != ExitCode::Success {
|
||||||
|
return exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExitCode::Success
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_batch<I>(&self, paths: I, buffer_output: bool) -> ExitCode
|
||||||
|
where
|
||||||
|
I: Iterator<Item = PathBuf>,
|
||||||
|
{
|
||||||
|
let path_separator = self.path_separator.as_deref();
|
||||||
|
let mut paths = paths.collect::<Vec<_>>();
|
||||||
|
paths.sort();
|
||||||
|
for cmd in &self.commands {
|
||||||
|
let exit = cmd.generate_and_execute_batch(&paths, path_separator, buffer_output);
|
||||||
|
if exit != ExitCode::Success {
|
||||||
|
return exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExitCode::Success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a template that is utilized to generate command strings.
|
/// Represents a template that is utilized to generate command strings.
|
||||||
///
|
///
|
||||||
/// The template is meant to be coupled with an input in order to generate a command. The
|
/// The template is meant to be coupled with an input in order to generate a command. The
|
||||||
/// `generate_and_execute()` method will be used to generate a command and execute it.
|
/// `generate_and_execute()` method will be used to generate a command and execute it.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct CommandTemplate {
|
struct CommandTemplate {
|
||||||
args: Vec<ArgumentTemplate>,
|
args: Vec<ArgumentTemplate>,
|
||||||
mode: ExecutionMode,
|
|
||||||
path_separator: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandTemplate {
|
impl CommandTemplate {
|
||||||
pub fn new<I, S>(input: I, path_separator: Option<String>) -> CommandTemplate
|
fn new<I, S>(input: I) -> CommandTemplate
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<str>,
|
|
||||||
{
|
|
||||||
Self::build(input, ExecutionMode::OneByOne, path_separator)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_batch<I, S>(input: I, path_separator: Option<String>) -> Result<CommandTemplate>
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = S>,
|
|
||||||
S: AsRef<str>,
|
|
||||||
{
|
|
||||||
let cmd = Self::build(input, ExecutionMode::Batch, path_separator);
|
|
||||||
if cmd.number_of_tokens() > 1 {
|
|
||||||
return Err(anyhow!("Only one placeholder allowed for batch commands"));
|
|
||||||
}
|
|
||||||
if cmd.args[0].has_tokens() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"First argument of exec-batch is expected to be a fixed executable"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build<I, S>(input: I, mode: ExecutionMode, path_separator: Option<String>) -> CommandTemplate
|
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = S>,
|
I: IntoIterator<Item = S>,
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
|
@ -122,11 +179,7 @@ impl CommandTemplate {
|
||||||
args.push(ArgumentTemplate::Tokens(vec![Token::Placeholder]));
|
args.push(ArgumentTemplate::Tokens(vec![Token::Placeholder]));
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandTemplate {
|
CommandTemplate { args }
|
||||||
args,
|
|
||||||
mode,
|
|
||||||
path_separator,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number_of_tokens(&self) -> usize {
|
fn number_of_tokens(&self) -> usize {
|
||||||
|
@ -137,44 +190,38 @@ impl CommandTemplate {
|
||||||
///
|
///
|
||||||
/// Using the internal `args` field, and a supplied `input` variable, a `Command` will be
|
/// Using the internal `args` field, and a supplied `input` variable, a `Command` will be
|
||||||
/// build. Once all arguments have been processed, the command is executed.
|
/// build. Once all arguments have been processed, the command is executed.
|
||||||
pub fn generate_and_execute(
|
fn generate_and_execute(
|
||||||
&self,
|
&self,
|
||||||
input: &Path,
|
input: &Path,
|
||||||
out_perm: Arc<Mutex<()>>,
|
path_separator: Option<&str>,
|
||||||
|
out_perm: &mut Arc<Mutex<()>>,
|
||||||
buffer_output: bool,
|
buffer_output: bool,
|
||||||
) -> ExitCode {
|
) -> ExitCode {
|
||||||
let mut cmd = Command::new(self.args[0].generate(&input, self.path_separator.as_deref()));
|
let mut cmd = Command::new(self.args[0].generate(&input, path_separator));
|
||||||
for arg in &self.args[1..] {
|
for arg in &self.args[1..] {
|
||||||
cmd.arg(arg.generate(&input, self.path_separator.as_deref()));
|
cmd.arg(arg.generate(&input, path_separator));
|
||||||
}
|
}
|
||||||
|
|
||||||
execute_command(cmd, &out_perm, buffer_output)
|
execute_command(cmd, &out_perm, buffer_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_batch_mode(&self) -> bool {
|
fn generate_and_execute_batch(
|
||||||
self.mode == ExecutionMode::Batch
|
&self,
|
||||||
}
|
paths: &Vec<PathBuf>,
|
||||||
|
path_separator: Option<&str>,
|
||||||
pub fn generate_and_execute_batch<I>(&self, paths: I, buffer_output: bool) -> ExitCode
|
buffer_output: bool,
|
||||||
where
|
) -> ExitCode {
|
||||||
I: Iterator<Item = PathBuf>,
|
|
||||||
{
|
|
||||||
let mut cmd = Command::new(self.args[0].generate("", None));
|
let mut cmd = Command::new(self.args[0].generate("", None));
|
||||||
cmd.stdin(Stdio::inherit());
|
cmd.stdin(Stdio::inherit());
|
||||||
cmd.stdout(Stdio::inherit());
|
cmd.stdout(Stdio::inherit());
|
||||||
cmd.stderr(Stdio::inherit());
|
cmd.stderr(Stdio::inherit());
|
||||||
|
|
||||||
let mut paths: Vec<_> = paths.collect();
|
|
||||||
let mut has_path = false;
|
let mut has_path = false;
|
||||||
|
|
||||||
for arg in &self.args[1..] {
|
for arg in &self.args[1..] {
|
||||||
if arg.has_tokens() {
|
if arg.has_tokens() {
|
||||||
paths.sort();
|
for path in paths {
|
||||||
|
cmd.arg(arg.generate(path, path_separator));
|
||||||
// A single `Tokens` is expected
|
|
||||||
// So we can directly consume the iterator once and for all
|
|
||||||
for path in &mut paths {
|
|
||||||
cmd.arg(arg.generate(path, self.path_separator.as_deref()));
|
|
||||||
has_path = true;
|
has_path = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -302,13 +349,15 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_with_placeholder() {
|
fn tokens_with_placeholder() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CommandTemplate::new(&[&"echo", &"${SHELL}:"], None),
|
CommandSet::new(vec![vec![&"echo", &"${SHELL}:"]], None),
|
||||||
CommandTemplate {
|
CommandSet {
|
||||||
args: vec![
|
commands: vec![CommandTemplate {
|
||||||
ArgumentTemplate::Text("echo".into()),
|
args: vec![
|
||||||
ArgumentTemplate::Text("${SHELL}:".into()),
|
ArgumentTemplate::Text("echo".into()),
|
||||||
ArgumentTemplate::Tokens(vec![Token::Placeholder]),
|
ArgumentTemplate::Text("${SHELL}:".into()),
|
||||||
],
|
ArgumentTemplate::Tokens(vec![Token::Placeholder]),
|
||||||
|
]
|
||||||
|
}],
|
||||||
mode: ExecutionMode::OneByOne,
|
mode: ExecutionMode::OneByOne,
|
||||||
path_separator: None,
|
path_separator: None,
|
||||||
}
|
}
|
||||||
|
@ -318,12 +367,14 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_with_no_extension() {
|
fn tokens_with_no_extension() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CommandTemplate::new(&["echo", "{.}"], None),
|
CommandSet::new(vec![vec!["echo", "{.}"]], None),
|
||||||
CommandTemplate {
|
CommandSet {
|
||||||
args: vec![
|
commands: vec![CommandTemplate {
|
||||||
ArgumentTemplate::Text("echo".into()),
|
args: vec![
|
||||||
ArgumentTemplate::Tokens(vec![Token::NoExt]),
|
ArgumentTemplate::Text("echo".into()),
|
||||||
],
|
ArgumentTemplate::Tokens(vec![Token::NoExt]),
|
||||||
|
],
|
||||||
|
}],
|
||||||
mode: ExecutionMode::OneByOne,
|
mode: ExecutionMode::OneByOne,
|
||||||
path_separator: None,
|
path_separator: None,
|
||||||
}
|
}
|
||||||
|
@ -333,12 +384,14 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_with_basename() {
|
fn tokens_with_basename() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CommandTemplate::new(&["echo", "{/}"], None),
|
CommandSet::new(vec![vec!["echo", "{/}"]], None),
|
||||||
CommandTemplate {
|
CommandSet {
|
||||||
args: vec![
|
commands: vec![CommandTemplate {
|
||||||
ArgumentTemplate::Text("echo".into()),
|
args: vec![
|
||||||
ArgumentTemplate::Tokens(vec![Token::Basename]),
|
ArgumentTemplate::Text("echo".into()),
|
||||||
],
|
ArgumentTemplate::Tokens(vec![Token::Basename]),
|
||||||
|
],
|
||||||
|
}],
|
||||||
mode: ExecutionMode::OneByOne,
|
mode: ExecutionMode::OneByOne,
|
||||||
path_separator: None,
|
path_separator: None,
|
||||||
}
|
}
|
||||||
|
@ -348,12 +401,14 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_with_parent() {
|
fn tokens_with_parent() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CommandTemplate::new(&["echo", "{//}"], None),
|
CommandSet::new(vec![vec!["echo", "{//}"]], None),
|
||||||
CommandTemplate {
|
CommandSet {
|
||||||
args: vec![
|
commands: vec![CommandTemplate {
|
||||||
ArgumentTemplate::Text("echo".into()),
|
args: vec![
|
||||||
ArgumentTemplate::Tokens(vec![Token::Parent]),
|
ArgumentTemplate::Text("echo".into()),
|
||||||
],
|
ArgumentTemplate::Tokens(vec![Token::Parent]),
|
||||||
|
],
|
||||||
|
}],
|
||||||
mode: ExecutionMode::OneByOne,
|
mode: ExecutionMode::OneByOne,
|
||||||
path_separator: None,
|
path_separator: None,
|
||||||
}
|
}
|
||||||
|
@ -363,12 +418,14 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_with_basename_no_extension() {
|
fn tokens_with_basename_no_extension() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CommandTemplate::new(&["echo", "{/.}"], None),
|
CommandSet::new(vec![vec!["echo", "{/.}"]], None),
|
||||||
CommandTemplate {
|
CommandSet {
|
||||||
args: vec![
|
commands: vec![CommandTemplate {
|
||||||
ArgumentTemplate::Text("echo".into()),
|
args: vec![
|
||||||
ArgumentTemplate::Tokens(vec![Token::BasenameNoExt]),
|
ArgumentTemplate::Text("echo".into()),
|
||||||
],
|
ArgumentTemplate::Tokens(vec![Token::BasenameNoExt]),
|
||||||
|
],
|
||||||
|
}],
|
||||||
mode: ExecutionMode::OneByOne,
|
mode: ExecutionMode::OneByOne,
|
||||||
path_separator: None,
|
path_separator: None,
|
||||||
}
|
}
|
||||||
|
@ -378,16 +435,18 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_multiple() {
|
fn tokens_multiple() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CommandTemplate::new(&["cp", "{}", "{/.}.ext"], None),
|
CommandSet::new(vec![vec!["cp", "{}", "{/.}.ext"]], None),
|
||||||
CommandTemplate {
|
CommandSet {
|
||||||
args: vec![
|
commands: vec![CommandTemplate {
|
||||||
ArgumentTemplate::Text("cp".into()),
|
args: vec![
|
||||||
ArgumentTemplate::Tokens(vec![Token::Placeholder]),
|
ArgumentTemplate::Text("cp".into()),
|
||||||
ArgumentTemplate::Tokens(vec![
|
ArgumentTemplate::Tokens(vec![Token::Placeholder]),
|
||||||
Token::BasenameNoExt,
|
ArgumentTemplate::Tokens(vec![
|
||||||
Token::Text(".ext".into())
|
Token::BasenameNoExt,
|
||||||
]),
|
Token::Text(".ext".into())
|
||||||
],
|
]),
|
||||||
|
],
|
||||||
|
}],
|
||||||
mode: ExecutionMode::OneByOne,
|
mode: ExecutionMode::OneByOne,
|
||||||
path_separator: None,
|
path_separator: None,
|
||||||
}
|
}
|
||||||
|
@ -397,12 +456,14 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_single_batch() {
|
fn tokens_single_batch() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CommandTemplate::new_batch(&["echo", "{.}"], None).unwrap(),
|
CommandSet::new_batch(vec![vec!["echo", "{.}"]], None).unwrap(),
|
||||||
CommandTemplate {
|
CommandSet {
|
||||||
|
commands: vec![CommandTemplate {
|
||||||
args: vec![
|
args: vec![
|
||||||
ArgumentTemplate::Text("echo".into()),
|
ArgumentTemplate::Text("echo".into()),
|
||||||
ArgumentTemplate::Tokens(vec![Token::NoExt]),
|
ArgumentTemplate::Tokens(vec![Token::NoExt]),
|
||||||
],
|
],
|
||||||
|
}],
|
||||||
mode: ExecutionMode::Batch,
|
mode: ExecutionMode::Batch,
|
||||||
path_separator: None,
|
path_separator: None,
|
||||||
}
|
}
|
||||||
|
@ -411,7 +472,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tokens_multiple_batch() {
|
fn tokens_multiple_batch() {
|
||||||
assert!(CommandTemplate::new_batch(&["echo", "{.}", "{}"], None).is_err());
|
assert!(CommandSet::new_batch(vec![vec!["echo", "{.}", "{}"]], None).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -24,7 +24,7 @@ use regex::bytes::{RegexBuilder, RegexSetBuilder};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::error::print_error;
|
use crate::error::print_error;
|
||||||
use crate::exec::CommandTemplate;
|
use crate::exec::CommandSet;
|
||||||
use crate::exit_codes::ExitCode;
|
use crate::exit_codes::ExitCode;
|
||||||
use crate::filetypes::FileTypes;
|
use crate::filetypes::FileTypes;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -390,19 +390,16 @@ fn extract_command(
|
||||||
matches: &clap::ArgMatches,
|
matches: &clap::ArgMatches,
|
||||||
path_separator: Option<&str>,
|
path_separator: Option<&str>,
|
||||||
colored_output: bool,
|
colored_output: bool,
|
||||||
) -> Result<Option<CommandTemplate>> {
|
) -> Result<Option<CommandSet>> {
|
||||||
None.or_else(|| {
|
None.or_else(|| {
|
||||||
matches.values_of("exec").map(|args| {
|
matches
|
||||||
Ok(CommandTemplate::new(
|
.grouped_values_of("exec")
|
||||||
args,
|
.map(|args| Ok(CommandSet::new(args, path_separator.map(str::to_string))))
|
||||||
path_separator.map(str::to_string),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
matches
|
matches
|
||||||
.values_of("exec-batch")
|
.grouped_values_of("exec-batch")
|
||||||
.map(|args| CommandTemplate::new_batch(args, path_separator.map(str::to_string)))
|
.map(|args| CommandSet::new_batch(args, path_separator.map(str::to_string)))
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if !matches.is_present("list-details") {
|
if !matches.is_present("list-details") {
|
||||||
|
@ -412,9 +409,8 @@ fn extract_command(
|
||||||
let color = matches.value_of("color").unwrap_or("auto");
|
let color = matches.value_of("color").unwrap_or("auto");
|
||||||
let color_arg = format!("--color={}", color);
|
let color_arg = format!("--color={}", color);
|
||||||
|
|
||||||
let res = determine_ls_command(&color_arg, colored_output).map(|cmd| {
|
let res = determine_ls_command(&color_arg, colored_output)
|
||||||
CommandTemplate::new_batch(cmd, path_separator.map(str::to_string)).unwrap()
|
.map(|cmd| CommandSet::new_batch([cmd], path_separator.map(str::to_string)).unwrap());
|
||||||
});
|
|
||||||
|
|
||||||
Some(res)
|
Some(res)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue