mirror of
https://github.com/sharkdp/hyperfine.git
synced 2024-09-11 22:17:46 +03:00
Parse --shell option value as shell command
This commit is contained in:
parent
5c6879e4c1
commit
e2fdaceb9f
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -243,6 +243,7 @@ dependencies = [
|
||||
"rust_decimal",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shell-words",
|
||||
"statistical",
|
||||
"tempfile",
|
||||
"winapi",
|
||||
@ -680,6 +681,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
|
||||
|
||||
[[package]]
|
||||
name = "statistical"
|
||||
version = "1.0.0"
|
||||
|
@ -21,6 +21,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
rust_decimal = "1.16"
|
||||
rand = "0.8"
|
||||
shell-words = "1.0"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
libc = "0.2"
|
||||
|
@ -9,7 +9,7 @@ use crate::benchmark_result::BenchmarkResult;
|
||||
use crate::command::Command;
|
||||
use crate::format::{format_duration, format_duration_unit};
|
||||
use crate::min_max::{max, min};
|
||||
use crate::options::{CmdFailureAction, HyperfineOptions, OutputStyleOption};
|
||||
use crate::options::{CmdFailureAction, HyperfineOptions, OutputStyleOption, Shell};
|
||||
use crate::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
||||
use crate::progress_bar::get_progress_bar;
|
||||
use crate::shell::execute_and_time;
|
||||
@ -45,7 +45,7 @@ fn subtract_shell_spawning_time(time: Second, shell_spawning_time: Second) -> Se
|
||||
|
||||
/// Run the given shell command and measure the execution time
|
||||
pub fn time_shell_command(
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
command: &Command<'_>,
|
||||
show_output: bool,
|
||||
failure_action: CmdFailureAction,
|
||||
@ -98,7 +98,7 @@ pub fn time_shell_command(
|
||||
|
||||
/// Measure the average shell spawning time
|
||||
pub fn mean_shell_spawning_time(
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
style: OutputStyleOption,
|
||||
show_output: bool,
|
||||
) -> io::Result<TimingResult> {
|
||||
@ -168,7 +168,7 @@ pub fn mean_shell_spawning_time(
|
||||
}
|
||||
|
||||
fn run_intermediate_command(
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
command: &Option<Command<'_>>,
|
||||
show_output: bool,
|
||||
error_output: &'static str,
|
||||
@ -187,7 +187,7 @@ fn run_intermediate_command(
|
||||
|
||||
/// Run the command specified by `--prepare`.
|
||||
fn run_preparation_command(
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
command: &Option<Command<'_>>,
|
||||
show_output: bool,
|
||||
) -> io::Result<TimingResult> {
|
||||
@ -199,7 +199,7 @@ fn run_preparation_command(
|
||||
|
||||
/// Run the command specified by `--cleanup`.
|
||||
fn run_cleanup_command(
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
command: &Option<Command<'_>>,
|
||||
show_output: bool,
|
||||
) -> io::Result<TimingResult> {
|
||||
|
@ -62,6 +62,8 @@ pub enum OptionsError<'a> {
|
||||
TooManyCommandNames(usize),
|
||||
UnexpectedCommandNameCount(usize, usize),
|
||||
NumericParsingError(&'a str, ParseIntError),
|
||||
EmptyShell,
|
||||
ShellParseError(shell_words::ParseError),
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for OptionsError<'a> {
|
||||
@ -85,6 +87,10 @@ impl<'a> fmt::Display for OptionsError<'a> {
|
||||
cmd = cmd,
|
||||
err = err
|
||||
),
|
||||
OptionsError::EmptyShell => write!(f, "Empty command at --shell option"),
|
||||
OptionsError::ShellParseError(ref err) => {
|
||||
write!(f, "Could not parse --shell value as command line: {}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ use benchmark_result::BenchmarkResult;
|
||||
use command::Command;
|
||||
use error::OptionsError;
|
||||
use export::{ExportManager, ExportType};
|
||||
use options::{CmdFailureAction, HyperfineOptions, OutputStyleOption};
|
||||
use options::{CmdFailureAction, HyperfineOptions, OutputStyleOption, Shell};
|
||||
use parameter_range::get_parameterized_commands;
|
||||
use tokenize::tokenize;
|
||||
use types::ParameterValue;
|
||||
@ -229,10 +229,9 @@ fn build_hyperfine_options<'a>(
|
||||
OutputStyleOption::Disabled => {}
|
||||
};
|
||||
|
||||
options.shell = matches
|
||||
.value_of("shell")
|
||||
.unwrap_or(&options.shell)
|
||||
.to_string();
|
||||
if let Some(shell) = matches.value_of("shell") {
|
||||
options.shell = Shell::parse(shell)?;
|
||||
}
|
||||
|
||||
if matches.is_present("ignore-failure") {
|
||||
options.failure_action = CmdFailureAction::Ignore;
|
||||
|
@ -1,3 +1,7 @@
|
||||
use std::fmt;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::error::OptionsError;
|
||||
use crate::units::{Second, Unit};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
@ -6,6 +10,62 @@ pub const DEFAULT_SHELL: &str = "sh";
|
||||
#[cfg(windows)]
|
||||
pub const DEFAULT_SHELL: &str = "cmd.exe";
|
||||
|
||||
/// Shell to use for executing benchmarked commands
|
||||
pub enum Shell {
|
||||
/// Default shell command
|
||||
Default(&'static str),
|
||||
/// Custom shell command specified via --shell
|
||||
Custom(Vec<String>),
|
||||
}
|
||||
|
||||
impl Default for Shell {
|
||||
fn default() -> Self {
|
||||
Shell::Default(DEFAULT_SHELL)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Shell {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Shell::Default(cmd) => write!(f, "{}", cmd),
|
||||
Shell::Custom(cmdline) => {
|
||||
let mut first = true;
|
||||
for s in cmdline.iter() {
|
||||
if first {
|
||||
first = false;
|
||||
write!(f, "{}", s)?;
|
||||
} else {
|
||||
write!(f, " {}", s)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Shell {
|
||||
/// Parse given string as shell command line
|
||||
pub fn parse<'a>(s: &str) -> Result<Self, OptionsError<'a>> {
|
||||
let v = shell_words::split(s.as_ref()).map_err(OptionsError::ShellParseError)?;
|
||||
if v.is_empty() {
|
||||
return Err(OptionsError::EmptyShell);
|
||||
}
|
||||
Ok(Shell::Custom(v))
|
||||
}
|
||||
|
||||
pub fn command(&self) -> Command {
|
||||
match self {
|
||||
Shell::Default(cmd) => Command::new(cmd),
|
||||
Shell::Custom(cmdline) => {
|
||||
let mut c = Command::new(&cmdline[0]);
|
||||
c.args(&cmdline[1..]);
|
||||
c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Action to take when an executed command fails.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum CmdFailureAction {
|
||||
@ -74,7 +134,7 @@ pub struct HyperfineOptions {
|
||||
pub output_style: OutputStyleOption,
|
||||
|
||||
/// The shell to use for executing commands.
|
||||
pub shell: String,
|
||||
pub shell: Shell,
|
||||
|
||||
/// Forward benchmark's stdout to hyperfine's stdout
|
||||
pub show_output: bool,
|
||||
@ -99,7 +159,7 @@ impl Default for HyperfineOptions {
|
||||
preparation_command: None,
|
||||
cleanup_command: None,
|
||||
output_style: OutputStyleOption::Full,
|
||||
shell: DEFAULT_SHELL.to_string(),
|
||||
shell: Shell::default(),
|
||||
show_output: false,
|
||||
time_unit: None,
|
||||
}
|
||||
|
17
src/shell.rs
17
src/shell.rs
@ -1,6 +1,7 @@
|
||||
use std::io;
|
||||
use std::process::{Command, ExitStatus, Stdio};
|
||||
use std::process::{ExitStatus, Stdio};
|
||||
|
||||
use crate::options::Shell;
|
||||
use crate::timer::get_cpu_timer;
|
||||
|
||||
/// Used to indicate the result of running a command
|
||||
@ -22,7 +23,7 @@ pub fn execute_and_time(
|
||||
stdout: Stdio,
|
||||
stderr: Stdio,
|
||||
command: &str,
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
) -> io::Result<ExecuteResult> {
|
||||
let mut child = run_shell_command(stdout, stderr, command, shell)?;
|
||||
let cpu_timer = get_cpu_timer(&child);
|
||||
@ -42,7 +43,7 @@ pub fn execute_and_time(
|
||||
stdout: Stdio,
|
||||
stderr: Stdio,
|
||||
command: &str,
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
) -> io::Result<ExecuteResult> {
|
||||
let cpu_timer = get_cpu_timer();
|
||||
|
||||
@ -63,9 +64,10 @@ fn run_shell_command(
|
||||
stdout: Stdio,
|
||||
stderr: Stdio,
|
||||
command: &str,
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
) -> io::Result<std::process::ExitStatus> {
|
||||
Command::new(shell)
|
||||
shell
|
||||
.command()
|
||||
.arg("-c")
|
||||
.arg(command)
|
||||
.env(
|
||||
@ -84,9 +86,10 @@ fn run_shell_command(
|
||||
stdout: Stdio,
|
||||
stderr: Stdio,
|
||||
command: &str,
|
||||
shell: &str,
|
||||
shell: &Shell,
|
||||
) -> io::Result<std::process::Child> {
|
||||
Command::new(shell)
|
||||
shell
|
||||
.command()
|
||||
.arg("/C")
|
||||
.arg(command)
|
||||
.stdin(Stdio::null())
|
||||
|
Loading…
Reference in New Issue
Block a user