Skip to content

Commit d09a568

Browse files
authored
Rollup merge of #97828 - ferrocene:pa-config-artifacts, r=jyn514
Allow configuring where artifacts are downloaded from Bootstrap has support for downloading prebuilt LLVM and rustc artifacts to speed up local builds, but that currently works only for users working on `rust-lang/rust`. Forks of the repository (for example Ferrocene) might have different URLs to download artifacts from, or might use a different email address on merge commits, breaking both LLVM and rustc artifact downloads. This PR refactors bootstrap to load the download URLs and other constants from `src/stage0.json`, allowing downstream forks to tweak those values. It also future-proofs the download code to easily allow forks to add their own custom protocols (like `s3://`). This PR is best reviewed commit-by-commit.
2 parents fc8027f + d3b1532 commit d09a568

File tree

7 files changed

+132
-73
lines changed

7 files changed

+132
-73
lines changed

src/bootstrap/bootstrap.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1043,7 +1043,7 @@ def bootstrap(help_triggered):
10431043
build.checksums_sha256 = data["checksums_sha256"]
10441044
build.stage0_compiler = Stage0Toolchain(data["compiler"])
10451045

1046-
build.set_dist_environment(data["dist_server"])
1046+
build.set_dist_environment(data["config"]["dist_server"])
10471047

10481048
build.build = args.build or build.build_triple()
10491049

src/bootstrap/builder.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -870,20 +870,23 @@ impl<'a> Builder<'a> {
870870
self.try_run(patchelf.arg(fname));
871871
}
872872

