mirror of
https://github.com/sharkdp/hyperfine.git
synced 2024-09-11 22:17:46 +03:00
Added --stdin-data argument
This argument accepts a path to a file. The data contained in the file will be passed to the command via stdin. Closes sharkdp/hyperfine#541
This commit is contained in:
parent
531fee3188
commit
e38acdb683
@ -1,7 +1,7 @@
|
||||
use std::process::{ExitStatus, Stdio};
|
||||
|
||||
use crate::command::Command;
|
||||
use crate::options::{CmdFailureAction, CommandOutputPolicy, Options, OutputStyleOption, Shell};
|
||||
use crate::options::{CmdFailureAction, CommandInputPolicy, CommandOutputPolicy, Options, OutputStyleOption, Shell};
|
||||
use crate::output::progress_bar::get_progress_bar;
|
||||
use crate::timer::{execute_and_measure, TimerResult};
|
||||
use crate::util::randomized_environment_offset;
|
||||
@ -36,11 +36,13 @@ pub trait Executor {
|
||||
fn run_command_and_measure_common(
|
||||
mut command: std::process::Command,
|
||||
command_failure_action: CmdFailureAction,
|
||||
command_input_policy: &CommandInputPolicy,
|
||||
command_output_policy: &CommandOutputPolicy,
|
||||
command_name: &str,
|
||||
) -> Result<TimerResult> {
|
||||
let (stdout, stderr) = command_output_policy.get_stdout_stderr()?;
|
||||
command.stdin(Stdio::null()).stdout(stdout).stderr(stderr);
|
||||
let stdin = command_input_policy.get_stdin()?;
|
||||
command.stdin(stdin).stdout(stdout).stderr(stderr);
|
||||
|
||||
command.env(
|
||||
"HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET",
|
||||
@ -83,6 +85,7 @@ impl<'a> Executor for RawExecutor<'a> {
|
||||
let result = run_command_and_measure_common(
|
||||
command.get_command()?,
|
||||
command_failure_action.unwrap_or(self.options.command_failure_action),
|
||||
&self.options.command_input_policy,
|
||||
&self.options.command_output_policy,
|
||||
&command.get_command_line(),
|
||||
)?;
|
||||
@ -142,6 +145,7 @@ impl<'a> Executor for ShellExecutor<'a> {
|
||||
let mut result = run_command_and_measure_common(
|
||||
command_builder,
|
||||
command_failure_action.unwrap_or(self.options.command_failure_action),
|
||||
&self.options.command_input_policy,
|
||||
&self.options.command_output_policy,
|
||||
&command.get_command_line(),
|
||||
)?;
|
||||
|
@ -312,6 +312,14 @@ fn build_command() -> Command {
|
||||
.hide(true)
|
||||
.help("Enable debug mode which does not actually run commands, but returns fake times when the command is 'sleep <time>'.")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("stdin-data")
|
||||
.long("stdin-data")
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.value_name("FILE")
|
||||
.help("Path to file containing stdin data to provide to the command"),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -53,4 +53,6 @@ pub enum OptionsError<'a> {
|
||||
ShellParseError(shell_words::ParseError),
|
||||
#[error("Unknown output policy '{0}'. Use './{0}' to output to a file named '{0}'.")]
|
||||
UnknownOutputPolicy(String),
|
||||
#[error("File containing stdin data '{0}' does not exist")]
|
||||
StdinDataFileDoesNotExist(String),
|
||||
}
|
||||
|
@ -110,6 +110,36 @@ impl Default for RunBounds {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CommandInputPolicy {
|
||||
/// Redirect from the null device
|
||||
Null,
|
||||
|
||||
/// Redirect input from a file
|
||||
File(PathBuf),
|
||||
}
|
||||
|
||||
impl Default for CommandInputPolicy {
|
||||
fn default() -> Self {
|
||||
CommandInputPolicy::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandInputPolicy {
|
||||
pub fn get_stdin(&self) -> io::Result<Stdio> {
|
||||
let stream: Stdio = match self {
|
||||
CommandInputPolicy::Null => Stdio::null(),
|
||||
|
||||
CommandInputPolicy::File(path) => {
|
||||
let file: File = File::open(&path)?;
|
||||
Stdio::from(file)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
}
|
||||
|
||||
/// How to handle the output of benchmarked commands
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum CommandOutputPolicy {
|
||||
@ -196,8 +226,12 @@ pub struct Options {
|
||||
/// What to do with the output of the benchmarked command
|
||||
pub command_output_policy: CommandOutputPolicy,
|
||||
|
||||
/// Which time unit to use when displaying resuls
|
||||
/// Which time unit to use when displaying results
|
||||
pub time_unit: Option<Unit>,
|
||||
|
||||
/// Where input to the benchmarked command comes from
|
||||
pub command_input_policy: CommandInputPolicy,
|
||||
|
||||
}
|
||||
|
||||
impl Default for Options {
|
||||
@ -214,6 +248,7 @@ impl Default for Options {
|
||||
executor_kind: ExecutorKind::default(),
|
||||
command_output_policy: CommandOutputPolicy::Null,
|
||||
time_unit: None,
|
||||
command_input_policy: CommandInputPolicy::Null,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,6 +389,16 @@ impl Options {
|
||||
.map_err(|e| OptionsError::FloatParsingError("min-benchmarking-time", e))?;
|
||||
}
|
||||
|
||||
options.command_input_policy = if let Some(path_str) = matches.value_of("stdin-data") {
|
||||
let path = PathBuf::from(path_str);
|
||||
if !path.exists() {
|
||||
return Err(OptionsError::StdinDataFileDoesNotExist(path_str.to_string()))
|
||||
}
|
||||
CommandInputPolicy::File(path)
|
||||
} else {
|
||||
CommandInputPolicy::Null
|
||||
};
|
||||
|
||||
Ok(options)
|
||||
}
|
||||
|
||||
|
1
tests/example_stdin_data
Normal file
1
tests/example_stdin_data
Normal file
@ -0,0 +1 @@
|
||||
This data is passed to the command via stdin
|
@ -215,6 +215,34 @@ fn runs_commands_using_user_defined_shell() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_pass_file_data_to_command_via_stdin(){
|
||||
hyperfine()
|
||||
.arg("--runs=1")
|
||||
.arg("--stdin-data=example_stdin_data")
|
||||
.arg("--show-output")
|
||||
.arg("cat")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(
|
||||
predicate::str::contains("This data is passed to the command via stdin")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_if_invalid_stdin_data_file_provided(){
|
||||
hyperfine()
|
||||
.arg("--runs=1")
|
||||
.arg("--stdin-data=example_stdin_data_invalid")
|
||||
.arg("--show-output")
|
||||
.arg("cat")
|
||||
.assert()
|
||||
.failure()
|
||||
.stderr(
|
||||
predicate::str::contains("File containing stdin data 'example_stdin_data_invalid' does not exist")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_mean_time_in_correct_unit() {
|
||||
hyperfine_debug()
|
||||
|
Loading…
Reference in New Issue
Block a user