mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-02 09:01:25 +00:00
Move Command struct to new module
This commit is contained in:
1 parent
b5bd054cf4
commit
eee32308b7
6 files changed
+130
-120
No files matched your search
@@ -5,6 +5,7 @@ use std::process::{ExitStatus, Stdio};
|
|||||||
use colored::*;
|
use colored::*;
|
||||||
use statistical::{mean, median, standard_deviation};
|
use statistical::{mean, median, standard_deviation};
|
||||||
|
|
||||||
|
use crate::hyperfine::command::Command;
|
||||||
use crate::hyperfine::format::{format_duration, format_duration_unit};
|
use crate::hyperfine::format::{format_duration, format_duration_unit};
|
||||||
use crate::hyperfine::internal::{get_progress_bar, max, min, MIN_EXECUTION_TIME};
|
use crate::hyperfine::internal::{get_progress_bar, max, min, MIN_EXECUTION_TIME};
|
||||||
use crate::hyperfine::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
use crate::hyperfine::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
||||||
@@ -12,7 +13,7 @@ use crate::hyperfine::shell::execute_and_time;
|
|||||||
use crate::hyperfine::timer::wallclocktimer::WallClockTimer;
|
use crate::hyperfine::timer::wallclocktimer::WallClockTimer;
|
||||||
use crate::hyperfine::timer::{TimerStart, TimerStop};
|
use crate::hyperfine::timer::{TimerStart, TimerStop};
|
||||||
use crate::hyperfine::types::{
|
use crate::hyperfine::types::{
|
||||||
BenchmarkResult, CmdFailureAction, Command, HyperfineOptions, OutputStyleOption,
|
BenchmarkResult, CmdFailureAction, HyperfineOptions, OutputStyleOption,
|
||||||
};
|
};
|
||||||
use crate::hyperfine::units::Second;
|
use crate::hyperfine::units::Second;
|
||||||
use crate::hyperfine::warnings::Warnings;
|
use crate::hyperfine::warnings::Warnings;
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use super::types::ParameterValue;
|
||||||
|
|
||||||
|
/// A command that should be benchmarked.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Command<'a> {
|
||||||
|
/// The command name (without parameter substitution)
|
||||||
|
name: Option<&'a str>,
|
||||||
|
|
||||||
|
/// The command that should be executed (without parameter substitution)
|
||||||
|
expression: &'a str,
|
||||||
|
|
||||||
|
/// Zero or more parameter values.
|
||||||
|
parameters: Vec<(&'a str, ParameterValue)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Command<'a> {
|
||||||
|
pub fn new(name: Option<&'a str>, expression: &'a str) -> Command<'a> {
|
||||||
|
Command {
|
||||||
|
name,
|
||||||
|
expression,
|
||||||
|
parameters: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_parametrized(
|
||||||
|
name: Option<&'a str>,
|
||||||
|
expression: &'a str,
|
||||||
|
parameters: Vec<(&'a str, ParameterValue)>,
|
||||||
|
) -> Command<'a> {
|
||||||
|
Command {
|
||||||
|
name,
|
||||||
|
expression,
|
||||||
|
parameters,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> String {
|
||||||
|
self.name.map_or_else(
|
||||||
|
|| self.get_shell_command(),
|
||||||
|
|name| self.replace_parameters_in(name),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_shell_command(&self) -> String {
|
||||||
|
self.replace_parameters_in(self.expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parameters(&self) -> &Vec<(&'a str, ParameterValue)> {
|
||||||
|
&self.parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_parameters_in(&self, original: &str) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut replacements = BTreeMap::<String, String>::new();
|
||||||
|
for (param_name, param_value) in &self.parameters {
|
||||||
|
replacements.insert(
|
||||||
|
format!("{{{param_name}}}", param_name = param_name),
|
||||||
|
param_value.to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut remaining = original;
|
||||||
|
// Manually replace consecutive occurrences to avoid double-replacing: e.g.,
|
||||||
|
//
|
||||||
|
// hyperfine -L foo 'a,{bar}' -L bar 'baz,quux' 'echo {foo} {bar}'
|
||||||
|
//
|
||||||
|
// should not ever run 'echo baz baz'. See `test_get_shell_command_nonoverlapping`.
|
||||||
|
'outer: while let Some(head) = remaining.chars().next() {
|
||||||
|
for (k, v) in &replacements {
|
||||||
|
if remaining.starts_with(k.as_str()) {
|
||||||
|
result.push_str(v);
|
||||||
|
remaining = &remaining[k.len()..];
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(head);
|
||||||
|
remaining = &remaining[head.len_utf8()..];
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_shell_command_nonoverlapping() {
|
||||||
|
let cmd = Command::new_parametrized(
|
||||||
|
None,
|
||||||
|
"echo {foo} {bar}",
|
||||||
|
vec![
|
||||||
|
("foo", ParameterValue::Text("{bar} baz".into())),
|
||||||
|
("bar", ParameterValue::Text("quux".into())),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_eq!(cmd.get_shell_command(), "echo {bar} baz quux");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_parameterized_command_name() {
|
||||||
|
let cmd = Command::new_parametrized(
|
||||||
|
Some("name-{bar}-{foo}"),
|
||||||
|
"echo {foo} {bar}",
|
||||||
|
vec![
|
||||||
|
("foo", ParameterValue::Text("baz".into())),
|
||||||
|
("bar", ParameterValue::Text("quux".into())),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_eq!(cmd.get_name(), "name-quux-baz");
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for Command<'a> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.get_shell_command())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod benchmark;
|
pub mod benchmark;
|
||||||
|
pub mod command;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod export;
|
pub mod export;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
use crate::hyperfine::error::ParameterScanError;
|
|
||||||
use crate::hyperfine::types::{Command, NumericType, ParameterValue};
|
|
||||||
use clap::Values;
|
|
||||||
use rust_decimal::Decimal;
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::ops::{Add, AddAssign, Div, Sub};
|
use std::ops::{Add, AddAssign, Div, Sub};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use clap::Values;
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
|
use crate::hyperfine::command::Command;
|
||||||
|
use crate::hyperfine::error::ParameterScanError;
|
||||||
|
use crate::hyperfine::types::{NumericType, ParameterValue};
|
||||||
|
|
||||||
trait Numeric:
|
trait Numeric:
|
||||||
Add<Output = Self>
|
Add<Output = Self>
|
||||||
+ Sub<Output = Self>
|
+ Sub<Output = Self>
|
||||||
|
|||||||
+3
-114
@@ -1,11 +1,11 @@
|
|||||||
use rust_decimal::prelude::ToPrimitive;
|
|
||||||
use rust_decimal::Decimal;
|
|
||||||
/// This module contains common internal types.
|
|
||||||
use serde::*;
|
use serde::*;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
use crate::hyperfine::units::{Second, Unit};
|
use crate::hyperfine::units::{Second, Unit};
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@@ -71,117 +71,6 @@ impl<'a> ToString for ParameterValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A command that should be benchmarked.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct Command<'a> {
|
|
||||||
/// The command name (without parameter substitution)
|
|
||||||
name: Option<&'a str>,
|
|
||||||
|
|
||||||
/// The command that should be executed (without parameter substitution)
|
|
||||||
expression: &'a str,
|
|
||||||
|
|
||||||
/// Zero or more parameter values.
|
|
||||||
parameters: Vec<(&'a str, ParameterValue)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Command<'a> {
|
|
||||||
pub fn new(name: Option<&'a str>, expression: &'a str) -> Command<'a> {
|
|
||||||
Command {
|
|
||||||
name,
|
|
||||||
expression,
|
|
||||||
parameters: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_parametrized(
|
|
||||||
name: Option<&'a str>,
|
|
||||||
expression: &'a str,
|
|
||||||
parameters: Vec<(&'a str, ParameterValue)>,
|
|
||||||
) -> Command<'a> {
|
|
||||||
Command {
|
|
||||||
name,
|
|
||||||
expression,
|
|
||||||
parameters,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_name(&self) -> String {
|
|
||||||
self.name.map_or_else(
|
|
||||||
|| self.get_shell_command(),
|
|
||||||
|name| self.replace_parameters_in(name),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_shell_command(&self) -> String {
|
|
||||||
self.replace_parameters_in(self.expression)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_parameters(&self) -> &Vec<(&'a str, ParameterValue)> {
|
|
||||||
&self.parameters
|
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_parameters_in(&self, original: &str) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
let mut replacements = BTreeMap::<String, String>::new();
|
|
||||||
for (param_name, param_value) in &self.parameters {
|
|
||||||
replacements.insert(
|
|
||||||
format!("{{{param_name}}}", param_name = param_name),
|
|
||||||
param_value.to_string(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut remaining = original;
|
|
||||||
// Manually replace consecutive occurrences to avoid double-replacing: e.g.,
|
|
||||||
//
|
|
||||||
// hyperfine -L foo 'a,{bar}' -L bar 'baz,quux' 'echo {foo} {bar}'
|
|
||||||
//
|
|
||||||
// should not ever run 'echo baz baz'. See `test_get_shell_command_nonoverlapping`.
|
|
||||||
'outer: while let Some(head) = remaining.chars().next() {
|
|
||||||
for (k, v) in &replacements {
|
|
||||||
if remaining.starts_with(k.as_str()) {
|
|
||||||
result.push_str(v);
|
|
||||||
remaining = &remaining[k.len()..];
|
|
||||||
continue 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.push(head);
|
|
||||||
remaining = &remaining[head.len_utf8()..];
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_shell_command_nonoverlapping() {
|
|
||||||
let cmd = Command::new_parametrized(
|
|
||||||
None,
|
|
||||||
"echo {foo} {bar}",
|
|
||||||
vec![
|
|
||||||
("foo", ParameterValue::Text("{bar} baz".into())),
|
|
||||||
("bar", ParameterValue::Text("quux".into())),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(cmd.get_shell_command(), "echo {bar} baz quux");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_parameterized_command_name() {
|
|
||||||
let cmd = Command::new_parametrized(
|
|
||||||
Some("name-{bar}-{foo}"),
|
|
||||||
"echo {foo} {bar}",
|
|
||||||
vec![
|
|
||||||
("foo", ParameterValue::Text("baz".into())),
|
|
||||||
("bar", ParameterValue::Text("quux".into())),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(cmd.get_name(), "name-quux-baz");
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> fmt::Display for Command<'a> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.get_shell_command())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 {
|
||||||
|
|||||||
+2
-1
@@ -11,12 +11,13 @@ mod hyperfine;
|
|||||||
|
|
||||||
use crate::hyperfine::app::get_arg_matches;
|
use crate::hyperfine::app::get_arg_matches;
|
||||||
use crate::hyperfine::benchmark::{mean_shell_spawning_time, run_benchmark};
|
use crate::hyperfine::benchmark::{mean_shell_spawning_time, run_benchmark};
|
||||||
|
use crate::hyperfine::command::Command;
|
||||||
use crate::hyperfine::error::OptionsError;
|
use crate::hyperfine::error::OptionsError;
|
||||||
use crate::hyperfine::export::{ExportManager, ExportType};
|
use crate::hyperfine::export::{ExportManager, ExportType};
|
||||||
use crate::hyperfine::internal::{tokenize, write_benchmark_comparison};
|
use crate::hyperfine::internal::{tokenize, write_benchmark_comparison};
|
||||||
use crate::hyperfine::parameter_range::get_parameterized_commands;
|
use crate::hyperfine::parameter_range::get_parameterized_commands;
|
||||||
use crate::hyperfine::types::{
|
use crate::hyperfine::types::{
|
||||||
CmdFailureAction, Command, HyperfineOptions, OutputStyleOption, ParameterValue,
|
CmdFailureAction, HyperfineOptions, OutputStyleOption, ParameterValue,
|
||||||
};
|
};
|
||||||
use crate::hyperfine::units::Unit;
|
use crate::hyperfine::units::Unit;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user