Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/toolchain/src/lib.rs')
| -rw-r--r-- | crates/toolchain/src/lib.rs | 106 |
1 files changed, 51 insertions, 55 deletions
diff --git a/crates/toolchain/src/lib.rs b/crates/toolchain/src/lib.rs index 793138588a..a77fed585a 100644 --- a/crates/toolchain/src/lib.rs +++ b/crates/toolchain/src/lib.rs @@ -16,18 +16,48 @@ pub enum Tool { } impl Tool { + pub fn proxy(self) -> Option<PathBuf> { + cargo_proxy(self.name()) + } + + /// Return a `PathBuf` to use for the given executable. + /// + /// The current implementation checks three places for an executable to use: + /// 1) `$CARGO_HOME/bin/<executable_name>` + /// where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html) + /// example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset. + /// It seems that this is a reasonable place to try for cargo, rustc, and rustup + /// 2) 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 + /// 3) $PATH/`<executable_name>` + /// example: for cargo, this tries all paths in $PATH with appended `cargo`, returning the + /// first that exists + /// 4) If all else fails, we just try to use the executable name directly + pub fn prefer_proxy(self) -> PathBuf { + invoke(&[cargo_proxy, lookup_as_env_var, lookup_in_path], self.name()) + } + + /// Return a `PathBuf` to use for the given executable. + /// + /// 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 + /// 2) $PATH/`<executable_name>` + /// example: for cargo, this tries all paths in $PATH with appended `cargo`, returning the + /// first that exists + /// 3) `$CARGO_HOME/bin/<executable_name>` + /// where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html) + /// example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset. + /// It seems that this is a reasonable place to try for cargo, rustc, and rustup + /// 4) If all else fails, we just try to use the executable name directly pub fn path(self) -> PathBuf { - get_path_for_executable(self.name()) + invoke(&[lookup_as_env_var, lookup_in_path, cargo_proxy], self.name()) } pub fn path_in(self, path: &Path) -> Option<PathBuf> { probe_for_binary(path.join(self.name())) } - pub fn path_in_or_discover(self, path: &Path) -> PathBuf { - probe_for_binary(path.join(self.name())).unwrap_or_else(|| self.path()) - } - pub fn name(self) -> &'static str { match self { Tool::Cargo => "cargo", @@ -38,60 +68,21 @@ impl Tool { } } -pub fn cargo() -> PathBuf { - get_path_for_executable("cargo") +fn invoke(list: &[fn(&str) -> Option<PathBuf>], executable: &str) -> PathBuf { + list.iter().find_map(|it| it(executable)).unwrap_or_else(|| executable.into()) } -pub fn rustc() -> PathBuf { - get_path_for_executable("rustc") +/// Looks up the binary as its SCREAMING upper case in the env variables. +fn lookup_as_env_var(executable_name: &str) -> Option<PathBuf> { + env::var_os(executable_name.to_ascii_uppercase()).map(Into::into) } -pub fn rustup() -> PathBuf { - get_path_for_executable("rustup") -} - -pub fn rustfmt() -> PathBuf { - get_path_for_executable("rustfmt") -} - -/// 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. -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 - // 2) `$CARGO_HOME/bin/<executable_name>` - // where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html) - // example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset. - // It seems that this is a reasonable place to try for cargo, rustc, and rustup - // 3) `<executable_name>` - // example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH - let env_var = executable_name.to_ascii_uppercase(); - if let Some(path) = env::var_os(env_var) { - return path.into(); - } - - if let Some(mut path) = get_cargo_home() { - path.push("bin"); - path.push(executable_name); - if let Some(path) = probe_for_binary(path) { - return path; - } - } - - if lookup_in_path(executable_name) { - return executable_name.into(); - } - - executable_name.into() -} - -fn lookup_in_path(exec: &str) -> bool { - let paths = env::var_os("PATH").unwrap_or_default(); - env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe_for_binary).is_some() +/// Looks up the binary in the cargo home directory if it exists. +fn cargo_proxy(executable_name: &str) -> Option<PathBuf> { + let mut path = get_cargo_home()?; + path.push("bin"); + path.push(executable_name); + probe_for_binary(path) } fn get_cargo_home() -> Option<PathBuf> { @@ -107,6 +98,11 @@ fn get_cargo_home() -> Option<PathBuf> { None } +fn lookup_in_path(exec: &str) -> Option<PathBuf> { + let paths = env::var_os("PATH").unwrap_or_default(); + env::split_paths(&paths).map(|path| path.join(exec)).find_map(probe_for_binary) +} + pub fn probe_for_binary(path: PathBuf) -> Option<PathBuf> { let with_extension = match env::consts::EXE_EXTENSION { "" => None, |