873-
pub(crate) fn download_component(
874-
&self,
875-
base: &str,
876-
url: &str,
877-
dest_path: &Path,
878-
help_on_error: &str,
879-
) {
873+
pub(crate) fn download_component(&self, url: &str, dest_path: &Path, help_on_error: &str) {
880874
// Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
881875
let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
882-
self.download_with_retries(&tempfile, &format!("{}/{}", base, url), help_on_error);
876+
// While bootstrap itself only supports http and https downloads, downstream forks might
877+
// need to download components from other protocols. The match allows them adding more
878+
// protocols without worrying about merge conficts if we change the HTTP implementation.
879+
match url.split_once("://").map(|(proto, _)| proto) {
880+
Some("http") | Some("https") => {
881+
self.download_http_with_retries(&tempfile, url, help_on_error)
882+
}
883+
Some(other) => panic!("unsupported protocol {other} in {url}"),
884+
None => panic!("no protocol in {url}"),
885+
}
883886
t!(std::fs::rename(&tempfile, dest_path));
884887
}
885888

886-
fn download_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
889+
fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
887890
println!("downloading {}", url);
888891
// Try curl. If that fails and we are on windows, fallback to PowerShell.
889892
let mut curl = Command::new("curl");

src/bootstrap/config.rs

+47-16
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use crate::channel::GitInfo;
2020
pub use crate::flags::Subcommand;
2121
use crate::flags::{Color, Flags};
2222
use crate::util::{exe, output, program_out_of_date, t};
23-
use crate::RustfmtMetadata;
2423
use once_cell::sync::OnceCell;
2524
use serde::{Deserialize, Deserializer};
2625

@@ -73,6 +72,7 @@ pub struct Config {
7372
pub test_compare_mode: bool,
7473
pub color: Color,
7574
pub patch_binaries_for_nix: bool,
75+
pub stage0_metadata: Stage0Metadata,
7676

7777
pub on_fail: Option<String>,
7878
pub stage: u32,
@@ -212,6 +212,28 @@ pub struct Config {
212212
pub out: PathBuf,
213213
}
214214

215+
#[derive(Default, Deserialize)]
216+
#[cfg_attr(test, derive(Clone))]
217+
pub struct Stage0Metadata {
218+
pub config: Stage0Config,
219+
pub checksums_sha256: HashMap<String, String>,
220+
pub rustfmt: Option<RustfmtMetadata>,
221+
}
222+
#[derive(Default, Deserialize)]
223+
#[cfg_attr(test, derive(Clone))]
224+
pub struct Stage0Config {
225+
pub dist_server: String,
226+
pub artifacts_server: String,
227+
pub artifacts_with_llvm_assertions_server: String,
228+
pub git_merge_commit_email: String,
229+
}
230+
#[derive(Default, Deserialize)]
231+
#[cfg_attr(test, derive(Clone))]
232+
pub struct RustfmtMetadata {
233+
pub date: String,
234+
pub version: String,
235+
}
236+
215237
#[derive(Clone, Debug)]
216238
pub enum RustfmtState {
217239
SystemToolchain(PathBuf),
@@ -776,6 +798,9 @@ impl Config {
776798
config.llvm_profile_use = flags.llvm_profile_use;
777799
config.llvm_profile_generate = flags.llvm_profile_generate;
778800

801+
let stage0_json = t!(std::fs::read(&config.src.join("src").join("stage0.json")));
802+
config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
803+
779804
#[cfg(test)]
780805
let get_toml = |_| TomlConfig::default();
781806
#[cfg(not(test))]
@@ -1103,8 +1128,11 @@ impl Config {
11031128
config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
11041129
config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
11051130
config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
1106-
config.download_rustc_commit =
1107-
download_ci_rustc_commit(rust.download_rustc, config.verbose > 0);
1131+
config.download_rustc_commit = download_ci_rustc_commit(
1132+
&config.stage0_metadata,
1133+
rust.download_rustc,
1134+
config.verbose > 0,
1135+
);
11081136
} else {
11091137
config.rust_profile_use = flags.rust_profile_use;
11101138
config.rust_profile_generate = flags.rust_profile_generate;
@@ -1424,7 +1452,11 @@ fn threads_from_config(v: u32) -> u32 {
14241452
}
14251453

14261454
/// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
1427-
fn download_ci_rustc_commit(download_rustc: Option<StringOrBool>, verbose: bool) -> Option<String> {
1455+
fn download_ci_rustc_commit(
1456+
stage0_metadata: &Stage0Metadata,
1457+
download_rustc: Option<StringOrBool>,
1458+
verbose: bool,
1459+
) -> Option<String> {
14281460
// If `download-rustc` is not set, default to rebuilding.
14291461
let if_unchanged = match download_rustc {
14301462
None | Some(StringOrBool::Bool(false)) => return None,
@@ -1443,13 +1475,12 @@ fn download_ci_rustc_commit(download_rustc: Option<StringOrBool>, verbose: bool)
14431475

14441476
// Look for a version to compare to based on the current commit.
14451477
// Only commits merged by bors will have CI artifacts.
1446-
let merge_base = output(Command::new("git").args(&[
1447-
"rev-list",
1448-
1449-
"-n1",
1450-
"--first-parent",
1451-
"HEAD",
1452-
]));
1478+
let merge_base = output(
1479+
Command::new("git")
1480+
.arg("rev-list")
1481+
.arg(format!("--author={}", stage0_metadata.config.git_merge_commit_email))
1482+
.args(&["-n1", "--first-parent", "HEAD"]),
1483+
);
14531484
let commit = merge_base.trim_end();
14541485
if commit.is_empty() {
14551486
println!("error: could not find commit hash for downloading rustc");
@@ -1484,7 +1515,7 @@ fn download_ci_rustc_commit(download_rustc: Option<StringOrBool>, verbose: bool)
14841515
}
14851516

14861517
fn maybe_download_rustfmt(builder: &Builder<'_>) -> Option<PathBuf> {
1487-
let RustfmtMetadata { date, version } = builder.stage0_metadata.rustfmt.as_ref()?;
1518+
let RustfmtMetadata { date, version } = builder.config.stage0_metadata.rustfmt.as_ref()?;
14881519
let channel = format!("{version}-{date}");
14891520

14901521
let host = builder.config.build;
@@ -1568,13 +1599,13 @@ fn download_component(
15681599
let tarball = cache_dir.join(&filename);
15691600
let (base_url, url, should_verify) = match mode {
15701601
DownloadSource::CI => (
1571-
"https://ci-artifacts.rust-lang.org/rustc-builds".to_string(),
1602+
builder.config.stage0_metadata.config.artifacts_server.clone(),
15721603
format!("{key}/{filename}"),
15731604
false,
15741605
),
15751606
DownloadSource::Dist => {
15761607
let dist_server = env::var("RUSTUP_DIST_SERVER")
1577-
.unwrap_or(builder.stage0_metadata.dist_server.to_string());
1608+
.unwrap_or(builder.config.stage0_metadata.config.dist_server.to_string());
15781609
// NOTE: make `dist` part of the URL because that's how it's stored in src/stage0.json
15791610
(dist_server, format!("dist/{key}/{filename}"), true)
15801611
}
@@ -1590,7 +1621,7 @@ fn download_component(
15901621
target at this time, see https://doc.rust-lang.org/nightly\
15911622
/rustc/platform-support.html for more information."
15921623
);
1593-
let sha256 = builder.stage0_metadata.checksums_sha256.get(&url).expect(&error);
1624+
let sha256 = builder.config.stage0_metadata.checksums_sha256.get(&url).expect(&error);
15941625
if tarball.exists() {
15951626
if builder.verify(&tarball, sha256) {
15961627
builder.unpack(&tarball, &bin_root, prefix);
@@ -1610,7 +1641,7 @@ fn download_component(
16101641
None
16111642
};
16121643

1613-
builder.download_component(&base_url, &url, &tarball, "");
1644+
builder.download_component(&format!("{base_url}/{url}"), &tarball, "");
16141645
if let Some(sha256) = checksum {
16151646
if !builder.verify(&tarball, sha256) {
16161647
panic!("failed to verify {}", tarball.display());

src/bootstrap/lib.rs

-19
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ use std::os::windows::fs::symlink_file;
118118

119119
use filetime::FileTime;
120120
use once_cell::sync::OnceCell;
121-
use serde::Deserialize;
122121

123122
use crate::builder::Kind;
124123
use crate::config::{LlvmLibunwind, TargetSelection};
@@ -294,8 +293,6 @@ pub struct Build {
294293
hosts: Vec<TargetSelection>,
295294
targets: Vec<TargetSelection>,
296295

297-
// Stage 0 (downloaded) compiler, lld and cargo or their local rust equivalents
298-
stage0_metadata: Stage0Metadata,
299296
initial_rustc: PathBuf,
300297
initial_cargo: PathBuf,
301298
initial_lld: PathBuf,
@@ -322,18 +319,6 @@ pub struct Build {
322319
metrics: metrics::BuildMetrics,
323320
}
324321

325-
#[derive(Deserialize)]
326-
struct Stage0Metadata {
327-
dist_server: String,
328-
checksums_sha256: HashMap<String, String>,
329-
rustfmt: Option<RustfmtMetadata>,
330-
}
331-
#[derive(Deserialize)]
332-
struct RustfmtMetadata {
333-
date: String,
334-
version: String,
335-
}
336-
337322
#[derive(Debug)]
338323
struct Crate {
339324
name: Interned<String>,
@@ -482,11 +467,7 @@ impl Build {
482467
bootstrap_out
483468
};
484469

485-
let stage0_json = t!(std::fs::read_to_string(&src.join("src").join("stage0.json")));
486-
let stage0_metadata = t!(serde_json::from_str::<Stage0Metadata>(&stage0_json));
487-
488470
let mut build = Build {
489-
stage0_metadata,
490471
initial_rustc: config.initial_rustc.clone(),
491472
initial_cargo: config.initial_cargo.clone(),
492473
initial_lld,

src/bootstrap/native.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
121121
let mut rev_list = Command::new("git");
122122
rev_list.args(&[
123123
PathBuf::from("rev-list"),
124-
"--author=[email protected]".into(),
124+
format!("--author={}", builder.config.stage0_metadata.config.git_merge_commit_email).into(),
125125
"-n1".into(),
126126
"--first-parent".into(),
127127
"HEAD".into(),
@@ -170,11 +170,10 @@ fn download_ci_llvm(builder: &Builder<'_>, llvm_sha: &str) {
170170
if !rustc_cache.exists() {
171171
t!(fs::create_dir_all(&rustc_cache));
172172
}
173-
let base = "https://ci-artifacts.rust-lang.org";
174-
let url = if llvm_assertions {
175-
format!("rustc-builds-alt/{}", llvm_sha)
173+
let base = if llvm_assertions {
174+
&builder.config.stage0_metadata.config.artifacts_with_llvm_assertions_server
176175
} else {
177-
format!("rustc-builds/{}", llvm_sha)
176+
&builder.config.stage0_metadata.config.artifacts_server
178177
};
179178
let filename = format!("rust-dev-nightly-{}.tar.xz", builder.build.build.triple);
180179
let tarball = rustc_cache.join(&filename);
@@ -187,7 +186,11 @@ help: if trying to compile an old commit of rustc, disable `download-ci-llvm` in
187186
[llvm]
188187
download-ci-llvm = false
189188
";
190-
builder.download_component(base, &format!("{}/{}", url, filename), &tarball, help_on_error);
189+
builder.download_component(
190+
&format!("{base}/{llvm_sha}/{filename}"),
191+
&tarball,
192+
help_on_error,
193+
);
191194
}
192195
let llvm_root = builder.config.ci_llvm_root();
193196
builder.unpack(&tarball, &llvm_root, "rust-dev");

src/stage0.json

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
{
2-
"__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.",
3-
"dist_server": "https://static.rust-lang.org",
2+
"config": {
3+
"dist_server": "https://static.rust-lang.org",
4+
"artifacts_server": "https://ci-artifacts.rust-lang.org/rustc-builds",
5+
"artifacts_with_llvm_assertions_server": "https://ci-artifacts.rust-lang.org/rustc-builds-alt",
6+
"git_merge_commit_email": "[email protected]"
7+
},
8+
"__comments": [
9+
"The configuration above this comment is editable, and can be changed",
10+
"by forks of the repository if they have alternate values.",
11+
"",
12+
"The section below is generated by `./x.py run src/tools/bump-stage0`,",
13+
"run that command again to update the bootstrap compiler.",
14+
"",
15+
"All changes below this comment will be overridden the next time the",
16+
"tool is executed."
17+
],
418
"compiler": {
519
"date": "2022-05-20",
620
"version": "beta"

0 commit comments

Comments
 (0)