summaryrefslogtreecommitdiffstats
path: root/src/modules/rust.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/rust.rs')
-rw-r--r--src/modules/rust.rs291
1 files changed, 0 insertions, 291 deletions
diff --git a/src/modules/rust.rs b/src/modules/rust.rs
deleted file mode 100644
index 31a404791..000000000
--- a/src/modules/rust.rs
+++ /dev/null
@@ -1,291 +0,0 @@
-use ansi_term::Color;
-use std::ffi::OsStr;
-use std::path::Path;
-use std::process::{Command, Output};
-use std::{env, fs};
-
-use super::{Context, Module};
-
-/// Creates a module with the current Rust version
-///
-/// Will display the Rust version if any of the following criteria are met:
-/// - Current directory contains a file with a `.rs` extension
-/// - Current directory contains a `Cargo.toml` file
-pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
- const RUST_CHAR: &str = "🦀 ";
-
- let is_rs_project = context
- .try_begin_scan()?
- .set_files(&["Cargo.toml"])
- .set_extensions(&["rs"])
- .is_match();
-
- if !is_rs_project {
- return None;
- }
-
- // `$CARGO_HOME/bin/rustc(.exe) --version` may attempt installing a rustup toolchain.
- // https://github.com/starship/starship/issues/417
- //
- // To display appropriate versions preventing `rustc` from downloading toolchains, we have to
- // check
- // 1. `$RUSTUP_TOOLCHAIN`
- // 2. `rustup override list`
- // 3. `rust-toolchain` in `.` or parent directories
- // as `rustup` does.
- // https://github.com/rust-lang/rustup.rs/tree/eb694fcada7becc5d9d160bf7c623abe84f8971d#override-precedence
- //
- // Probably we have no other way to know whether any toolchain override is specified for the
- // current directory. The following commands also cause toolchain installations.
- // - `rustup show`
- // - `rustup show active-toolchain`
- // - `rustup which`
- let module_version = if let Some(toolchain) = env_rustup_toolchain()
- .or_else(|| execute_rustup_override_list(&context.current_dir))
- .or_else(|| find_rust_toolchain_file(&context))
- {
- match execute_rustup_run_rustc_version(&toolchain) {
- RustupRunRustcVersionOutcome::RustcVersion(stdout) => format_rustc_version(stdout),
- RustupRunRustcVersionOutcome::ToolchainName(toolchain) => toolchain,
- RustupRunRustcVersionOutcome::RustupNotWorking => {
- // If `rustup` is not in `$PATH` or cannot be executed for other reasons, we can
- // safely execute `rustc --version`.
- format_rustc_version(execute_rustc_version()?)
- }
- RustupRunRustcVersionOutcome::Err => return None,
- }
- } else {
- format_rustc_version(execute_rustc_version()?)
- };
-
- let mut module = context.new_module("rust");
-
- let module_style = module
- .config_value_style("style")
- .unwrap_or_else(|| Color::Red.bold());
- module.set_style(module_style);
- module.new_segment("symbol", RUST_CHAR);
- module.new_segment("version", &module_version);
-
- Some(module)
-}
-
-fn env_rustup_toolchain() -> Option<String> {
- let val = env::var("RUSTUP_TOOLCHAIN").ok()?;
- Some(val.trim().to_owned())
-}
-
-fn execute_rustup_override_list(cwd: &Path) -> Option<String> {
- let Output { stdout, .. } = Command::new("rustup")
- .args(&["override", "list"])
- .output()
- .ok()?;
- let stdout = String::from_utf8(stdout).ok()?;
- extract_toolchain_from_rustup_override_list(&stdout, cwd)
-}
-
-fn extract_toolchain_from_rustup_override_list(stdout: &str, cwd: &Path) -> Option<String> {
- if stdout == "no overrides\n" {
- return None;
- }
- stdout
- .lines()
- .flat_map(|line| {
- let mut words = line.split_whitespace();
- let dir = words.next()?;
- let toolchain = words.next()?;
- Some((dir, toolchain))
- })
- .find(|(dir, _)| cwd.starts_with(dir))
- .map(|(_, toolchain)| toolchain.to_owned())
-}
-
-fn find_rust_toolchain_file(context: &Context) -> Option<String> {
- // Look for 'rust-toolchain' as rustup does.
- // https://github.com/rust-lang/rustup.rs/blob/d84e6e50126bccd84649e42482fc35a11d019401/src/config.rs#L320-L358
-
- fn read_first_line(path: &Path) -> Option<String> {
- let content = fs::read_to_string(path).ok()?;
- let line = content.lines().next()?;
- Some(line.trim().to_owned())
- }
-
- if let Some(path) = context
- .get_dir_files()
- .ok()?
- .iter()
- .find(|p| p.file_name() == Some(OsStr::new("rust-toolchain")))
- {
- if let Some(toolchain) = read_first_line(path) {
- return Some(toolchain);
- }
- }
-
- let mut dir = &*context.current_dir;
- loop {
- if let Some(toolchain) = read_first_line(&dir.join("rust-toolchain")) {
- return Some(toolchain);
- }
- dir = dir.parent()?;
- }
-}
-
-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)
-}
-
-fn extract_toolchain_from_rustup_run_rustc_version(output: Output) -> RustupRunRustcVersionOutcome {
- if output.status.success() {
- if let Ok(output) = String::from_utf8(output.stdout) {
- return RustupRunRustcVersionOutcome::RustcVersion(output);
- }
- } else if let Ok(stderr) = String::from_utf8(output.stderr) {
- if stderr.starts_with("error: toolchain '") && stderr.ends_with("' is not installed\n") {
- let stderr = stderr
- ["error: toolchain '".len()..stderr.len() - "' is not installed\n".len()]
- .to_owned();
- return RustupRunRustcVersionOutcome::ToolchainName(stderr);
- }
- }
- RustupRunRustcVersionOutcome::Err
-}
-
-fn execute_rustc_version() -> Option<String> {
- match Command::new("rustc").arg("--version").output() {
- Ok(output) => Some(String::from_utf8(output.stdout).unwrap()),
- Err(_) => None,
- }
-}
-
-fn format_rustc_version(mut rustc_stdout: String) -> String {
- let offset = &rustc_stdout.find('(').unwrap_or_else(|| rustc_stdout.len());
- let formatted_version: String = rustc_stdout.drain(..offset).collect();
-
- format!("v{}", formatted_version.replace("rustc", "").trim())
-}
-
-#[derive(Debug, PartialEq)]
-enum RustupRunRustcVersionOutcome {
- RustcVersion(String),
- ToolchainName(String),
- RustupNotWorking,
- Err,
-}
-
-#[cfg(test)]
-mod tests {
- use once_cell::sync::Lazy;
- use std::process::{ExitStatus, Output};
-
- use super::*;
-
- #[test]
- fn test_extract_toolchain_from_rustup_override_list() {
- static NO_OVERRIDES_INPUT: &str = "no overrides\n";
- static NO_OVERRIDES_CWD: &str = "";
- assert_eq!(
- extract_toolchain_from_rustup_override_list(
- NO_OVERRIDES_INPUT,
- NO_OVERRIDES_CWD.as_ref(),
- ),
- None,
- );
-
- static OVERRIDES_INPUT: &str =
- "/home/user/src/a beta-x86_64-unknown-linux-gnu\n\
- /home/user/src/b nightly-x86_64-unknown-linux-gnu\n";
- static OVERRIDES_CWD_A: &str = "/home/user/src/a/src";
- static OVERRIDES_CWD_B: &str = "/home/user/src/b/tests";
- static OVERRIDES_CWD_C: &str = "/home/user/src/c/examples";
- assert_eq!(
- extract_toolchain_from_rustup_override_list(OVERRIDES_INPUT, OVERRIDES_CWD_A.as_ref()),
- Some("beta-x86_64-unknown-linux-gnu".to_owned()),
- );
- assert_eq!(
- extract_toolchain_from_rustup_override_list(OVERRIDES_INPUT, OVERRIDES_CWD_B.as_ref()),
- Some("nightly-x86_64-unknown-linux-gnu".to_owned()),
- );
- assert_eq!(
- extract_toolchain_from_rustup_override_list(OVERRIDES_INPUT, OVERRIDES_CWD_C.as_ref()),
- None,
- );
- }
-
- #[cfg(any(unix, windows))]
- #[test]
- fn test_extract_toolchain_from_rustup_run_rustc_version() {
- #[cfg(unix)]
- use std::os::unix::process::ExitStatusExt as _;
- #[cfg(windows)]
- use std::os::windows::process::ExitStatusExt as _;
-
- static RUSTC_VERSION: Lazy<Output> = Lazy::new(|| Output {
- status: ExitStatus::from_raw(0),
- stdout: b"rustc 1.34.0\n"[..].to_owned(),
- stderr: vec![],
- });
- assert_eq!(
- extract_toolchain_from_rustup_run_rustc_version(RUSTC_VERSION.clone()),
- RustupRunRustcVersionOutcome::RustcVersion("rustc 1.34.0\n".to_owned()),
- );
-
- static TOOLCHAIN_NAME: Lazy<Output> = Lazy::new(|| Output {
- status: ExitStatus::from_raw(1),
- stdout: vec![],
- stderr: b"error: toolchain 'channel-triple' is not installed\n"[..].to_owned(),
- });
- assert_eq!(
- extract_toolchain_from_rustup_run_rustc_version(TOOLCHAIN_NAME.clone()),
- RustupRunRustcVersionOutcome::ToolchainName("channel-triple".to_owned()),
- );
-
- static INVALID_STDOUT: Lazy<Output> = Lazy::new(|| Output {
- status: ExitStatus::from_raw(0),
- stdout: b"\xc3\x28"[..].to_owned(),
- stderr: vec![],
- });
- assert_eq!(
- extract_toolchain_from_rustup_run_rustc_version(INVALID_STDOUT.clone()),
- RustupRunRustcVersionOutcome::Err,
- );
-
- static INVALID_STDERR: Lazy<Output> = Lazy::new(|| Output {
- status: ExitStatus::from_raw(1),
- stdout: vec![],
- stderr: b"\xc3\x28"[..].to_owned(),
- });
- assert_eq!(
- extract_toolchain_from_rustup_run_rustc_version(INVALID_STDERR.clone()),
- RustupRunRustcVersionOutcome::Err,
- );
-
- static UNEXPECTED_FORMAT_OF_ERROR: Lazy<Output> = Lazy::new(|| Output {
- status: ExitStatus::from_raw(1),
- stdout: vec![],
- stderr: b"error:"[..].to_owned(),
- });
- assert_eq!(
- extract_toolchain_from_rustup_run_rustc_version(UNEXPECTED_FORMAT_OF_ERROR.clone()),
- RustupRunRustcVersionOutcome::Err,
- );
- }
-
- #[test]
- fn test_format_rustc_version() {
- let nightly_input = String::from("rustc 1.34.0-nightly (b139669f3 2019-04-10)");
- assert_eq!(format_rustc_version(nightly_input), "v1.34.0-nightly");
-
- let beta_input = String::from("rustc 1.34.0-beta.1 (2bc1d406d 2019-04-10)");
- assert_eq!(format_rustc_version(beta_input), "v1.34.0-beta.1");
-
- let stable_input = String::from("rustc 1.34.0 (91856ed52 2019-04-10)");
- assert_eq!(format_rustc_version(stable_input), "v1.34.0");
-
- let version_without_hash = String::from("rustc 1.34.0");
- assert_eq!(format_rustc_version(version_without_hash), "v1.34.0");
- }
-}