Skip to content

Commit 8315873

Browse files
committed
Auto merge of #14701 - linyihai:trace-env-table, r=weihanglo
Fix: trace `config` `[env]` table in dep-info. ### What does this PR try to resolve? The `env` defined in `config.toml` or `--config env` are stripped before recording in the dep-info file. The absence of the env table doesn't rebuild when env changed By tracing the `env` table into the `dep-info` file, If the envs changed then the rebuild can be triggered. Fixes #13280 ### How should we test and review this PR? One commit add the test, the latter commit update the test through the fixes. ### Additional information The PR only fixed the `env` table changes can't trigger a rebuild, other `CARGO-like` envs doesn't take into account.
2 parents cf91520 + 668d82e commit 8315873

File tree

4 files changed

+226
-40
lines changed

4 files changed

+226
-40
lines changed

src/cargo/core/compiler/fingerprint/mod.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@
362362
mod dirty_reason;
363363

364364
use std::collections::hash_map::{Entry, HashMap};
365-
366365
use std::env;
366+
use std::ffi::OsString;
367367
use std::fmt::{self, Display};
368368
use std::fs::{self, File};
369369
use std::hash::{self, Hash, Hasher};
@@ -849,7 +849,11 @@ impl LocalFingerprint {
849849
.to_string(),
850850
)
851851
} else {
852-
gctx.get_env(key).ok()
852+
if let Some(value) = gctx.env_config()?.get(key) {
853+
value.to_str().and_then(|s| Some(s.to_string()))
854+
} else {
855+
gctx.get_env(key).ok()
856+
}
853857
};
854858
if current == *previous {
855859
continue;
@@ -2124,6 +2128,9 @@ enum DepInfoPathType {
21242128
///
21252129
/// The serialized Cargo format will contain a list of files, all of which are
21262130
/// relative if they're under `root`. or absolute if they're elsewhere.
2131+
///
2132+
/// The `env_config` argument is a set of environment variables that are
2133+
/// defined in `[env]` table of the `config.toml`.
21272134
pub fn translate_dep_info(
21282135
rustc_dep_info: &Path,
21292136
cargo_dep_info: &Path,
@@ -2132,6 +2139,7 @@ pub fn translate_dep_info(
21322139
target_root: &Path,
21332140
rustc_cmd: &ProcessBuilder,
21342141
allow_package: bool,
2142+
env_config: &Arc<HashMap<String, OsString>>,
21352143
) -> CargoResult<()> {
21362144
let depinfo = parse_rustc_dep_info(rustc_dep_info)?;
21372145

@@ -2168,9 +2176,11 @@ pub fn translate_dep_info(
21682176
// This also includes `CARGO` since if the code is explicitly wanting to
21692177
// know that path, it should be rebuilt if it changes. The CARGO path is
21702178
// not tracked elsewhere in the fingerprint.
2171-
on_disk_info
2172-
.env
2173-
.retain(|(key, _)| !rustc_cmd.get_envs().contains_key(key) || key == CARGO_ENV);
2179+
//
2180+
// For cargo#13280, We trace env vars that are defined in the `[env]` config table.
2181+
on_disk_info.env.retain(|(key, _)| {
2182+
env_config.contains_key(key) || !rustc_cmd.get_envs().contains_key(key) || key == CARGO_ENV
2183+
});
21742184

21752185
let serialize_path = |file| {
21762186
// The path may be absolute or relative, canonical or not. Make sure

src/cargo/core/compiler/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ fn rustc(
330330
if hide_diagnostics_for_scrape_unit {
331331
output_options.show_diagnostics = false;
332332
}
333-
333+
let env_config = Arc::clone(build_runner.bcx.gctx.env_config()?);
334334
return Ok(Work::new(move |state| {
335335
// Artifacts are in a different location than typical units,
336336
// hence we must assure the crate- and target-dependent
@@ -459,6 +459,7 @@ fn rustc(
459459
&rustc,
460460
// Do not track source files in the fingerprint for registry dependencies.
461461
is_local,
462+
&env_config,
462463
)
463464
.with_context(|| {
464465
internal(format!(
@@ -1987,10 +1988,7 @@ pub(crate) fn apply_env_config(
19871988
if cmd.get_envs().contains_key(key) {
19881989
continue;
19891990
}
1990-
1991-
if value.is_force() || gctx.get_env_os(key).is_none() {
1992-
cmd.env(key, value.resolve(gctx));
1993-
}
1991+
cmd.env(key, value);
19941992
}
19951993
Ok(())
19961994
}

src/cargo/util/context/mod.rs

+43-30
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use std::io::SeekFrom;
6363
use std::mem;
6464
use std::path::{Path, PathBuf};
6565
use std::str::FromStr;
66-
use std::sync::Once;
66+
use std::sync::{Arc, Once};
6767
use std::time::Instant;
6868

6969
use self::ConfigValue as CV;
@@ -227,7 +227,7 @@ pub struct GlobalContext {
227227
target_cfgs: LazyCell<Vec<(String, TargetCfgConfig)>>,
228228
doc_extern_map: LazyCell<RustdocExternMap>,
229229
progress_config: ProgressConfig,
230-
env_config: LazyCell<EnvConfig>,
230+
env_config: LazyCell<Arc<HashMap<String, OsString>>>,
231231
/// This should be false if:
232232
/// - this is an artifact of the rustc distribution process for "stable" or for "beta"
233233
/// - this is an `#[test]` that does not opt in with `enable_nightly_features`
@@ -1833,34 +1833,47 @@ impl GlobalContext {
18331833
&self.progress_config
18341834
}
18351835

1836-
pub fn env_config(&self) -> CargoResult<&EnvConfig> {
1837-
let env_config = self
1838-
.env_config
1839-
.try_borrow_with(|| self.get::<EnvConfig>("env"))?;
1840-
1841-
// Reasons for disallowing these values:
1842-
//
1843-
// - CARGO_HOME: The initial call to cargo does not honor this value
1844-
// from the [env] table. Recursive calls to cargo would use the new
1845-
// value, possibly behaving differently from the outer cargo.
1846-
//
1847-
// - RUSTUP_HOME and RUSTUP_TOOLCHAIN: Under normal usage with rustup,
1848-
// this will have no effect because the rustup proxy sets
1849-
// RUSTUP_HOME and RUSTUP_TOOLCHAIN, and that would override the
1850-
// [env] table. If the outer cargo is executed directly
1851-
// circumventing the rustup proxy, then this would affect calls to
1852-
// rustc (assuming that is a proxy), which could potentially cause
1853-
// problems with cargo and rustc being from different toolchains. We
1854-
// consider this to be not a use case we would like to support,
1855-
// since it will likely cause problems or lead to confusion.
1856-
for disallowed in &["CARGO_HOME", "RUSTUP_HOME", "RUSTUP_TOOLCHAIN"] {
1857-
if env_config.contains_key(*disallowed) {
1858-
bail!(
1859-
"setting the `{disallowed}` environment variable is not supported \
1860-
in the `[env]` configuration table"
1861-
);
1862-
}
1863-
}
1836+
/// Get the env vars from the config `[env]` table which
1837+
/// are `force = true` or don't exist in the env snapshot [`GlobalContext::get_env`].
1838+
pub fn env_config(&self) -> CargoResult<&Arc<HashMap<String, OsString>>> {
1839+
let env_config = self.env_config.try_borrow_with(|| {
1840+
CargoResult::Ok(Arc::new({
1841+
let env_config = self.get::<EnvConfig>("env")?;
1842+
// Reasons for disallowing these values:
1843+
//
1844+
// - CARGO_HOME: The initial call to cargo does not honor this value
1845+
// from the [env] table. Recursive calls to cargo would use the new
1846+
// value, possibly behaving differently from the outer cargo.
1847+
//
1848+
// - RUSTUP_HOME and RUSTUP_TOOLCHAIN: Under normal usage with rustup,
1849+
// this will have no effect because the rustup proxy sets
1850+
// RUSTUP_HOME and RUSTUP_TOOLCHAIN, and that would override the
1851+
// [env] table. If the outer cargo is executed directly
1852+
// circumventing the rustup proxy, then this would affect calls to
1853+
// rustc (assuming that is a proxy), which could potentially cause
1854+
// problems with cargo and rustc being from different toolchains. We
1855+
// consider this to be not a use case we would like to support,
1856+
// since it will likely cause problems or lead to confusion.
1857+
for disallowed in &["CARGO_HOME", "RUSTUP_HOME", "RUSTUP_TOOLCHAIN"] {
1858+
if env_config.contains_key(*disallowed) {
1859+
bail!(
1860+
"setting the `{disallowed}` environment variable is not supported \
1861+
in the `[env]` configuration table"
1862+
);
1863+
}
1864+
}
1865+
env_config
1866+
.into_iter()
1867+
.filter_map(|(k, v)| {
1868+
if v.is_force() || self.get_env_os(&k).is_none() {
1869+
Some((k, v.resolve(self).to_os_string()))
1870+
} else {
1871+
None
1872+
}
1873+
})
1874+
.collect()
1875+
}))
1876+
})?;
18641877

18651878
Ok(env_config)
18661879
}

tests/testsuite/cargo_env_config.rs

+165
Original file line numberDiff line numberDiff line change
@@ -276,3 +276,168 @@ MAIN ENV_TEST:from-env
276276
"#]])
277277
.run();
278278
}
279+
280+
#[cargo_test]
281+
fn env_changed_defined_in_config_toml() {
282+
let p = project()
283+
.file("Cargo.toml", &basic_bin_manifest("foo"))
284+
.file(
285+
"src/main.rs",
286+
r#"
287+
use std::env;
288+
fn main() {
289+
println!( "{}", env!("ENV_TEST") );
290+
}
291+
"#,
292+
)
293+
.file(
294+
".cargo/config.toml",
295+
r#"
296+
[env]
297+
ENV_TEST = "from-config"
298+
"#,
299+
)
300+
.build();
301+
302+
p.cargo("run")
303+
.with_stdout_data(str![[r#"
304+
from-config
305+
306+
"#]])
307+
.with_stderr_data(str![[r#"
308+
[COMPILING] foo v0.5.0 ([ROOT]/foo)
309+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
310+
[RUNNING] `target/debug/foo[EXE]`
311+
312+
"#]])
313+
.run();
314+
315+
p.cargo("run")
316+
.env("ENV_TEST", "from-env")
317+
.with_stdout_data(str![[r#"
318+
from-env
319+
320+
"#]])
321+
.with_stderr_data(str![[r#"
322+
[COMPILING] foo v0.5.0 ([ROOT]/foo)
323+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
324+
[RUNNING] `target/debug/foo[EXE]`
325+
326+
"#]])
327+
.run();
328+
// This identical cargo invocation is to ensure no rebuild happen.
329+
p.cargo("run")
330+
.env("ENV_TEST", "from-env")
331+
.with_stdout_data(str![[r#"
332+
from-env
333+
334+
"#]])
335+
.with_stderr_data(str![[r#"
336+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
337+
[RUNNING] `target/debug/foo[EXE]`
338+
339+
"#]])
340+
.run();
341+
}
342+
343+
#[cargo_test]
344+
fn forced_env_changed_defined_in_config_toml() {
345+
let p = project()
346+
.file("Cargo.toml", &basic_bin_manifest("foo"))
347+
.file(
348+
"src/main.rs",
349+
r#"
350+
use std::env;
351+
fn main() {
352+
println!( "{}", env!("ENV_TEST") );
353+
}
354+
"#,
355+
)
356+
.file(
357+
".cargo/config.toml",
358+
r#"
359+
[env]
360+
ENV_TEST = {value = "from-config", force = true}
361+
"#,
362+
)
363+
.build();
364+
365+
p.cargo("run")
366+
.with_stdout_data(str![[r#"
367+
from-config
368+
369+
"#]])
370+
.with_stderr_data(str![[r#"
371+
[COMPILING] foo v0.5.0 ([ROOT]/foo)
372+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
373+
[RUNNING] `target/debug/foo[EXE]`
374+
375+
"#]])
376+
.run();
377+
378+
p.cargo("run")
379+
.env("ENV_TEST", "from-env")
380+
.with_stdout_data(str![[r#"
381+
from-config
382+
383+
"#]])
384+
.with_stderr_data(str![[r#"
385+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
386+
[RUNNING] `target/debug/foo[EXE]`
387+
388+
"#]])
389+
.run();
390+
}
391+
392+
#[cargo_test]
393+
fn env_changed_defined_in_config_args() {
394+
let p = project()
395+
.file("Cargo.toml", &basic_bin_manifest("foo"))
396+
.file(
397+
"src/main.rs",
398+
r#"
399+
use std::env;
400+
fn main() {
401+
println!( "{}", env!("ENV_TEST") );
402+
}
403+
"#,
404+
)
405+
.build();
406+
p.cargo(r#"run --config 'env.ENV_TEST="one"'"#)
407+
.with_stdout_data(str![[r#"
408+
one
409+
410+
"#]])
411+
.with_stderr_data(str![[r#"
412+
[COMPILING] foo v0.5.0 ([ROOT]/foo)
413+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
414+
[RUNNING] `target/debug/foo[EXE]`
415+
416+
"#]])
417+
.run();
418+
419+
p.cargo(r#"run --config 'env.ENV_TEST="two"'"#)
420+
.with_stdout_data(str![[r#"
421+
two
422+
423+
"#]])
424+
.with_stderr_data(str![[r#"
425+
[COMPILING] foo v0.5.0 ([ROOT]/foo)
426+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
427+
[RUNNING] `target/debug/foo[EXE]`
428+
429+
"#]])
430+
.run();
431+
// This identical cargo invocation is to ensure no rebuild happen.
432+
p.cargo(r#"run --config 'env.ENV_TEST="two"'"#)
433+
.with_stdout_data(str![[r#"
434+
two
435+
436+
"#]])
437+
.with_stderr_data(str![[r#"
438+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
439+
[RUNNING] `target/debug/foo[EXE]`
440+
441+
"#]])
442+
.run();
443+
}

0 commit comments

Comments
 (0)