feat: allow changing default command timeout (#2283)

* feat: allow changing default command timeout

* fix clippy

* add doc to exec_cmd in Context

* update docs in CONTRIBUTING.md

* Fix comment in CONTRIBUTING.md

Co-authored-by: Thomas O'Donnell <andytom@users.noreply.github.com>

Co-authored-by: Thomas O'Donnell <andytom@users.noreply.github.com>
This commit is contained in:
David Knaack 2021-02-11 21:34:47 +01:00 committed by GitHub
parent 04d1332f9c
commit eccbda8328
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 112 additions and 97 deletions

View File

@ -37,7 +37,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::php::PhpConfig;
use crate::formatter::StringFormatter;
use crate::utils;
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
@ -51,20 +50,19 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
## External commands
To run a external command (e.g. to get the version of a tool) and to allow for mocking use the `utils::exec_cmd` function. Here's a quick example:
To run a external command (e.g. to get the version of a tool) and to allow for mocking use the `context.exec_cmd` function. Here's a quick example:
```rust
use super::{Context, Module, RootModuleConfig};
use crate::configs::php::PhpConfig;
use crate::formatter::StringFormatter;
use crate::utils;
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// Here `my_env_var` will be either the stdout of the called command or the function
// Here `output` will be either the stdout of the called command or the function
// will exit if the called program was not installed or could not be run.
let output = utils::exec_cmd("my_command", &["first_arg", "second_arg"])?.stdout;
let output = context.exec_cmd("my_command", &["first_arg", "second_arg"])?.stdout;
// Then you can happily use the output
}

View File

@ -3,6 +3,7 @@ use crate::utils::exec_cmd;
use std::fs;
use std::path::PathBuf;
use std::time::Duration;
#[cfg(feature = "http")]
const GIT_IO_BASE_URL: &str = "https://git.io/";
@ -152,7 +153,7 @@ fn get_shell_info() -> ShellInfo {
let shell = shell.unwrap();
let version = exec_cmd(&shell, &["--version"])
let version = exec_cmd(&shell, &["--version"], Duration::from_millis(500))
.map(|output| output.stdout.trim().to_string())
.unwrap_or_else(|| UNKNOWN_VERSION.to_string());

View File

@ -6,6 +6,7 @@ use starship_module_config_derive::ModuleConfig;
pub struct StarshipRootConfig<'a> {
pub format: &'a str,
pub scan_timeout: u64,
pub command_timeout: u64,
pub add_newline: bool,
}
@ -78,6 +79,7 @@ impl<'a> RootModuleConfig<'a> for StarshipRootConfig<'a> {
StarshipRootConfig {
format: "$all",
scan_timeout: 30,
command_timeout: 500,
add_newline: true,
}
}

View File

@ -1,5 +1,6 @@
use crate::config::StarshipConfig;
use crate::module::Module;
use crate::utils::{exec_cmd, CommandOutput};
use crate::modules;
use clap::ArgMatches;
@ -43,6 +44,9 @@ pub struct Context<'a> {
/// A HashMap of environment variable mocks
pub env: HashMap<&'a str, String>,
/// Timeout for the execution of commands
cmd_timeout: Duration,
}
impl<'a> Context<'a> {
@ -100,6 +104,8 @@ impl<'a> Context<'a> {
let current_dir = current_dir.canonicalize().unwrap_or(current_dir);
let logical_dir = logical_path;
let cmd_timeout = Duration::from_millis(config.get_root_config().command_timeout);
Context {
config,
properties,
@ -109,6 +115,7 @@ impl<'a> Context<'a> {
repo: OnceCell::new(),
shell,
env: HashMap::new(),
cmd_timeout,
}
}
@ -237,6 +244,11 @@ impl<'a> Context<'a> {
pub fn get_cmd_duration(&self) -> Option<u128> {
self.properties.get("cmd_duration")?.parse::<u128>().ok()
}
/// Execute a command and return the output on stdout and stderr if successful
pub fn exec_cmd(&self, cmd: &str, args: &[&str]) -> Option<CommandOutput> {
exec_cmd(cmd, args, self.cmd_timeout)
}
}
#[derive(Debug)]

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::cmake::CMakeConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current CMake version
///
@ -31,7 +30,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
_ => None,
})
.map(|variable| match variable {
"version" => utils::exec_cmd("cmake", &["--version"])
"version" => context
.exec_cmd("cmake", &["--version"])
.map(|output| format_cmake_version(&output.stdout))
.flatten()
.map(Ok),

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::crystal::CrystalConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Crystal version
///
@ -35,7 +34,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => format_crystal_version(
utils::exec_cmd("crystal", &["--version"])?.stdout.as_str(),
context.exec_cmd("crystal", &["--version"])?.stdout.as_str(),
)
.map(Ok),
_ => None,

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::dart::DartConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Dart version
///
@ -37,7 +36,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let dart_version = utils::exec_cmd("dart", &["--version"])?.stderr;
let dart_version = context.exec_cmd("dart", &["--version"])?.stderr;
parse_dart_version(&dart_version).map(Ok)
}
_ => None,

View File

@ -66,9 +66,14 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
"version" => {
let version = if enable_heuristic {
let repo_root = context.get_repo().ok().and_then(|r| r.root.as_deref());
estimate_dotnet_version(&dotnet_files, &context.current_dir, repo_root)
estimate_dotnet_version(
context,
&dotnet_files,
&context.current_dir,
repo_root,
)
} else {
get_version_from_cli()
get_version_from_cli(context)
};
version.map(|v| Ok(v.0))
}
@ -136,6 +141,7 @@ fn get_tfm_from_project_file(path: &Path) -> Option<String> {
}
fn estimate_dotnet_version(
context: &Context,
files: &[DotNetFile],
current_dir: &Path,
repo_root: Option<&Path>,
@ -150,17 +156,18 @@ fn estimate_dotnet_version(
match relevant_file.file_type {
FileType::GlobalJson => get_pinned_sdk_version_from_file(relevant_file.path.as_path())
.or_else(get_latest_sdk_from_cli),
.or_else(|| get_latest_sdk_from_cli(context)),
FileType::SolutionFile => {
// With this heuristic, we'll assume that a "global.json" won't
// be found in any directory above the solution file.
get_latest_sdk_from_cli()
get_latest_sdk_from_cli(context)
}
_ => {
// If we see a dotnet project, we'll check a small number of neighboring
// directories to see if we can find a global.json. Otherwise, assume the
// latest SDK is in use.
try_find_nearby_global_json(current_dir, repo_root).or_else(get_latest_sdk_from_cli)
try_find_nearby_global_json(current_dir, repo_root)
.or_else(|| get_latest_sdk_from_cli(context))
}
}
}
@ -288,13 +295,13 @@ fn map_str_to_lower(value: Option<&OsStr>) -> Option<String> {
Some(value?.to_str()?.to_ascii_lowercase())
}
fn get_version_from_cli() -> Option<Version> {
let version_output = utils::exec_cmd("dotnet", &["--version"])?;
fn get_version_from_cli(context: &Context) -> Option<Version> {
let version_output = context.exec_cmd("dotnet", &["--version"])?;
Some(Version(format!("v{}", version_output.stdout.trim())))
}
fn get_latest_sdk_from_cli() -> Option<Version> {
match utils::exec_cmd("dotnet", &["--list-sdks"]) {
fn get_latest_sdk_from_cli(context: &Context) -> Option<Version> {
match context.exec_cmd("dotnet", &["--list-sdks"]) {
Some(sdks_output) => {
fn parse_failed<T>() -> Option<T> {
log::warn!("Unable to parse the output from `dotnet --list-sdks`.");
@ -325,7 +332,7 @@ fn get_latest_sdk_from_cli() -> Option<Version> {
"Received a non-success exit code from `dotnet --list-sdks`. \
Falling back to `dotnet --version`.",
);
get_version_from_cli()
get_version_from_cli(context)
}
}
}

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::elixir::ElixirConfig;
use crate::formatter::StringFormatter;
use crate::utils;
use once_cell::sync::Lazy;
use regex::Regex;
@ -23,7 +22,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
return None;
}
let versions = Lazy::new(get_elixir_version);
let versions = Lazy::new(|| get_elixir_version(context));
let mut module = context.new_module("elixir");
let config = ElixirConfig::try_load(module.config);
@ -64,8 +63,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Some(module)
}
fn get_elixir_version() -> Option<(String, String)> {
let output = utils::exec_cmd("elixir", &["--version"])?.stdout;
fn get_elixir_version(context: &Context) -> Option<(String, String)> {
let output = context.exec_cmd("elixir", &["--version"])?.stdout;
parse_elixir_version(&output)
}

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::elm::ElmConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Elm version
///
@ -39,7 +38,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let elm_version = utils::exec_cmd("elm", &["--version"])?.stdout;
let elm_version = context.exec_cmd("elm", &["--version"])?.stdout;
let module_version = Some(format!("v{}", elm_version.trim()))?;
Some(Ok(module_version))
}

View File

@ -32,7 +32,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
_ => None,
})
.map(|variable| match variable {
"version" => get_erlang_version().map(Ok),
"version" => get_erlang_version(context).map(Ok),
_ => None,
})
.parse(None)
@ -49,10 +49,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Some(module)
}
fn get_erlang_version() -> Option<String> {
use crate::utils;
Some(utils::exec_cmd(
fn get_erlang_version(context: &Context) -> Option<String> {
Some(context.exec_cmd(
"erl",
&[
"-noshell",

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::go::GoConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Go version
///
@ -48,7 +47,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
format_go_version(&utils::exec_cmd("go", &["version"])?.stdout.as_str()).map(Ok)
format_go_version(&context.exec_cmd("go", &["version"])?.stdout.as_str())
.map(Ok)
}
_ => None,
})

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::helm::HelmConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Helm version
///
@ -33,7 +32,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => format_helm_version(
&utils::exec_cmd("helm", &["version", "--short", "--client"])?
&context
.exec_cmd("helm", &["version", "--short", "--client"])?
.stdout
.as_str(),
)

View File

@ -3,8 +3,6 @@ use crate::formatter::StringFormatter;
use super::{Context, Module, RootModuleConfig};
use crate::utils;
use regex::Regex;
const JAVA_VERSION_PATTERN: &str = "(?P<version>[\\d\\.]+)[^\\s]*\\s(?:built|from)";
@ -72,7 +70,7 @@ fn get_java_version(context: &Context) -> Option<String> {
None => String::from("java"),
};
let output = utils::exec_cmd(&java_command.as_str(), &["-Xinternalversion"])?;
let output = context.exec_cmd(&java_command.as_str(), &["-Xinternalversion"])?;
let java_version = if output.stdout.is_empty() {
output.stderr
} else {

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::julia::JuliaConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Julia version
///
@ -34,10 +33,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
_ => None,
})
.map(|variable| match variable {
"version" => {
format_julia_version(&utils::exec_cmd("julia", &["--version"])?.stdout.as_str())
.map(Ok)
}
"version" => format_julia_version(
&context.exec_cmd("julia", &["--version"])?.stdout.as_str(),
)
.map(Ok),
_ => None,
})
.parse(None)

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::kotlin::KotlinConfig;
use crate::formatter::StringFormatter;
use crate::utils;
use regex::Regex;
const KOTLIN_VERSION_PATTERN: &str = "(?P<version>[\\d\\.]+[\\d\\.]+[\\d\\.]+)";
@ -35,8 +34,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let kotlin_version =
format_kotlin_version(&get_kotlin_version(&config.kotlin_binary)?)?;
let kotlin_version = format_kotlin_version(&get_kotlin_version(
context,
&config.kotlin_binary,
)?)?;
Some(Ok(kotlin_version))
}
_ => None,
@ -55,8 +56,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Some(module)
}
fn get_kotlin_version(kotlin_binary: &str) -> Option<String> {
match utils::exec_cmd(kotlin_binary, &["-version"]) {
fn get_kotlin_version(context: &Context, kotlin_binary: &str) -> Option<String> {
match context.exec_cmd(kotlin_binary, &["-version"]) {
Some(output) => {
if output.stdout.is_empty() {
Some(output.stderr)

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::lua::LuaConfig;
use crate::formatter::StringFormatter;
use crate::utils;
use regex::Regex;
const LUA_VERSION_PATERN: &str = "(?P<version>[\\d\\.]+[a-z\\-]*[1-9]*)[^\\s]*";
@ -39,7 +38,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let lua_version = format_lua_version(&get_lua_version(&config.lua_binary)?)?;
let lua_version =
format_lua_version(&get_lua_version(context, &config.lua_binary)?)?;
Some(Ok(lua_version))
}
_ => None,
@ -58,8 +58,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Some(module)
}
fn get_lua_version(lua_binary: &str) -> Option<String> {
match utils::exec_cmd(lua_binary, &["-v"]) {
fn get_lua_version(context: &Context, lua_binary: &str) -> Option<String> {
match context.exec_cmd(lua_binary, &["-v"]) {
Some(output) => {
if output.stdout.is_empty() {
Some(output.stderr)

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::nim::NimConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Nim version
///
@ -34,7 +33,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
_ => None,
})
.map(|variable| match variable {
"version" => utils::exec_cmd("nim", &["--version"])
"version" => context
.exec_cmd("nim", &["--version"])
.map(|command_output| command_output.stdout)
.and_then(|nim_version_output| {
Some(format!("v{}", parse_nim_version(&nim_version_output)?))

View File

@ -38,8 +38,11 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("nodejs");
let config = NodejsConfig::try_load(module.config);
let nodejs_version =
Lazy::new(|| utils::exec_cmd("node", &["--version"]).map(|cmd| cmd.stdout));
let nodejs_version = Lazy::new(|| {
context
.exec_cmd("node", &["--version"])
.map(|cmd| cmd.stdout)
});
let parsed = StringFormatter::new(config.format).and_then(|formatter| {
formatter
.map_meta(|var, _| match var {

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::ocaml::OCamlConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current OCaml version
///
@ -46,9 +45,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
.is_match();
let ocaml_version = if is_esy_project {
utils::exec_cmd("esy", &["ocaml", "-vnum"])?.stdout
context.exec_cmd("esy", &["ocaml", "-vnum"])?.stdout
} else {
utils::exec_cmd("ocaml", &["-vnum"])?.stdout
context.exec_cmd("ocaml", &["-vnum"])?.stdout
};
Some(Ok(format!("v{}", &ocaml_version.trim())))
}

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::perl::PerlConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current perl version
///
@ -44,8 +43,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let perl_version =
utils::exec_cmd("perl", &["-e", "printf q#%vd#,$^V;"])?.stdout;
let perl_version = context
.exec_cmd("perl", &["-e", "printf q#%vd#,$^V;"])?
.stdout;
Some(Ok(format!("v{}", perl_version)))
}
_ => None,

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::php::PhpConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current PHP version
///
@ -35,7 +34,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let php_cmd_output = utils::exec_cmd(
let php_cmd_output = context.exec_cmd(
"php",
&[
"-nr",

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::purescript::PureScriptConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current PureScript version
///
@ -35,7 +34,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let purs_version = utils::exec_cmd("purs", &["--version"])?.stdout;
let purs_version = context.exec_cmd("purs", &["--version"])?.stdout;
Some(Ok(format!("v{}", purs_version.trim())))
}
_ => None,

View File

@ -4,7 +4,6 @@ use std::path::Path;
use super::{Context, Module, RootModuleConfig};
use crate::configs::python::PythonConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Python version and, if active, virtual environment.
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
@ -42,7 +41,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let version = get_python_version(&config)?;
let version = get_python_version(context, &config)?;
Some(Ok(version.trim().to_string()))
}
"virtualenv" => {
@ -66,12 +65,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Some(module)
}
fn get_python_version(config: &PythonConfig) -> Option<String> {
fn get_python_version(context: &Context, config: &PythonConfig) -> Option<String> {
if config.pyenv_version_name {
return Some(utils::exec_cmd("pyenv", &["version-name"])?.stdout);
return Some(context.exec_cmd("pyenv", &["version-name"])?.stdout);
};
let version = config.python_binary.0.iter().find_map(|binary| {
match utils::exec_cmd(binary, &["--version"]) {
match context.exec_cmd(binary, &["--version"]) {
Some(output) => {
if output.stdout.is_empty() {
Some(output.stderr)

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::ruby::RubyConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Ruby version
///
@ -34,7 +33,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
format_ruby_version(&utils::exec_cmd("ruby", &["-v"])?.stdout.as_str()).map(Ok)
format_ruby_version(&context.exec_cmd("ruby", &["-v"])?.stdout.as_str()).map(Ok)
}
_ => None,
})

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::swift::SwiftConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Swift version
///
@ -34,7 +33,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let swift_version = utils::exec_cmd("swift", &["--version"])?.stdout;
let swift_version = context.exec_cmd("swift", &["--version"])?.stdout;
parse_swift_version(&swift_version).map(Ok)
}
_ => None,

View File

@ -38,7 +38,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => format_terraform_version(
&utils::exec_cmd("terraform", &["version"])?.stdout.as_str(),
&context.exec_cmd("terraform", &["version"])?.stdout.as_str(),
)
.map(Ok),
"workspace" => get_terraform_workspace(context).map(Ok),

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::vagrant::VagrantConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Vagrant version
///
@ -32,7 +31,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => format_vagrant_version(
&utils::exec_cmd("vagrant", &["--version"])?.stdout.as_str(),
&context.exec_cmd("vagrant", &["--version"])?.stdout.as_str(),
)
.map(Ok),
_ => None,

View File

@ -2,7 +2,6 @@ use super::{Context, Module, RootModuleConfig};
use crate::configs::zig::ZigConfig;
use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Zig version
///
@ -33,7 +32,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
})
.map(|variable| match variable {
"version" => {
let zig_version_output = utils::exec_cmd("zig", &["version"])?.stdout;
let zig_version_output = context.exec_cmd("zig", &["version"])?.stdout;
let zig_version = format!("v{}", zig_version_output.trim());
Some(Ok(zig_version))
}

View File

@ -30,12 +30,12 @@ impl PartialEq for CommandOutput {
/// Execute a command and return the output on stdout and stderr if successful
#[cfg(not(test))]
pub fn exec_cmd(cmd: &str, args: &[&str]) -> Option<CommandOutput> {
internal_exec_cmd(&cmd, &args)
pub fn exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<CommandOutput> {
internal_exec_cmd(&cmd, &args, time_limit)
}
#[cfg(test)]
pub fn exec_cmd(cmd: &str, args: &[&str]) -> Option<CommandOutput> {
pub fn exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<CommandOutput> {
let command = match args.len() {
0 => String::from(cmd),
_ => format!("{} {}", cmd, args.join(" ")),
@ -202,7 +202,7 @@ CMake suite maintained and supported by Kitware (kitware.com/cmake).\n",
stderr: String::default(),
}),
// If we don't have a mocked command fall back to executing the command
_ => internal_exec_cmd(&cmd, &args),
_ => internal_exec_cmd(&cmd, &args, time_limit),
}
}
@ -255,7 +255,7 @@ pub fn wrap_seq_for_shell(
final_string
}
fn internal_exec_cmd(cmd: &str, args: &[&str]) -> Option<CommandOutput> {
fn internal_exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<CommandOutput> {
log::trace!("Executing command {:?} with args {:?}", cmd, args);
let full_path = match which::which(cmd) {
@ -269,8 +269,6 @@ fn internal_exec_cmd(cmd: &str, args: &[&str]) -> Option<CommandOutput> {
}
};
let time_limit = Duration::from_millis(500);
let start = Instant::now();
let process = match Command::new(full_path)
@ -310,7 +308,8 @@ fn internal_exec_cmd(cmd: &str, args: &[&str]) -> Option<CommandOutput> {
})
}
Ok(None) => {
log::warn!("Executing command {:?} timed out", cmd);
log::warn!("Executing command {:?} timed out.", cmd);
log::warn!("You can set command_timeout in your config to a higher value to allow longer-running commands to keep executing.");
None
}
Err(error) => {
@ -326,7 +325,7 @@ mod tests {
#[test]
fn exec_mocked_command() {
let result = exec_cmd("dummy_command", &[]);
let result = exec_cmd("dummy_command", &[], Duration::from_millis(500));
let expected = Some(CommandOutput {
stdout: String::from("stdout ok!\n"),
stderr: String::from("stderr ok!\n"),
@ -341,7 +340,7 @@ mod tests {
#[test]
#[cfg(not(windows))]
fn exec_no_output() {
let result = internal_exec_cmd("true", &[]);
let result = internal_exec_cmd("true", &[], Duration::from_millis(500));
let expected = Some(CommandOutput {
stdout: String::from(""),
stderr: String::from(""),
@ -353,7 +352,8 @@ mod tests {
#[test]
#[cfg(not(windows))]
fn exec_with_output_stdout() {
let result = internal_exec_cmd("/bin/sh", &["-c", "echo hello"]);
let result =
internal_exec_cmd("/bin/sh", &["-c", "echo hello"], Duration::from_millis(500));
let expected = Some(CommandOutput {
stdout: String::from("hello\n"),
stderr: String::from(""),
@ -365,7 +365,11 @@ mod tests {
#[test]
#[cfg(not(windows))]
fn exec_with_output_stderr() {
let result = internal_exec_cmd("/bin/sh", &["-c", "echo hello >&2"]);
let result = internal_exec_cmd(
"/bin/sh",
&["-c", "echo hello >&2"],
Duration::from_millis(500),
);
let expected = Some(CommandOutput {
stdout: String::from(""),
stderr: String::from("hello\n"),
@ -377,7 +381,11 @@ mod tests {
#[test]
#[cfg(not(windows))]
fn exec_with_output_both() {
let result = internal_exec_cmd("/bin/sh", &["-c", "echo hello; echo world >&2"]);
let result = internal_exec_cmd(
"/bin/sh",
&["-c", "echo hello; echo world >&2"],
Duration::from_millis(500),
);
let expected = Some(CommandOutput {
stdout: String::from("hello\n"),
stderr: String::from("world\n"),
@ -389,7 +397,7 @@ mod tests {
#[test]
#[cfg(not(windows))]
fn exec_with_non_zero_exit_code() {
let result = internal_exec_cmd("false", &[]);
let result = internal_exec_cmd("false", &[], Duration::from_millis(500));
let expected = None;
assert_eq!(result, expected)
@ -398,7 +406,7 @@ mod tests {
#[test]
#[cfg(not(windows))]
fn exec_slow_command() {
let result = internal_exec_cmd("sleep", &["500"]);
let result = internal_exec_cmd("sleep", &["500"], Duration::from_millis(500));
let expected = None;
assert_eq!(result, expected)