Skip to content

Commit 6e3f35b

Browse files
committed
Use the same filename hash for pre-release channels.
1 parent 805462e commit 6e3f35b

File tree

3 files changed

+226
-10
lines changed

3 files changed

+226
-10
lines changed

src/cargo/core/compiler/context/compilation_files.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ fn compute_metadata<'a, 'cfg>(
614614
unit.target.name().hash(&mut hasher);
615615
unit.target.kind().hash(&mut hasher);
616616

617-
bcx.rustc().verbose_version.hash(&mut hasher);
617+
hash_rustc_version(bcx, &mut hasher);
618618

619619
if cx.bcx.ws.is_member(unit.pkg) {
620620
// This is primarily here for clippy. This ensures that the clippy
@@ -641,3 +641,35 @@ fn compute_metadata<'a, 'cfg>(
641641

642642
Some(Metadata(hasher.finish()))
643643
}
644+
645+
fn hash_rustc_version(bcx: &BuildContext<'_, '_>, hasher: &mut SipHasher) {
646+
let vers = &bcx.rustc().version;
647+
if vers.pre.is_empty() {
648+
// For stable, keep the artifacts separate. This helps if someone is
649+
// testing multiple versions, to avoid recompiles.
650+
bcx.rustc().verbose_version.hash(hasher);
651+
return;
652+
}
653+
// On "nightly"/"beta"/"dev"/etc, keep each "channel" separate. Don't hash
654+
// the date/git information, so that whenever someone updates "nightly",
655+
// they won't have a bunch of stale artifacts in the target directory.
656+
//
657+
// This assumes that the first segment is the important bit ("nightly",
658+
// "beta", "dev", etc.). Skip other parts like the `.3` in `-beta.3`.
659+
vers.pre[0].hash(hasher);
660+
// Keep "host" since some people switch hosts to implicitly change
661+
// targets, (like gnu vs musl or gnu vs msvc). In the future, we may want
662+
// to consider hashing `unit.kind.short_name()` instead.
663+
bcx.rustc().host.hash(hasher);
664+
// None of the other lines are important. Currently they are:
665+
// binary: rustc <-- or "rustdoc"
666+
// commit-hash: 38114ff16e7856f98b2b4be7ab4cd29b38bed59a
667+
// commit-date: 2020-03-21
668+
// host: x86_64-apple-darwin
669+
// release: 1.44.0-nightly
670+
// LLVM version: 9.0
671+
//
672+
// The backend version ("LLVM version") might become more relevant in
673+
// the future when cranelift sees more use, and people want to switch
674+
// between different backends without recompiling.
675+
}

src/cargo/util/rustc.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub struct Rustc {
2525
pub workspace_wrapper: Option<PathBuf>,
2626
/// Verbose version information (the output of `rustc -vV`)
2727
pub verbose_version: String,
28+
/// The rustc version (`1.23.4-beta.2`), this comes from verbose_version.
29+
pub version: semver::Version,
2830
/// The host triple (arch-platform-OS), this comes from verbose_version.
2931
pub host: InternedString,
3032
cache: Mutex<Cache>,
@@ -51,25 +53,34 @@ impl Rustc {
5153
cmd.arg("-vV");
5254
let verbose_version = cache.cached_output(&cmd)?.0;
5355

54-
let host = {
55-
let triple = verbose_version
56+
let extract = |field: &str| -> CargoResult<&str> {
57+
verbose_version
5658
.lines()
57-
.find(|l| l.starts_with("host: "))
58-
.map(|l| &l[6..])
59+
.find(|l| l.starts_with(field))
60+
.map(|l| &l[field.len()..])
5961
.ok_or_else(|| {
6062
anyhow::format_err!(
61-
"`rustc -vV` didn't have a line for `host:`, got:\n{}",
63+
"`rustc -vV` didn't have a line for `{}`, got:\n{}",
64+
field.trim(),
6265
verbose_version
6366
)
64-
})?;
65-
InternedString::new(triple)
67+
})
6668
};
6769

70+
let host = InternedString::new(extract("host: ")?);
71+
let version = semver::Version::parse(extract("release: ")?).chain_err(|| {
72+
format!(
73+
"rustc version does not appear to be a valid semver version, from:\n{}",
74+
verbose_version
75+
)
76+
})?;
77+
6878
Ok(Rustc {
6979
path,
7080
wrapper,
7181
workspace_wrapper,
7282
verbose_version,
83+
version,
7384
host,
7485
cache: Mutex::new(cache),
7586
})

tests/testsuite/freshness.rs

Lines changed: 175 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ use std::time::SystemTime;
1111

1212
use cargo_test_support::paths::{self, CargoPathExt};
1313
use cargo_test_support::registry::Package;
14-
use cargo_test_support::sleep_ms;
15-
use cargo_test_support::{basic_manifest, is_coarse_mtime, project};
14+
use cargo_test_support::{basic_manifest, is_coarse_mtime, project, rustc_host, sleep_ms};
1615

1716
#[cargo_test]
1817
fn modifying_and_moving() {
@@ -2150,3 +2149,177 @@ fn rerun_if_changes() {
21502149
.with_stderr("[FINISHED] [..]")
21512150
.run();
21522151
}
2152+
2153+
#[cargo_test]
2154+
fn channel_shares_filenames() {
2155+
// Test that different "nightly" releases use the same output filename.
2156+
2157+
// Create separate rustc binaries to emulate running different toolchains.
2158+
let nightly1 = format!(
2159+
"\
2160+
rustc 1.44.0-nightly (38114ff16 2020-03-21)
2161+
binary: rustc
2162+
commit-hash: 38114ff16e7856f98b2b4be7ab4cd29b38bed59a
2163+
commit-date: 2020-03-21
2164+
host: {}
2165+
release: 1.44.0-nightly
2166+
LLVM version: 9.0
2167+
",
2168+
rustc_host()
2169+
);
2170+
2171+
let nightly2 = format!(
2172+
"\
2173+
rustc 1.44.0-nightly (a5b09d354 2020-03-31)
2174+
binary: rustc
2175+
commit-hash: a5b09d35473615e7142f5570f5c5fad0caf68bd2
2176+
commit-date: 2020-03-31
2177+
host: {}
2178+
release: 1.44.0-nightly
2179+
LLVM version: 9.0
2180+
",
2181+
rustc_host()
2182+
);
2183+
2184+
let beta1 = format!(
2185+
"\
2186+
rustc 1.43.0-beta.3 (4c587bbda 2020-03-25)
2187+
binary: rustc
2188+
commit-hash: 4c587bbda04ab55aaf56feab11dfdfe387a85d7a
2189+
commit-date: 2020-03-25
2190+
host: {}
2191+
release: 1.43.0-beta.3
2192+
LLVM version: 9.0
2193+
",
2194+
rustc_host()
2195+
);
2196+
2197+
let beta2 = format!(
2198+
"\
2199+
rustc 1.42.0-beta.5 (4e1c5f0e9 2020-02-28)
2200+
binary: rustc
2201+
commit-hash: 4e1c5f0e9769a588b91c977e3d81e140209ef3a2
2202+
commit-date: 2020-02-28
2203+
host: {}
2204+
release: 1.42.0-beta.5
2205+
LLVM version: 9.0
2206+
",
2207+
rustc_host()
2208+
);
2209+
2210+
let stable1 = format!(
2211+
"\
2212+
rustc 1.42.0 (b8cedc004 2020-03-09)
2213+
binary: rustc
2214+
commit-hash: b8cedc00407a4c56a3bda1ed605c6fc166655447
2215+
commit-date: 2020-03-09
2216+
host: {}
2217+
release: 1.42.0
2218+
LLVM version: 9.0
2219+
",
2220+
rustc_host()
2221+
);
2222+
2223+
let stable2 = format!(
2224+
"\
2225+
rustc 1.41.1 (f3e1a954d 2020-02-24)
2226+
binary: rustc
2227+
commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196
2228+
commit-date: 2020-02-24
2229+
host: {}
2230+
release: 1.41.1
2231+
LLVM version: 9.0
2232+
",
2233+
rustc_host()
2234+
);
2235+
2236+
let compiler = project()
2237+
.at("compiler")
2238+
.file("Cargo.toml", &basic_manifest("compiler", "0.1.0"))
2239+
.file(
2240+
"src/main.rs",
2241+
r#"
2242+
fn main() {
2243+
if std::env::args_os().any(|a| a == "-vV") {
2244+
print!("{}", env!("FUNKY_VERSION_TEST"));
2245+
return;
2246+
}
2247+
let mut cmd = std::process::Command::new("rustc");
2248+
cmd.args(std::env::args_os().skip(1));
2249+
assert!(cmd.status().unwrap().success());
2250+
}
2251+
"#,
2252+
)
2253+
.build();
2254+
2255+
let makeit = |version, vv| {
2256+
// Force a rebuild.
2257+
compiler.target_debug_dir().join("deps").rm_rf();
2258+
compiler.cargo("build").env("FUNKY_VERSION_TEST", vv).run();
2259+
fs::rename(compiler.bin("compiler"), compiler.bin(version)).unwrap();
2260+
};
2261+
makeit("nightly1", nightly1);
2262+
makeit("nightly2", nightly2);
2263+
makeit("beta1", beta1);
2264+
makeit("beta2", beta2);
2265+
makeit("stable1", stable1);
2266+
makeit("stable2", stable2);
2267+
2268+
// Run `cargo check` with different rustc versions to observe its behavior.
2269+
let p = project().file("src/lib.rs", "").build();
2270+
2271+
// Runs `cargo check` and returns the rmeta filename created.
2272+
// Checks that the freshness matches the given value.
2273+
let check = |version, fresh| -> String {
2274+
let output = p
2275+
.cargo("check --message-format=json")
2276+
.env("RUSTC", compiler.bin(version))
2277+
.exec_with_output()
2278+
.unwrap();
2279+
// Collect the filenames generated.
2280+
let mut artifacts: Vec<_> = std::str::from_utf8(&output.stdout)
2281+
.unwrap()
2282+
.lines()
2283+
.filter_map(|line| {
2284+
let value: serde_json::Value = serde_json::from_str(line).unwrap();
2285+
if value["reason"].as_str().unwrap() == "compiler-artifact" {
2286+
assert_eq!(value["fresh"].as_bool().unwrap(), fresh);
2287+
let filenames = value["filenames"].as_array().unwrap();
2288+
assert_eq!(filenames.len(), 1);
2289+
Some(filenames[0].to_string())
2290+
} else {
2291+
None
2292+
}
2293+
})
2294+
.collect();
2295+
// Should only generate one rmeta file.
2296+
assert_eq!(artifacts.len(), 1);
2297+
artifacts.pop().unwrap()
2298+
};
2299+
2300+
let nightly1_name = check("nightly1", false);
2301+
assert_eq!(check("nightly1", true), nightly1_name);
2302+
assert_eq!(check("nightly2", false), nightly1_name); // same as before
2303+
assert_eq!(check("nightly2", true), nightly1_name);
2304+
// Should rebuild going back to nightly1.
2305+
assert_eq!(check("nightly1", false), nightly1_name);
2306+
2307+
let beta1_name = check("beta1", false);
2308+
assert_ne!(beta1_name, nightly1_name);
2309+
assert_eq!(check("beta1", true), beta1_name);
2310+
assert_eq!(check("beta2", false), beta1_name); // same as before
2311+
assert_eq!(check("beta2", true), beta1_name);
2312+
// Should rebuild going back to beta1.
2313+
assert_eq!(check("beta1", false), beta1_name);
2314+
2315+
let stable1_name = check("stable1", false);
2316+
assert_ne!(stable1_name, nightly1_name);
2317+
assert_ne!(stable1_name, beta1_name);
2318+
let stable2_name = check("stable2", false);
2319+
assert_ne!(stable1_name, stable2_name);
2320+
// Check everything is fresh.
2321+
assert_eq!(check("stable1", true), stable1_name);
2322+
assert_eq!(check("stable2", true), stable2_name);
2323+
assert_eq!(check("beta1", true), beta1_name);
2324+
assert_eq!(check("nightly1", true), nightly1_name);
2325+
}

0 commit comments

Comments
 (0)