summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/modules/rust.rs28
-rw-r--r--src/utils.rs70
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,