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