For toolchain binaries ue the full path found in $PATH

This commit is contained in:
Lukas Wirth 2024-03-05 10:16:30 +01:00
parent fe0daa7be3
commit c310aee8d6
7 changed files with 63 additions and 67 deletions

1
Cargo.lock generated
View file

@ -1336,7 +1336,6 @@ name = "proc-macro-test"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"cargo_metadata", "cargo_metadata",
"toolchain",
] ]
[[package]] [[package]]

View file

@ -189,7 +189,7 @@ fn _format(
let &crate_id = db.relevant_crates(file_id).iter().next()?; let &crate_id = db.relevant_crates(file_id).iter().next()?;
let edition = db.crate_graph()[crate_id].edition; let edition = db.crate_graph()[crate_id].edition;
let mut cmd = std::process::Command::new(toolchain::rustfmt()); let mut cmd = std::process::Command::new(toolchain::Tool::Rustfmt.path());
cmd.arg("--edition"); cmd.arg("--edition");
cmd.arg(edition.to_string()); cmd.arg(edition.to_string());

View file

@ -11,6 +11,3 @@ doctest = false
[build-dependencies] [build-dependencies]
cargo_metadata = "0.18.1" cargo_metadata = "0.18.1"
# local deps
toolchain.workspace = true

View file

@ -18,12 +18,12 @@ use cargo_metadata::Message;
fn main() { fn main() {
println!("cargo:rerun-if-changed=imp"); println!("cargo:rerun-if-changed=imp");
let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
let has_features = env::var_os("RUSTC_BOOTSTRAP").is_some() let has_features = env::var_os("RUSTC_BOOTSTRAP").is_some()
|| String::from_utf8( || String::from_utf8(Command::new(&cargo).arg("--version").output().unwrap().stdout)
Command::new(toolchain::cargo()).arg("--version").output().unwrap().stdout, .unwrap()
) .contains("nightly");
.unwrap()
.contains("nightly");
let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = env::var_os("OUT_DIR").unwrap();
let out_dir = Path::new(&out_dir); let out_dir = Path::new(&out_dir);
@ -66,7 +66,7 @@ fn main() {
let target_dir = out_dir.join("target"); let target_dir = out_dir.join("target");
let mut cmd = Command::new(toolchain::cargo()); let mut cmd = Command::new(&cargo);
cmd.current_dir(&staging_dir) cmd.current_dir(&staging_dir)
.args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"]) .args(["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
// Explicit override the target directory to avoid using the same one which the parent // Explicit override the target directory to avoid using the same one which the parent
@ -96,7 +96,7 @@ fn main() {
let repr = format!("{name} {version}"); let repr = format!("{name} {version}");
// New Package Id Spec since rust-lang/cargo#13311 // New Package Id Spec since rust-lang/cargo#13311
let pkgid = String::from_utf8( let pkgid = String::from_utf8(
Command::new(toolchain::cargo()) Command::new(cargo)
.current_dir(&staging_dir) .current_dir(&staging_dir)
.args(["pkgid", name]) .args(["pkgid", name])
.output() .output()

View file

@ -12,7 +12,7 @@ use itertools::Itertools;
use la_arena::{Arena, Idx}; use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf}; use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use toolchain::probe_for_binary; use toolchain::{probe_for_binary, Tool};
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath}; use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
@ -411,7 +411,7 @@ fn discover_sysroot_dir(
current_dir: &AbsPath, current_dir: &AbsPath,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
) -> Result<AbsPathBuf> { ) -> Result<AbsPathBuf> {
let mut rustc = Command::new(toolchain::rustc()); let mut rustc = Command::new(Tool::Rustc.path());
rustc.envs(extra_env); rustc.envs(extra_env);
rustc.current_dir(current_dir).args(["--print", "sysroot"]); rustc.current_dir(current_dir).args(["--print", "sysroot"]);
tracing::debug!("Discovering sysroot by {:?}", rustc); tracing::debug!("Discovering sysroot by {:?}", rustc);
@ -443,7 +443,7 @@ fn discover_sysroot_src_dir_or_add_component(
) -> Result<AbsPathBuf> { ) -> Result<AbsPathBuf> {
discover_sysroot_src_dir(sysroot_path) discover_sysroot_src_dir(sysroot_path)
.or_else(|| { .or_else(|| {
let mut rustup = Command::new(toolchain::rustup()); let mut rustup = Command::new(Tool::Rustup.prefer_proxy());
rustup.envs(extra_env); rustup.envs(extra_env);
rustup.current_dir(current_dir).args(["component", "add", "rust-src"]); rustup.current_dir(current_dir).args(["component", "add", "rust-src"]);
tracing::info!("adding rust-src component by {:?}", rustup); tracing::info!("adding rust-src component by {:?}", rustup);

View file

@ -1937,7 +1937,7 @@ fn run_rustfmt(
let mut command = match snap.config.rustfmt() { let mut command = match snap.config.rustfmt() {
RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
// FIXME: Set RUSTUP_TOOLCHAIN // FIXME: Set RUSTUP_TOOLCHAIN
let mut cmd = process::Command::new(toolchain::rustfmt()); let mut cmd = process::Command::new(toolchain::Tool::Rustfmt.path());
cmd.envs(snap.config.extra_env()); cmd.envs(snap.config.extra_env());
cmd.args(extra_args); cmd.args(extra_args);

View file

@ -16,8 +16,42 @@ pub enum Tool {
} }
impl 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 { 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> { pub fn path_in(self, path: &Path) -> Option<PathBuf> {
@ -38,60 +72,21 @@ impl Tool {
} }
} }
pub fn cargo() -> PathBuf { fn invoke(list: &[fn(&str) -> Option<PathBuf>], executable: &str) -> PathBuf {
get_path_for_executable("cargo") list.iter().find_map(|it| it(executable)).unwrap_or_else(|| executable.into())
} }
pub fn rustc() -> PathBuf { /// Looks up the binary as its SCREAMING upper case in the env variables.
get_path_for_executable("rustc") 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 { /// Looks up the binary in the cargo home directory if it exists.
get_path_for_executable("rustup") fn cargo_proxy(executable_name: &str) -> Option<PathBuf> {
} let mut path = get_cargo_home()?;
path.push("bin");
pub fn rustfmt() -> PathBuf { path.push(executable_name);
get_path_for_executable("rustfmt") probe_for_binary(path)
}
/// 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) `<executable_name>`
// example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH
// 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
let env_var = executable_name.to_ascii_uppercase();
if let Some(path) = env::var_os(env_var) {
return path.into();
}
if lookup_in_path(executable_name) {
return executable_name.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;
}
}
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()
} }
fn get_cargo_home() -> Option<PathBuf> { fn get_cargo_home() -> Option<PathBuf> {
@ -107,6 +102,11 @@ fn get_cargo_home() -> Option<PathBuf> {
None 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> { pub fn probe_for_binary(path: PathBuf) -> Option<PathBuf> {
let with_extension = match env::consts::EXE_EXTENSION { let with_extension = match env::consts::EXE_EXTENSION {
"" => None, "" => None,