diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs index c2271ce64ee2..8167f7301a8d 100644 --- a/crates/project-model/src/lib.rs +++ b/crates/project-model/src/lib.rs @@ -20,6 +20,7 @@ pub mod toolchain_info { pub mod rustc_cfg; pub mod target_data_layout; pub mod target_tuple; + pub mod version; use std::path::Path; diff --git a/crates/project-model/src/toolchain_info/rustc_cfg.rs b/crates/project-model/src/toolchain_info/rustc_cfg.rs index b1e8c3376a16..a37731225283 100644 --- a/crates/project-model/src/toolchain_info/rustc_cfg.rs +++ b/crates/project-model/src/toolchain_info/rustc_cfg.rs @@ -68,10 +68,10 @@ fn rustc_print_cfg( cmd.envs(extra_env); cmd.env("RUSTC_BOOTSTRAP", "1"); cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS); - cmd.args(["--", "-O"]); if let Some(target) = target { cmd.args(["--target", target]); } + cmd.args(["--", "-O"]); match utf8_stdout(&mut cmd) { Ok(it) => return Ok(it), diff --git a/crates/project-model/src/toolchain_info/version.rs b/crates/project-model/src/toolchain_info/version.rs new file mode 100644 index 000000000000..a873944dd8a8 --- /dev/null +++ b/crates/project-model/src/toolchain_info/version.rs @@ -0,0 +1,32 @@ +//! Get the version string of the toolchain. + +use anyhow::Context; +use rustc_hash::FxHashMap; +use semver::Version; +use toolchain::Tool; + +use crate::{toolchain_info::QueryConfig, utf8_stdout}; + +pub(crate) fn get( + config: QueryConfig<'_>, + extra_env: &FxHashMap, +) -> Result, anyhow::Error> { + let (mut cmd, prefix) = match config { + QueryConfig::Cargo(sysroot, cargo_toml) => { + (sysroot.tool(Tool::Cargo, cargo_toml.parent()), "cargo ") + } + QueryConfig::Rustc(sysroot, current_dir) => { + (sysroot.tool(Tool::Rustc, current_dir), "rustc ") + } + }; + cmd.envs(extra_env); + cmd.arg("--version"); + let out = utf8_stdout(&mut cmd).with_context(|| format!("Failed to query rust toolchain version via `{cmd:?}`, is your toolchain setup correctly?"))?; + + let version = + out.strip_prefix(prefix).and_then(|it| Version::parse(it.split_whitespace().next()?).ok()); + if version.is_none() { + tracing::warn!("Failed to parse `{cmd:?}` output `{out}` as a semver version"); + } + anyhow::Ok(version) +} diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 2caf0a536b64..36e2a6107e52 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -26,7 +26,7 @@ use crate::{ env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env}, project_json::{Crate, CrateArrayIdx}, sysroot::{SysrootCrate, SysrootMode}, - toolchain_info::{rustc_cfg, target_data_layout, target_tuple, QueryConfig}, + toolchain_info::{rustc_cfg, target_data_layout, target_tuple, version, QueryConfig}, utf8_stdout, CargoConfig, CargoWorkspace, CfgOverrides, InvocationStrategy, ManifestPath, Package, ProjectJson, ProjectManifest, Sysroot, TargetData, TargetKind, WorkspaceBuildScripts, }; @@ -150,27 +150,6 @@ impl fmt::Debug for ProjectWorkspace { } } -fn get_toolchain_version( - current_dir: &AbsPath, - sysroot: &Sysroot, - tool: Tool, - extra_env: &FxHashMap, - prefix: &str, -) -> Result, anyhow::Error> { - let cargo_version = utf8_stdout(&mut { - let mut cmd = Sysroot::tool(sysroot, tool, current_dir); - cmd.envs(extra_env); - cmd.arg("--version"); - cmd - }) - .with_context(|| format!("Failed to query rust toolchain version at {current_dir}, is your toolchain setup correctly?"))?; - anyhow::Ok( - cargo_version - .get(prefix.len()..) - .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()), - ) -} - impl ProjectWorkspace { pub fn load( manifest: ProjectManifest, @@ -249,12 +228,10 @@ impl ProjectWorkspace { .ok_or_else(|| Some("Failed to discover rustc source for sysroot.".to_owned())), None => Err(None), }; - let targets = target_tuple::get( - QueryConfig::Cargo(&sysroot, cargo_toml), - config.target.as_deref(), - &config.extra_env, - ) - .unwrap_or_default(); + let toolchain_config = QueryConfig::Cargo(&sysroot, cargo_toml); + let targets = + target_tuple::get(toolchain_config, config.target.as_deref(), &config.extra_env) + .unwrap_or_default(); let rustc = rustc_dir.and_then(|rustc_dir| { info!(workspace = %cargo_toml, rustc_dir = %rustc_dir, "Using rustc source"); match CargoWorkspace::fetch_metadata( @@ -291,21 +268,19 @@ impl ProjectWorkspace { } } }); - let toolchain = get_toolchain_version( - cargo_toml.parent(), - &sysroot, - Tool::Cargo, - &config.extra_env, - "cargo ", - )?; - let rustc_cfg = rustc_cfg::get( - QueryConfig::Cargo(&sysroot, cargo_toml), - targets.first().map(Deref::deref), - &config.extra_env, - ); + let toolchain = version::get(toolchain_config, &config.extra_env) + .inspect_err(|e| { + tracing::error!(%e, + "failed fetching toolchain version for {cargo_toml:?} workspace" + ) + }) + .ok() + .flatten(); + let rustc_cfg = + rustc_cfg::get(toolchain_config, targets.first().map(Deref::deref), &config.extra_env); let cfg_overrides = config.cfg_overrides.clone(); let data_layout = target_data_layout::get( - QueryConfig::Cargo(&sysroot, cargo_toml), + toolchain_config, targets.first().map(Deref::deref), &config.extra_env, ); @@ -355,19 +330,7 @@ impl ProjectWorkspace { &config.sysroot_query_metadata, ); let query_config = QueryConfig::Rustc(&sysroot, project_json.path().as_ref()); - let toolchain = match get_toolchain_version( - project_json.path(), - &sysroot, - Tool::Rustc, - &config.extra_env, - "rustc ", - ) { - Ok(it) => it, - Err(e) => { - tracing::error!("{e}"); - None - } - }; + let toolchain = version::get(query_config, &config.extra_env).ok().flatten(); let target = config.target.as_deref(); let rustc_cfg = rustc_cfg::get(query_config, target, &config.extra_env); @@ -397,22 +360,10 @@ impl ProjectWorkspace { None => Sysroot::empty(), }; - let toolchain = - match get_toolchain_version(dir, &sysroot, Tool::Rustc, &config.extra_env, "rustc ") { - Ok(it) => it, - Err(e) => { - tracing::error!("{e}"); - None - } - }; - - let targets = target_tuple::get( - QueryConfig::Cargo(&sysroot, detached_file), - config.target.as_deref(), - &config.extra_env, - ) - .unwrap_or_default(); - let query_config = QueryConfig::Rustc(&sysroot, dir.as_ref()); + let query_config = QueryConfig::Cargo(&sysroot, detached_file); + let toolchain = version::get(query_config, &config.extra_env).ok().flatten(); + let targets = target_tuple::get(query_config, config.target.as_deref(), &config.extra_env) + .unwrap_or_default(); let rustc_cfg = rustc_cfg::get(query_config, None, &config.extra_env); let data_layout = target_data_layout::get(query_config, None, &config.extra_env);