diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/modules/rust.rs | 28 | ||||
-rw-r--r-- | src/utils.rs | 70 |
2 files changed, 84 insertions, 14 deletions
diff --git a/src/modules/rust.rs b/src/modules/rust.rs index 2dcf73087..2fd255b62 100644 --- a/src/modules/rust.rs +++ b/src/modules/rust.rs @@ -1,6 +1,7 @@ use std::fs; use std::path::Path; use std::process::{Command, Output}; +use std::time::Duration; use serde::Deserialize; @@ -8,6 +9,8 @@ use super::{Context, Module, RootModuleConfig}; use crate::configs::rust::RustConfig; use crate::formatter::{StringFormatter, VersionFormatter}; +use crate::utils::exec_cmd; +use starship_cache::CachedOutput; /// Creates a module with the current Rust version pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> { @@ -188,15 +191,20 @@ fn find_rust_toolchain_file(context: &Context) -> Option<String> { } fn execute_rustup_run_rustc_version(toolchain: &str) -> RustupRunRustcVersionOutcome { - Command::new("rustup") - .args(&["run", toolchain, "rustc", "--version"]) - .output() - .map(extract_toolchain_from_rustup_run_rustc_version) - .unwrap_or(RustupRunRustcVersionOutcome::RustupNotWorking) + exec_cmd( + "rustup", + &["run", toolchain, "rustc", "--version"], + Duration::from_millis(500), + ) + .map(extract_toolchain_from_rustup_run_rustc_version) + .unwrap_or(RustupRunRustcVersionOutcome::RustupNotWorking) } -fn extract_toolchain_from_rustup_run_rustc_version(output: Output) -> RustupRunRustcVersionOutcome { - if output.status.success() { +fn extract_toolchain_from_rustup_run_rustc_version<O: Into<CachedOutput>>( + output: O, +) -> RustupRunRustcVersionOutcome { + let output = output.into(); + if output.success() { if let Ok(output) = String::from_utf8(output.stdout) { return RustupRunRustcVersionOutcome::RustcVersion(output); } @@ -212,9 +220,9 @@ fn extract_toolchain_from_rustup_run_rustc_version(output: Output) -> RustupRunR } fn execute_rustc_version() -> Option<String> { - match Command::new("rustc").arg("--version").output() { - Ok(output) => Some(String::from_utf8(output.stdout).unwrap()), - Err(_) => None, + match exec_cmd("rustc", &["--version"], Duration::from_millis(500)) { + Some(output) => Some(output.stdout), + None => None, } } diff --git a/src/utils.rs b/src/utils.rs index 67265c9c8..22b7a952b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,8 +1,10 @@ use process_control::{ChildExt, Timeout}; +use starship_cache::{Cache, CachedOutput}; +use std::convert::TryInto; use std::fmt::Debug; use std::fs::read_to_string; use std::io::Result; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::time::{Duration, Instant}; @@ -35,6 +37,16 @@ impl PartialEq for CommandOutput { } } +impl From<CommandOutput> for CachedOutput { + fn from(output: CommandOutput) -> Self { + Self { + stdout: output.stdout.into_bytes(), + stderr: output.stderr.into_bytes(), + status: Some(0), + } + } +} + /// Execute a command and return the output on stdout and stderr if successful #[cfg(not(test))] pub fn exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<CommandOutput> { @@ -311,6 +323,16 @@ pub fn wrap_seq_for_shell( fn internal_exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<CommandOutput> { log::trace!("Executing command {:?} with args {:?}", cmd, args); + let cache_dir = std::env::var_os("STARSHIP_CACHE") + .map(PathBuf::from) + .unwrap_or_else(|| { + dirs_next::home_dir() + .expect("Unable to find home directory") + .join(".cache/starship") + }); + let mut cache = Cache::new(&cache_dir.join("bin-cache")).ok()?; + log::debug!("Cache initialized: {:?}", &cache_dir); + let full_path = match which::which(cmd) { Ok(full_path) => { log::trace!("Using {:?} as {:?}", full_path, cmd); @@ -324,7 +346,31 @@ fn internal_exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<C let start = Instant::now(); - let process = match Command::new(full_path) + let full_command = format!("{} {}", cmd, args.join(" ")); + if let Some(output) = cache.get(&full_path, &full_command) { + log::info!("Retreived {:?} from cache: {:?}", full_command, output); + + let stdout_string = match String::from_utf8(output.stdout.clone()) { + Ok(stdout) => stdout, + Err(error) => { + log::warn!("Unable to decode stdout: {:?}", error); + return None; + } + }; + let stderr_string = match String::from_utf8(output.stderr.clone()) { + Ok(stderr) => stderr, + Err(error) => { + log::warn!("Unable to decode stderr: {:?}", error); + return None; + } + }; + return Some(CommandOutput { + stdout: stdout_string, + stderr: stderr_string, + }); + } + + let process = match Command::new(&full_path) .args(args) .stderr(Stdio::piped()) .stdout(Stdio::piped()) @@ -340,14 +386,14 @@ fn internal_exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<C match process.with_output_timeout(time_limit).terminating().wait() { Ok(Some(output)) => { - let stdout_string = match String::from_utf8(output.stdout) { + let stdout_string = match String::from_utf8(output.stdout.clone()) { Ok(stdout) => stdout, Err(error) => { log::warn!("Unable to decode stdout: {:?}", error); return None; } }; - let stderr_string = match String::from_utf8(output.stderr) { + let stderr_string = match String::from_utf8(output.stderr.clone()) { Ok(stderr) => stderr, Err(error) => { log::warn!("Unable to decode stderr: {:?}", error); @@ -355,6 +401,22 @@ fn internal_exec_cmd(cmd: &str, args: &[&str], time_limit: Duration) -> Option<C } }; + cache.set( + &full_path, + &full_command, + CachedOutput { + stdout: output.stdout, + stderr: output.stderr, + status: output + .status + .code() + .map(|i| i.try_into().unwrap_or_default()), + }, + ); + cache.write().unwrap_or_else(|e| { + log::warn!("Unable to write to binary cache: {}", e); + }); + log::trace!( "stdout: {:?}, stderr: {:?}, exit code: \"{:?}\", took {:?}", stdout_string, |