diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs index c50e63dfe556..3e52dbaea654 100644 --- a/crates/load-cargo/src/lib.rs +++ b/crates/load-cargo/src/lib.rs @@ -66,7 +66,7 @@ pub fn load_workspace_at( pub fn load_workspace( ws: ProjectWorkspace, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, load_config: &LoadCargoConfig, ) -> anyhow::Result<(RootDatabase, vfs::Vfs, Option)> { let (sender, receiver) = unbounded(); diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index d67d6058d50a..25c30b6db4a4 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -105,10 +105,11 @@ impl fmt::Display for ServerError { impl ProcMacroClient { /// Spawns an external process as the proc macro server and returns a client connected to it. - pub fn spawn( + pub fn spawn<'a>( process_path: &AbsPath, - env: impl IntoIterator, impl AsRef)> - + Clone, + env: impl IntoIterator< + Item = (impl AsRef, &'a Option>), + > + Clone, ) -> io::Result { let process = ProcMacroServerProcess::run(process_path, env)?; Ok(ProcMacroClient { process: Arc::new(process), path: process_path.to_owned() }) diff --git a/crates/proc-macro-api/src/process.rs b/crates/proc-macro-api/src/process.rs index 27bf751bde81..fcea75ef672a 100644 --- a/crates/proc-macro-api/src/process.rs +++ b/crates/proc-macro-api/src/process.rs @@ -43,10 +43,11 @@ struct ProcessSrvState { impl ProcMacroServerProcess { /// Starts the proc-macro server and performs a version check - pub(crate) fn run( + pub(crate) fn run<'a>( process_path: &AbsPath, - env: impl IntoIterator, impl AsRef)> - + Clone, + env: impl IntoIterator< + Item = (impl AsRef, &'a Option>), + > + Clone, ) -> io::Result { let create_srv = || { let mut process = Process::run(process_path, env.clone())?; @@ -193,9 +194,11 @@ struct Process { impl Process { /// Runs a new proc-macro server process with the specified environment variables. - fn run( + fn run<'a>( path: &AbsPath, - env: impl IntoIterator, impl AsRef)>, + env: impl IntoIterator< + Item = (impl AsRef, &'a Option>), + >, ) -> io::Result { let child = JodChild(mk_child(path, env)?); Ok(Process { child }) @@ -212,14 +215,21 @@ impl Process { } /// Creates and configures a new child process for the proc-macro server. -fn mk_child( +fn mk_child<'a>( path: &AbsPath, - env: impl IntoIterator, impl AsRef)>, + extra_env: impl IntoIterator< + Item = (impl AsRef, &'a Option>), + >, ) -> io::Result { #[allow(clippy::disallowed_methods)] let mut cmd = Command::new(path); - cmd.envs(env) - .env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") + for env in extra_env { + match env { + (key, Some(val)) => cmd.env(key, val), + (key, None) => cmd.env_remove(key), + }; + } + cmd.env("RUST_ANALYZER_INTERNALS_DO_NOT_USE", "this is unstable") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::inherit()); diff --git a/crates/project-model/src/build_dependencies.rs b/crates/project-model/src/build_dependencies.rs index b26d19e32689..e0c38ccf3331 100644 --- a/crates/project-model/src/build_dependencies.rs +++ b/crates/project-model/src/build_dependencies.rs @@ -163,7 +163,7 @@ impl WorkspaceBuildScripts { pub(crate) fn rustc_crates( rustc: &CargoWorkspace, current_dir: &AbsPath, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, sysroot: &Sysroot, ) -> Self { let mut bs = WorkspaceBuildScripts::default(); @@ -172,16 +172,14 @@ impl WorkspaceBuildScripts { } let res = (|| { let target_libdir = (|| { - let mut cargo_config = sysroot.tool(Tool::Cargo, current_dir); - cargo_config.envs(extra_env); + let mut cargo_config = sysroot.tool(Tool::Cargo, current_dir, extra_env); cargo_config .args(["rustc", "-Z", "unstable-options", "--print", "target-libdir"]) .env("RUSTC_BOOTSTRAP", "1"); if let Ok(it) = utf8_stdout(&mut cargo_config) { return Ok(it); } - let mut cmd = sysroot.tool(Tool::Rustc, current_dir); - cmd.envs(extra_env); + let mut cmd = sysroot.tool(Tool::Rustc, current_dir, extra_env); cmd.args(["--print", "target-libdir"]); utf8_stdout(&mut cmd) })()?; @@ -390,12 +388,12 @@ impl WorkspaceBuildScripts { ) -> io::Result { let mut cmd = match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { - let mut cmd = toolchain::command(program, current_dir); + let mut cmd = toolchain::command(program, current_dir, &config.extra_env); cmd.args(args); cmd } _ => { - let mut cmd = sysroot.tool(Tool::Cargo, current_dir); + let mut cmd = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env); cmd.args(["check", "--quiet", "--workspace", "--message-format=json"]); cmd.args(&config.extra_args); @@ -448,7 +446,6 @@ impl WorkspaceBuildScripts { } }; - cmd.envs(&config.extra_env); if config.wrap_rustc_in_build_scripts { // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use // that to compile only proc macros and build scripts during the initial diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index d304c9762cb2..6e730b1aea26 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -104,7 +104,7 @@ pub struct CargoConfig { /// Extra args to pass to the cargo command. pub extra_args: Vec, /// Extra env vars to set when invoking the cargo command - pub extra_env: FxHashMap, + pub extra_env: FxHashMap>, pub invocation_strategy: InvocationStrategy, /// Optional path to use instead of `target` when building pub target_dir: Option, @@ -289,7 +289,7 @@ pub struct CargoMetadataConfig { /// Extra args to pass to the cargo command. pub extra_args: Vec, /// Extra env vars to set when invoking the cargo command - pub extra_env: FxHashMap, + pub extra_env: FxHashMap>, } // Deserialize helper for the cargo metadata @@ -343,11 +343,10 @@ impl CargoWorkspace { locked: bool, progress: &dyn Fn(String), ) -> anyhow::Result<(cargo_metadata::Metadata, Option)> { - let cargo = sysroot.tool(Tool::Cargo, current_dir); + let cargo = sysroot.tool(Tool::Cargo, current_dir, &config.extra_env); let mut meta = MetadataCommand::new(); meta.cargo_path(cargo.get_program()); cargo.get_envs().for_each(|(var, val)| _ = meta.env(var, val.unwrap_or_default())); - config.extra_env.iter().for_each(|(var, val)| _ = meta.env(var, val)); meta.manifest_path(cargo_toml.to_path_buf()); match &config.features { CargoFeatures::All => { diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs index 08d51c0d0888..f2e5df171ae3 100644 --- a/crates/project-model/src/env.rs +++ b/crates/project-model/src/env.rs @@ -62,11 +62,10 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe pub(crate) fn cargo_config_env( manifest: &ManifestPath, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, sysroot: &Sysroot, ) -> Env { - let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent()); - cargo_config.envs(extra_env); + let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env); cargo_config .args(["-Z", "unstable-options", "config", "get", "env"]) .env("RUSTC_BOOTSTRAP", "1"); diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index 6ed030a4c3aa..c7c1b0431867 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -86,7 +86,7 @@ impl Sysroot { impl Sysroot { /// Attempts to discover the toolchain's sysroot from the given `dir`. - pub fn discover(dir: &AbsPath, extra_env: &FxHashMap) -> Sysroot { + pub fn discover(dir: &AbsPath, extra_env: &FxHashMap>) -> Sysroot { let sysroot_dir = discover_sysroot_dir(dir, extra_env); let rust_lib_src_dir = sysroot_dir.as_ref().ok().map(|sysroot_dir| { discover_rust_lib_src_dir_or_add_component(sysroot_dir, dir, extra_env) @@ -96,7 +96,7 @@ impl Sysroot { pub fn discover_with_src_override( current_dir: &AbsPath, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, rust_lib_src_dir: AbsPathBuf, ) -> Sysroot { let sysroot_dir = discover_sysroot_dir(current_dir, extra_env); @@ -118,7 +118,12 @@ impl Sysroot { } /// Returns a command to run a tool preferring the cargo proxies if the sysroot exists. - pub fn tool(&self, tool: Tool, current_dir: impl AsRef) -> Command { + pub fn tool( + &self, + tool: Tool, + current_dir: impl AsRef, + envs: &FxHashMap>, + ) -> Command { match self.root() { Some(root) => { // special case rustc, we can look that up directly in the sysroot's bin folder @@ -127,15 +132,15 @@ impl Sysroot { if let Some(path) = probe_for_binary(root.join("bin").join(Tool::Rustc.name()).into()) { - return toolchain::command(path, current_dir); + return toolchain::command(path, current_dir, envs); } } - let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir); + let mut cmd = toolchain::command(tool.prefer_proxy(), current_dir, envs); cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(root)); cmd } - _ => toolchain::command(tool.path(), current_dir), + _ => toolchain::command(tool.path(), current_dir, envs), } } @@ -292,7 +297,7 @@ impl Sysroot { // the sysroot uses `public-dependency`, so we make cargo think it's a nightly cargo_config.extra_env.insert( "__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS".to_owned(), - "nightly".to_owned(), + Some("nightly".to_owned()), ); let (mut res, _) = match CargoWorkspace::fetch_metadata( @@ -368,10 +373,9 @@ impl Sysroot { fn discover_sysroot_dir( current_dir: &AbsPath, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, ) -> Result { - let mut rustc = toolchain::command(Tool::Rustc.path(), current_dir); - rustc.envs(extra_env); + let mut rustc = toolchain::command(Tool::Rustc.path(), current_dir, extra_env); rustc.current_dir(current_dir).args(["--print", "sysroot"]); tracing::debug!("Discovering sysroot by {:?}", rustc); let stdout = utf8_stdout(&mut rustc)?; @@ -398,12 +402,11 @@ fn discover_rust_lib_src_dir(sysroot_path: &AbsPathBuf) -> Option { fn discover_rust_lib_src_dir_or_add_component( sysroot_path: &AbsPathBuf, current_dir: &AbsPath, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, ) -> Result { discover_rust_lib_src_dir(sysroot_path) .or_else(|| { - let mut rustup = toolchain::command(Tool::Rustup.prefer_proxy(), current_dir); - rustup.envs(extra_env); + let mut rustup = toolchain::command(Tool::Rustup.prefer_proxy(), current_dir, extra_env); rustup.args(["component", "add", "rust-src"]); tracing::info!("adding rust-src component by {:?}", rustup); utf8_stdout(&mut rustup).ok()?; diff --git a/crates/project-model/src/toolchain_info/rustc_cfg.rs b/crates/project-model/src/toolchain_info/rustc_cfg.rs index e472da0c89b0..a77f76797fca 100644 --- a/crates/project-model/src/toolchain_info/rustc_cfg.rs +++ b/crates/project-model/src/toolchain_info/rustc_cfg.rs @@ -11,7 +11,7 @@ use crate::{toolchain_info::QueryConfig, utf8_stdout}; pub fn get( config: QueryConfig<'_>, target: Option<&str>, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, ) -> Vec { let _p = tracing::info_span!("rustc_cfg::get").entered(); @@ -58,14 +58,13 @@ pub fn get( fn rustc_print_cfg( target: Option<&str>, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, config: QueryConfig<'_>, ) -> anyhow::Result { const RUSTC_ARGS: [&str; 2] = ["--print", "cfg"]; let (sysroot, current_dir) = match config { QueryConfig::Cargo(sysroot, cargo_toml) => { - let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent()); - cmd.envs(extra_env); + let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env); cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS); if let Some(target) = target { cmd.args(["--target", target]); @@ -86,8 +85,7 @@ fn rustc_print_cfg( QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir), }; - let mut cmd = sysroot.tool(Tool::Rustc, current_dir); - cmd.envs(extra_env); + let mut cmd = sysroot.tool(Tool::Rustc, current_dir, extra_env); cmd.args(RUSTC_ARGS); cmd.arg("-O"); if let Some(target) = target { diff --git a/crates/project-model/src/toolchain_info/target_data_layout.rs b/crates/project-model/src/toolchain_info/target_data_layout.rs index 5d96c372e95a..a4d0ec69537a 100644 --- a/crates/project-model/src/toolchain_info/target_data_layout.rs +++ b/crates/project-model/src/toolchain_info/target_data_layout.rs @@ -10,7 +10,7 @@ use crate::{Sysroot, toolchain_info::QueryConfig, utf8_stdout}; pub fn get( config: QueryConfig<'_>, target: Option<&str>, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, ) -> anyhow::Result { const RUSTC_ARGS: [&str; 2] = ["--print", "target-spec-json"]; let process = |output: String| { @@ -21,8 +21,7 @@ pub fn get( }; let (sysroot, current_dir) = match config { QueryConfig::Cargo(sysroot, cargo_toml) => { - let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent()); - cmd.envs(extra_env); + let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env); cmd.env("RUSTC_BOOTSTRAP", "1"); cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS).args([ "--", @@ -43,11 +42,8 @@ pub fn get( QueryConfig::Rustc(sysroot, current_dir) => (sysroot, current_dir), }; - let mut cmd = Sysroot::tool(sysroot, Tool::Rustc, current_dir); - cmd.envs(extra_env) - .env("RUSTC_BOOTSTRAP", "1") - .args(["-Z", "unstable-options"]) - .args(RUSTC_ARGS); + let mut cmd = Sysroot::tool(sysroot, Tool::Rustc, current_dir, extra_env); + cmd.env("RUSTC_BOOTSTRAP", "1").args(["-Z", "unstable-options"]).args(RUSTC_ARGS); if let Some(target) = target { cmd.args(["--target", target]); } diff --git a/crates/project-model/src/toolchain_info/target_tuple.rs b/crates/project-model/src/toolchain_info/target_tuple.rs index 3917efba0b34..f6ab85321978 100644 --- a/crates/project-model/src/toolchain_info/target_tuple.rs +++ b/crates/project-model/src/toolchain_info/target_tuple.rs @@ -12,7 +12,7 @@ use crate::{ManifestPath, Sysroot, toolchain_info::QueryConfig, utf8_stdout}; pub fn get( config: QueryConfig<'_>, target: Option<&str>, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, ) -> anyhow::Result> { let _p = tracing::info_span!("target_tuple::get").entered(); if let Some(target) = target { @@ -32,12 +32,11 @@ pub fn get( } fn rustc_discover_host_tuple( - extra_env: &FxHashMap, + extra_env: &FxHashMap>, sysroot: &Sysroot, current_dir: &Path, ) -> anyhow::Result { - let mut cmd = sysroot.tool(Tool::Rustc, current_dir); - cmd.envs(extra_env); + let mut cmd = sysroot.tool(Tool::Rustc, current_dir, extra_env); cmd.arg("-vV"); let stdout = utf8_stdout(&mut cmd) .with_context(|| format!("unable to discover host platform via `{cmd:?}`"))?; @@ -53,11 +52,10 @@ fn rustc_discover_host_tuple( fn cargo_config_build_target( cargo_toml: &ManifestPath, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, sysroot: &Sysroot, ) -> Option> { - let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent()); - cmd.envs(extra_env); + let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env); cmd.current_dir(cargo_toml.parent()).env("RUSTC_BOOTSTRAP", "1"); cmd.args(["-Z", "unstable-options", "config", "get", "build.target"]); // if successful we receive `build.target = "target-tuple"` diff --git a/crates/project-model/src/toolchain_info/version.rs b/crates/project-model/src/toolchain_info/version.rs index e795fdf1d64f..91ba85985914 100644 --- a/crates/project-model/src/toolchain_info/version.rs +++ b/crates/project-model/src/toolchain_info/version.rs @@ -9,17 +9,16 @@ use crate::{toolchain_info::QueryConfig, utf8_stdout}; pub(crate) fn get( config: QueryConfig<'_>, - extra_env: &FxHashMap, + 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 ") + (sysroot.tool(Tool::Cargo, cargo_toml.parent(), extra_env), "cargo ") } QueryConfig::Rustc(sysroot, current_dir) => { - (sysroot.tool(Tool::Rustc, current_dir), "rustc ") + (sysroot.tool(Tool::Rustc, current_dir, extra_env), "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?"))?; diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 7a139ea0c4ca..2909f03c4bd6 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -856,7 +856,7 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, load: FileLoader<'_>, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, ) -> (CrateGraphBuilder, ProcMacroPaths) { let _p = tracing::info_span!("ProjectWorkspace::to_crate_graph").entered(); @@ -974,7 +974,7 @@ fn project_json_to_crate_graph( load: FileLoader<'_>, project: &ProjectJson, sysroot: &Sysroot, - extra_env: &FxHashMap, + extra_env: &FxHashMap>, override_cfg: &CfgOverrides, set_test: bool, is_sysroot: bool, @@ -1806,7 +1806,7 @@ fn add_dep_inner(graph: &mut CrateGraphBuilder, from: CrateBuilderId, dep: Depen } fn sysroot_metadata_config( - extra_env: &FxHashMap, + extra_env: &FxHashMap>, targets: &[String], ) -> CargoMetadataConfig { CargoMetadataConfig { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index aceacff98597..44b511376e89 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -602,7 +602,7 @@ config_data! { cargo_extraArgs: Vec = vec![], /// Extra environment variables that will be set when running cargo, rustc /// or other commands within the workspace. Useful for setting RUSTFLAGS. - cargo_extraEnv: FxHashMap = FxHashMap::default(), + cargo_extraEnv: FxHashMap> = FxHashMap::default(), /// List of features to activate. /// /// Set this to `"all"` to pass `--all-features` to cargo. @@ -652,7 +652,7 @@ config_data! { check_extraArgs | checkOnSave_extraArgs: Vec = vec![], /// Extra environment variables that will be set when running `cargo check`. /// Extends `#rust-analyzer.cargo.extraEnv#`. - check_extraEnv | checkOnSave_extraEnv: FxHashMap = FxHashMap::default(), + check_extraEnv | checkOnSave_extraEnv: FxHashMap> = FxHashMap::default(), /// List of features to activate. Defaults to /// `#rust-analyzer.cargo.features#`. /// @@ -1879,7 +1879,10 @@ impl Config { self.cargo_extraArgs(source_root) } - pub fn extra_env(&self, source_root: Option) -> &FxHashMap { + pub fn extra_env( + &self, + source_root: Option, + ) -> &FxHashMap> { self.cargo_extraEnv(source_root) } @@ -1889,7 +1892,10 @@ impl Config { extra_args } - pub fn check_extra_env(&self, source_root: Option) -> FxHashMap { + pub fn check_extra_env( + &self, + source_root: Option, + ) -> FxHashMap> { let mut extra_env = self.cargo_extraEnv(source_root).clone(); extra_env.extend(self.check_extraEnv(source_root).clone()); extra_env diff --git a/crates/rust-analyzer/src/discover.rs b/crates/rust-analyzer/src/discover.rs index 09de309ce956..6b87505fc735 100644 --- a/crates/rust-analyzer/src/discover.rs +++ b/crates/rust-analyzer/src/discover.rs @@ -3,6 +3,7 @@ use std::{io, path::Path}; use crossbeam_channel::Sender; +use ide_db::FxHashMap; use paths::{AbsPathBuf, Utf8Path, Utf8PathBuf}; use project_model::ProjectJsonData; use serde::{Deserialize, Serialize}; @@ -62,7 +63,8 @@ impl DiscoverCommand { }) .collect(); - let mut cmd = toolchain::command(command, current_dir); + // TODO: are we sure the extra env should be empty? + let mut cmd = toolchain::command(command, current_dir, &FxHashMap::default()); cmd.args(args); Ok(DiscoverHandle { diff --git a/crates/rust-analyzer/src/flycheck.rs b/crates/rust-analyzer/src/flycheck.rs index 126d065f5b1a..2778b311e1e3 100644 --- a/crates/rust-analyzer/src/flycheck.rs +++ b/crates/rust-analyzer/src/flycheck.rs @@ -35,7 +35,7 @@ pub(crate) struct CargoOptions { pub(crate) features: Vec, pub(crate) extra_args: Vec, pub(crate) extra_test_bin_args: Vec, - pub(crate) extra_env: FxHashMap, + pub(crate) extra_env: FxHashMap>, pub(crate) target_dir: Option, } @@ -69,7 +69,6 @@ impl CargoOptions { if let Some(target_dir) = &self.target_dir { cmd.arg("--target-dir").arg(target_dir); } - cmd.envs(&self.extra_env); } } @@ -83,7 +82,7 @@ pub(crate) enum FlycheckConfig { CustomCommand { command: String, args: Vec, - extra_env: FxHashMap, + extra_env: FxHashMap>, invocation_strategy: InvocationStrategy, }, } @@ -468,7 +467,8 @@ impl FlycheckActor { ) -> Option { match &self.config { FlycheckConfig::CargoCommand { command, options, ansi_color_output } => { - let mut cmd = toolchain::command(Tool::Cargo.path(), &*self.root); + let mut cmd = + toolchain::command(Tool::Cargo.path(), &*self.root, &options.extra_env); if let Some(sysroot_root) = &self.sysroot_root { cmd.env("RUSTUP_TOOLCHAIN", AsRef::::as_ref(sysroot_root)); } @@ -516,8 +516,7 @@ impl FlycheckActor { &*self.root } }; - let mut cmd = toolchain::command(command, root); - cmd.envs(extra_env); + let mut cmd = toolchain::command(command, root, extra_env); // If the custom command has a $saved_file placeholder, and // we're saving a file, replace the placeholder in the arguments. diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index dd41991a913f..e08dd80973a7 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -2315,8 +2315,11 @@ fn run_rustfmt( let mut command = match snap.config.rustfmt(source_root_id) { RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { // FIXME: Set RUSTUP_TOOLCHAIN - let mut cmd = toolchain::command(toolchain::Tool::Rustfmt.path(), current_dir); - cmd.envs(snap.config.extra_env(source_root_id)); + let mut cmd = toolchain::command( + toolchain::Tool::Rustfmt.path(), + current_dir, + snap.config.extra_env(source_root_id), + ); cmd.args(extra_args); if let Some(edition) = edition { @@ -2358,6 +2361,7 @@ fn run_rustfmt( RustfmtConfig::CustomCommand { command, args } => { let cmd = Utf8PathBuf::from(&command); let target_spec = TargetSpec::for_file(snap, file_id)?; + let extra_env = snap.config.extra_env(source_root_id); let mut cmd = match target_spec { Some(TargetSpec::Cargo(_)) => { // approach: if the command name contains a path separator, join it with the project root. @@ -2370,12 +2374,11 @@ fn run_rustfmt( } else { cmd }; - toolchain::command(cmd_path, current_dir) + toolchain::command(cmd_path, current_dir, extra_env) } - _ => toolchain::command(cmd, current_dir), + _ => toolchain::command(cmd, current_dir, extra_env), }; - cmd.envs(snap.config.extra_env(source_root_id)); cmd.args(args); cmd } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index b73019b310d4..b0e1e0a65b2b 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -652,12 +652,14 @@ impl GlobalState { | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, ..)), .. } => cargo .env() .into_iter() - .chain(self.config.extra_env(None)) - .map(|(a, b)| (a.clone(), b.clone())) + .map(|(k, v)| (k.clone(), Some(v.clone()))) + .chain( + self.config.extra_env(None).iter().map(|(k, v)| (k.clone(), v.clone())), + ) .chain( ws.sysroot .root() - .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), it.to_string())), + .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), Some(it.to_string()))), ) .collect(), @@ -893,7 +895,7 @@ impl GlobalState { // FIXME: Move this into load-cargo? pub fn ws_to_crate_graph( workspaces: &[ProjectWorkspace], - extra_env: &FxHashMap, + extra_env: &FxHashMap>, mut load: impl FnMut(&AbsPath) -> Option, ) -> (CrateGraphBuilder, Vec) { let mut crate_graph = CrateGraphBuilder::default(); diff --git a/crates/rust-analyzer/src/test_runner.rs b/crates/rust-analyzer/src/test_runner.rs index f245c6ac4bf6..9c0bc33af646 100644 --- a/crates/rust-analyzer/src/test_runner.rs +++ b/crates/rust-analyzer/src/test_runner.rs @@ -101,7 +101,7 @@ impl CargoTestHandle { test_target: TestTarget, sender: Sender, ) -> std::io::Result { - let mut cmd = toolchain::command(Tool::Cargo.path(), root); + let mut cmd = toolchain::command(Tool::Cargo.path(), root, &options.extra_env); cmd.env("RUSTC_BOOTSTRAP", "1"); cmd.arg("test"); diff --git a/crates/toolchain/src/lib.rs b/crates/toolchain/src/lib.rs index e3b30ff9cdec..8b7bf1a80641 100644 --- a/crates/toolchain/src/lib.rs +++ b/crates/toolchain/src/lib.rs @@ -71,11 +71,22 @@ impl Tool { } } -pub fn command(cmd: impl AsRef, working_directory: impl AsRef) -> Command { +#[allow(clippy::disallowed_types)] /* generic parameter allows for FxHashMap */ +pub fn command( + cmd: impl AsRef, + working_directory: impl AsRef, + extra_env: &std::collections::HashMap, H>, +) -> Command { // we are `toolchain::command`` #[allow(clippy::disallowed_methods)] let mut cmd = Command::new(cmd); cmd.current_dir(working_directory); + for env in extra_env { + match env { + (key, Some(val)) => cmd.env(key, val), + (key, None) => cmd.env_remove(key), + }; + } cmd }