Skip to content

Commit 1d9637e

Browse files
committed
Respect env defined in cargo.toml
1 parent d91a692 commit 1d9637e

File tree

8 files changed

+248
-11
lines changed

8 files changed

+248
-11
lines changed

cargo-nextest/src/dispatch.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ use clap::{ArgEnum, Args, Parser, Subcommand};
1212
use guppy::graph::PackageGraph;
1313
use itertools::Itertools;
1414
use nextest_filtering::FilteringExpr;
15-
use nextest_metadata::{BinaryListSummary, BuildPlatform};
15+
use nextest_metadata::{BinaryListSummary, BuildPlatform, EnvironmentMap};
1616
use nextest_runner::{
1717
cargo_config::{CargoConfigs, TargetTriple},
1818
config::{NextestConfig, NextestProfile, TestThreads, ToolConfigFile},
19-
errors::WriteTestListError,
19+
errors::{CargoConfigError, WriteTestListError},
2020
list::{BinaryList, OutputFormat, RustTestArtifact, SerializableFormat, TestList},
2121
partition::PartitionerBuilder,
2222
reporter::{FinalStatusLevel, StatusLevel, TestOutputDisplay, TestReporterBuilder},
@@ -440,6 +440,7 @@ impl TestBuildFilter {
440440
binary_list: Arc<BinaryList>,
441441
test_filter_builder: TestFilterBuilder,
442442
runner: &TargetRunner,
443+
env: EnvironmentMap,
443444
reuse_build: &ReuseBuildInfo,
444445
) -> Result<TestList<'g>> {
445446
let path_mapper = make_path_mapper(
@@ -461,6 +462,7 @@ impl TestBuildFilter {
461462
rust_build_meta,
462463
&test_filter_builder,
463464
runner,
465+
env,
464466
// TODO: do we need to allow customizing this?
465467
num_cpus::get(),
466468
)
@@ -765,6 +767,7 @@ struct BaseApp {
765767

766768
cargo_configs: CargoConfigs,
767769
target_runner: OnceCell<TargetRunner>,
770+
env: OnceCell<EnvironmentMap>,
768771
}
769772

770773
impl BaseApp {
@@ -848,9 +851,14 @@ impl BaseApp {
848851
cargo_configs,
849852

850853
target_runner: OnceCell::new(),
854+
env: OnceCell::new(),
851855
})
852856
}
853857

858+
fn load_env(&self) -> Result<&EnvironmentMap, CargoConfigError> {
859+
self.env.get_or_try_init(|| self.cargo_configs.env())
860+
}
861+
854862
fn load_runner(&self, triple: Option<&TargetTriple>) -> &TargetRunner {
855863
self.target_runner
856864
.get_or_init(|| runner_for_target(&self.cargo_configs, triple))
@@ -971,12 +979,14 @@ impl App {
971979
binary_list: Arc<BinaryList>,
972980
test_filter_builder: TestFilterBuilder,
973981
target_runner: &TargetRunner,
982+
env: EnvironmentMap,
974983
) -> Result<TestList> {
975984
self.build_filter.compute_test_list(
976985
self.base.graph(),
977986
binary_list,
978987
test_filter_builder,
979988
target_runner,
989+
env,
980990
&self.base.reuse_build,
981991
)
982992
}
@@ -1031,8 +1041,13 @@ impl App {
10311041
let target_runner = self
10321042
.base
10331043
.load_runner(binary_list.rust_build_meta.target_triple.as_ref());
1034-
let test_list =
1035-
self.build_test_list(binary_list, test_filter_builder, target_runner)?;
1044+
let env = self.base.load_env()?;
1045+
let test_list = self.build_test_list(
1046+
binary_list,
1047+
test_filter_builder,
1048+
target_runner,
1049+
env.to_owned(),
1050+
)?;
10361051

10371052
let mut writer = output_writer.stdout_writer();
10381053
test_list.write(
@@ -1067,8 +1082,14 @@ impl App {
10671082
let target_runner = self
10681083
.base
10691084
.load_runner(binary_list.rust_build_meta.target_triple.as_ref());
1085+
let env = self.base.load_env()?;
10701086

1071-
let test_list = self.build_test_list(binary_list, test_filter_builder, target_runner)?;
1087+
let test_list = self.build_test_list(
1088+
binary_list,
1089+
test_filter_builder,
1090+
target_runner,
1091+
env.to_owned(),
1092+
)?;
10721093

10731094
let output = output_writer.reporter_output();
10741095

fixtures/nextest-tests/.cargo/config

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,10 @@ replace-with = "vendored-sources"
1212

1313
[source.vendored-sources]
1414
directory = "vendor"
15+
16+
[env]
17+
__NEXTEST_ENV_VAR_FOR_TESTING_NOT_IN_PARENT_ENV = "if-this-value-is-present-then-test-passed"
18+
__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_NO_OVERRIDE = "if-this-value-is-present-then-test-failed"
19+
__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_OVERRIDDEN = { value = "if-this-value-is-present-then-test-passed", force = true }
20+
__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_RELATIVE_NO_OVERRIDE = { value = "if-this-value-is-present-then-test-failed", relative = true }
21+
__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_RELATIVE_OVERRIDDEN = { value = "if-this-value-is-present-then-test-passed", force = true, relative = true }

fixtures/nextest-tests/tests/basic.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,38 @@ fn test_cargo_env_vars() {
156156
// CARGO_PRIMARY_PACKAGE is missing at runtime
157157
// CARGO_TARGET_TMPDIR is missing at runtime
158158
// Dynamic library paths are tested by actually executing the tests -- they depend on the dynamic library.
159+
160+
assert_eq!(
161+
std::env::var("__NEXTEST_ENV_VAR_FOR_TESTING_NOT_IN_PARENT_ENV",).as_deref(),
162+
Ok("if-this-value-is-present-then-test-passed")
163+
);
164+
assert_eq!(
165+
std::env::var("__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_NO_OVERRIDE",).as_deref(),
166+
Ok("if-this-value-is-present-then-test-passed")
167+
);
168+
assert_eq!(
169+
std::env::var("__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_OVERRIDDEN",).as_deref(),
170+
Ok("if-this-value-is-present-then-test-passed")
171+
);
172+
assert_eq!(
173+
std::env::var("__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_RELATIVE_NO_OVERRIDE",)
174+
.as_deref(),
175+
Ok("if-this-value-is-present-then-test-passed")
176+
);
177+
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
178+
let overridden_path =
179+
std::env::var("__NEXTEST_ENV_VAR_FOR_TESTING_IN_PARENT_ENV_RELATIVE_OVERRIDDEN").unwrap();
180+
let overridden_path = match overridden_path.strip_prefix(&manifest_dir) {
181+
Some(overridden_path) => overridden_path,
182+
None => panic!(
183+
"Path {overridden_path:?} should start with workspace root {:?}",
184+
manifest_dir
185+
),
186+
};
187+
assert_eq!(
188+
overridden_path,
189+
"/.cargo/if-this-value-is-present-then-test-passed"
190+
);
159191
}
160192

161193
#[test]

nextest-metadata/src/test_list.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@ use std::{
1212
process::Command,
1313
};
1414

15+
/// An environment variable set in `config.toml`. See https://doc.rust-lang.org/cargo/reference/config.html#env
16+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
17+
pub struct CargoEnvironmentVariable {
18+
/// The source `config.toml` file. See
19+
/// https://doc.rust-lang.org/cargo/reference/config.html#hierarchical-structure for the lookup
20+
/// order.
21+
pub source: Option<Utf8PathBuf>,
22+
23+
/// The name of the environment variable to set.
24+
pub name: String,
25+
26+
/// The value of the environment variable to set.
27+
pub value: String,
28+
29+
/// If the environment variable is already set in the environment, it is not reassigned unless
30+
/// `force` is set to `true`.
31+
pub force: bool,
32+
33+
/// Interpret the environment variable as a path relative to the directory containing the source
34+
/// `config.toml` file.
35+
pub relative: bool,
36+
}
37+
38+
/// A list of environment variables to set when running tests.
39+
///
40+
/// This is a `Vec` instead of a map because, on Windows, environment variables are case-insensitive
41+
/// but case-preserving. We produce the environment as-is and let the caller handle the case of
42+
/// duplicates.
43+
pub type EnvironmentMap = Vec<CargoEnvironmentVariable>;
44+
1545
/// Command builder for `cargo nextest list`.
1646
#[derive(Clone, Debug, Default)]
1747
pub struct ListCommand {

nextest-runner/src/cargo_config.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
99
use crate::errors::{CargoConfigError, InvalidCargoCliConfigReason, TargetTripleError};
1010
use camino::{Utf8Path, Utf8PathBuf};
11+
use nextest_metadata::{CargoEnvironmentVariable, EnvironmentMap};
1112
use once_cell::sync::OnceCell;
1213
use serde::Deserialize;
1314
use std::{collections::BTreeMap, fmt};
@@ -241,6 +242,51 @@ impl CargoConfigs {
241242
&self.cwd
242243
}
243244

245+
/// The environment variables to set when running Cargo commands.
246+
pub fn env(&self) -> Result<EnvironmentMap, CargoConfigError> {
247+
let env = self
248+
.discovered_configs()?
249+
.rev()
250+
.filter_map(|config| match config {
251+
DiscoveredConfig::CliOption { config, source }
252+
| DiscoveredConfig::File { config, source } => Some((config, source)),
253+
DiscoveredConfig::Env => None,
254+
})
255+
.flat_map(|(config, source)| {
256+
let source = match source {
257+
CargoConfigSource::CliOption => None,
258+
CargoConfigSource::File(path) => Some(path.clone()),
259+
};
260+
config
261+
.env
262+
.clone()
263+
.into_iter()
264+
.map(move |(name, value)| (source.clone(), name, value))
265+
})
266+
.map(|(source, name, value)| match value {
267+
CargoConfigEnv::Value(value) => CargoEnvironmentVariable {
268+
source,
269+
name,
270+
value,
271+
force: false,
272+
relative: false,
273+
},
274+
CargoConfigEnv::Fields {
275+
value,
276+
force,
277+
relative,
278+
} => CargoEnvironmentVariable {
279+
source,
280+
name,
281+
value,
282+
force,
283+
relative,
284+
},
285+
})
286+
.collect();
287+
Ok(env)
288+
}
289+
244290
pub(crate) fn discovered_configs(
245291
&self,
246292
) -> Result<
@@ -493,11 +539,26 @@ fn load_file(
493539
Ok((CargoConfigSource::File(path), config))
494540
}
495541

542+
#[derive(Clone, Deserialize, Debug)]
543+
#[serde(untagged)]
544+
pub(crate) enum CargoConfigEnv {
545+
Value(String),
546+
Fields {
547+
value: String,
548+
#[serde(default)]
549+
force: bool,
550+
#[serde(default)]
551+
relative: bool,
552+
},
553+
}
554+
496555
#[derive(Deserialize, Debug)]
497556
pub(crate) struct CargoConfig {
498557
#[serde(default)]
499558
pub(crate) build: CargoConfigBuild,
500559
pub(crate) target: Option<BTreeMap<String, CargoConfigRunner>>,
560+
#[serde(default)]
561+
pub(crate) env: BTreeMap<String, CargoConfigEnv>,
501562
}
502563

503564
#[derive(Deserialize, Default, Debug)]

nextest-runner/src/list/rust_build_meta.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ impl RustBuildMeta<BinaryListState> {
5353
base_output_directories: BTreeSet::new(),
5454
non_test_binaries: BTreeMap::new(),
5555
linked_paths: BTreeMap::new(),
56-
state: PhantomData,
5756
target_triple,
57+
state: PhantomData,
5858
}
5959
}
6060

@@ -69,8 +69,8 @@ impl RustBuildMeta<BinaryListState> {
6969
base_output_directories: self.base_output_directories.clone(),
7070
non_test_binaries: self.non_test_binaries.clone(),
7171
linked_paths: self.linked_paths.clone(),
72-
state: PhantomData,
7372
target_triple: self.target_triple.clone(),
73+
state: PhantomData,
7474
}
7575
}
7676
}

0 commit comments

Comments
 (0)