From ecff5dc141046c5b9e40639657247a05fb9b0344 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 8 May 2020 14:54:29 +0200 Subject: Cleanup --- crates/ra_toolchain/src/lib.rs | 69 ++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 37 deletions(-) (limited to 'crates/ra_toolchain/src') diff --git a/crates/ra_toolchain/src/lib.rs b/crates/ra_toolchain/src/lib.rs index afa76619d..3c307a0ea 100644 --- a/crates/ra_toolchain/src/lib.rs +++ b/crates/ra_toolchain/src/lib.rs @@ -1,21 +1,26 @@ //! This crate contains a single public function //! [`get_path_for_executable`](fn.get_path_for_executable.html). //! See docs there for more information. -use std::{ - env, - path::{Path, PathBuf}, - process::Command, -}; +use std::{env, iter, path::PathBuf}; -use anyhow::{bail, Result}; +pub fn cargo() -> PathBuf { + get_path_for_executable("cargo") +} + +pub fn rustc() -> PathBuf { + get_path_for_executable("rustc") +} + +pub fn rustup() -> PathBuf { + get_path_for_executable("rustup") +} /// Return a `PathBuf` to use for the given executable. /// /// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that /// gives a valid Cargo executable; or it may return a full path to a valid /// Cargo. -pub fn get_path_for_executable(executable_name: &'static str) -> Result { - assert!(executable_name == "rustc" || executable_name == "cargo"); +fn get_path_for_executable(executable_name: &'static str) -> PathBuf { // The current implementation checks three places for an executable to use: // 1) Appropriate environment variable (erroring if this is set but not a usable executable) // example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc @@ -25,45 +30,35 @@ pub fn get_path_for_executable(executable_name: &'static str) -> Result // example: for cargo, this tries ~/.cargo/bin/cargo // It seems that this is a reasonable place to try for cargo, rustc, and rustup let env_var = executable_name.to_ascii_uppercase(); - if let Ok(path) = env::var(&env_var) { - return if is_valid_executable(&path) { - Ok(path.into()) - } else { - bail!( - "`{}` environment variable points to something that's not a valid executable", - env_var - ) - }; + if let Some(path) = env::var_os(&env_var) { + return path.into(); } - if is_valid_executable(executable_name) { - return Ok(executable_name.into()); + if lookup_in_path(executable_name) { + return executable_name.into(); } if let Some(mut path) = home::home_dir() { path.push(".cargo"); path.push("bin"); path.push(executable_name); - if is_valid_executable(&path) { - return Ok(path); + if path.is_file() { + return path; } } - // This error message may also be caused by $PATH or $CARGO/$RUSTC/etc not being set correctly - // for VSCode, even if they are set correctly in a terminal. - // On macOS in particular, launching VSCode from terminal with `code ` causes VSCode - // to inherit environment variables including $PATH, $CARGO, $RUSTC, etc from that terminal; - // but launching VSCode from Dock does not inherit environment variables from a terminal. - // For more discussion, see #3118. - bail!( - "Failed to find `{}` executable. Make sure `{}` is in `$PATH`, or set `${}` to point to a valid executable.", - executable_name, executable_name, env_var - ) + executable_name.into() } -/// Does the given `Path` point to a usable executable? -/// -/// (assumes the executable takes a `--version` switch and writes to stdout, -/// which is true for `cargo`, `rustc`, and `rustup`) -fn is_valid_executable(p: &'static str) -> bool { - Command::new(p).arg("--version").output().is_ok() +fn lookup_in_path(exec: &str) -> bool { + let paths = env::var_os("PATH").unwrap_or_default(); + let mut candidates = env::split_paths(&paths).flat_map(|path| { + let candidate = path.join(&exec); + let with_exe = if env::consts::EXE_EXTENSION == "" { + None + } else { + Some(candidate.with_extension(env::consts::EXE_EXTENSION)) + }; + iter::once(candidate).chain(with_exe) + }); + candidates.any(|it| it.is_file()) } -- cgit v1.2.3