allow using null to unset an environment variable

this makes three changes:
- all callsites of `toolchain::command` are changed to use
  `command(path, extra_env)`, instead of manually adding the env after
  the fact.
- all `map<str, str>` are changed to `map<str, option<str>>`.
- `command` checks for None and calls `env_remove` if so.

this caught several places where environment variables weren't being
propagated:
- when running `rustc --print=target-libdir`
- when running `cargo rustc -- --print=target-spec-json`
- when running the custom DiscoverLinkedProjects config. I *think* this
  is for use with non-cargo build systems, so I didn't change it.
This commit is contained in:
jyn 2025-04-19 11:42:38 -04:00
parent a09a5502c3
commit 3b964a7105
19 changed files with 114 additions and 91 deletions

View file

@ -602,7 +602,7 @@ config_data! {
cargo_extraArgs: Vec<String> = 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<String, String> = FxHashMap::default(),
cargo_extraEnv: FxHashMap<String, Option<String>> = 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<String> = vec![],
/// Extra environment variables that will be set when running `cargo check`.
/// Extends `#rust-analyzer.cargo.extraEnv#`.
check_extraEnv | checkOnSave_extraEnv: FxHashMap<String, String> = FxHashMap::default(),
check_extraEnv | checkOnSave_extraEnv: FxHashMap<String, Option<String>> = 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<SourceRootId>) -> &FxHashMap<String, String> {
pub fn extra_env(
&self,
source_root: Option<SourceRootId>,
) -> &FxHashMap<String, Option<String>> {
self.cargo_extraEnv(source_root)
}
@ -1889,7 +1892,10 @@ impl Config {
extra_args
}
pub fn check_extra_env(&self, source_root: Option<SourceRootId>) -> FxHashMap<String, String> {
pub fn check_extra_env(
&self,
source_root: Option<SourceRootId>,
) -> FxHashMap<String, Option<String>> {
let mut extra_env = self.cargo_extraEnv(source_root).clone();
extra_env.extend(self.check_extraEnv(source_root).clone());
extra_env

View file

@ -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 {

View file

@ -35,7 +35,7 @@ pub(crate) struct CargoOptions {
pub(crate) features: Vec<String>,
pub(crate) extra_args: Vec<String>,
pub(crate) extra_test_bin_args: Vec<String>,
pub(crate) extra_env: FxHashMap<String, String>,
pub(crate) extra_env: FxHashMap<String, Option<String>>,
pub(crate) target_dir: Option<Utf8PathBuf>,
}
@ -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<String>,
extra_env: FxHashMap<String, String>,
extra_env: FxHashMap<String, Option<String>>,
invocation_strategy: InvocationStrategy,
},
}
@ -468,7 +467,8 @@ impl FlycheckActor {
) -> Option<Command> {
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::<std::path::Path>::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.

View file

@ -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
}

View file

@ -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<String, String>,
extra_env: &FxHashMap<String, Option<String>>,
mut load: impl FnMut(&AbsPath) -> Option<vfs::FileId>,
) -> (CrateGraphBuilder, Vec<ProcMacroPaths>) {
let mut crate_graph = CrateGraphBuilder::default();

View file

@ -101,7 +101,7 @@ impl CargoTestHandle {
test_target: TestTarget,
sender: Sender<CargoTestMessage>,
) -> std::io::Result<Self> {
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");