|
3 | 3 | //! This module implements parsing `config.toml` configuration files to tweak
|
4 | 4 | //! how the build runs.
|
5 | 5 |
|
6 |
| -use std::cell::Cell; |
| 6 | +use std::cell::{Cell, RefCell}; |
7 | 7 | use std::cmp;
|
8 | 8 | use std::collections::{HashMap, HashSet};
|
9 | 9 | use std::env;
|
@@ -204,10 +204,27 @@ pub struct Config {
|
204 | 204 | // These are either the stage0 downloaded binaries or the locally installed ones.
|
205 | 205 | pub initial_cargo: PathBuf,
|
206 | 206 | pub initial_rustc: PathBuf,
|
207 |
| - pub initial_rustfmt: Option<PathBuf>, |
| 207 | + #[cfg(not(test))] |
| 208 | + initial_rustfmt: RefCell<RustfmtState>, |
| 209 | + #[cfg(test)] |
| 210 | + pub initial_rustfmt: RefCell<RustfmtState>, |
208 | 211 | pub out: PathBuf,
|
209 | 212 | }
|
210 | 213 |
|
| 214 | +#[derive(Clone, Debug)] |
| 215 | +pub enum RustfmtState { |
| 216 | + SystemToolchain(PathBuf), |
| 217 | + Downloaded(PathBuf), |
| 218 | + Unavailable, |
| 219 | + LazyEvaluated, |
| 220 | +} |
| 221 | + |
| 222 | +impl Default for RustfmtState { |
| 223 | + fn default() -> Self { |
| 224 | + RustfmtState::LazyEvaluated |
| 225 | + } |
| 226 | +} |
| 227 | + |
211 | 228 | #[derive(Debug, Clone, Copy, PartialEq)]
|
212 | 229 | pub enum LlvmLibunwind {
|
213 | 230 | No,
|
@@ -1151,13 +1168,22 @@ impl Config {
|
1151 | 1168 | set(&mut config.missing_tools, t.missing_tools);
|
1152 | 1169 | }
|
1153 | 1170 |
|
1154 |
| - config.initial_rustfmt = build.rustfmt.or_else(|| { |
1155 |
| - // Cargo does not provide a RUSTFMT environment variable, so we |
1156 |
| - // synthesize it manually. |
1157 |
| - let rustfmt = config.initial_rustc.with_file_name(exe("rustfmt", config.build)); |
1158 |
| - |
1159 |
| - if rustfmt.exists() { Some(rustfmt) } else { None } |
1160 |
| - }); |
| 1171 | + if let Some(r) = build.rustfmt { |
| 1172 | + *config.initial_rustfmt.borrow_mut() = if r.exists() { |
| 1173 | + RustfmtState::SystemToolchain(r) |
| 1174 | + } else { |
| 1175 | + RustfmtState::Unavailable |
| 1176 | + }; |
| 1177 | + } else { |
| 1178 | + // If using a system toolchain for bootstrapping, see if that has rustfmt available. |
| 1179 | + let host = config.build; |
| 1180 | + let rustfmt_path = config.initial_rustc.with_file_name(exe("rustfmt", host)); |
| 1181 | + let bin_root = config.out.join(host.triple).join("stage0"); |
| 1182 | + if !rustfmt_path.starts_with(&bin_root) { |
| 1183 | + // Using a system-provided toolchain; we shouldn't download rustfmt. |
| 1184 | + *config.initial_rustfmt.borrow_mut() = RustfmtState::SystemToolchain(rustfmt_path); |
| 1185 | + } |
| 1186 | + } |
1161 | 1187 |
|
1162 | 1188 | // Now that we've reached the end of our configuration, infer the
|
1163 | 1189 | // default values for all options that we haven't otherwise stored yet.
|
@@ -1327,6 +1353,25 @@ impl Config {
|
1327 | 1353 | })
|
1328 | 1354 | }
|
1329 | 1355 |
|
| 1356 | + pub(crate) fn initial_rustfmt(builder: &Builder<'_>) -> Option<PathBuf> { |
| 1357 | + match &mut *builder.config.initial_rustfmt.borrow_mut() { |
| 1358 | + RustfmtState::SystemToolchain(p) | RustfmtState::Downloaded(p) => Some(p.clone()), |
| 1359 | + RustfmtState::Unavailable => None, |
| 1360 | + r @ RustfmtState::LazyEvaluated => { |
| 1361 | + if builder.config.dry_run { |
| 1362 | + return Some(PathBuf::new()); |
| 1363 | + } |
| 1364 | + let path = maybe_download_rustfmt(builder); |
| 1365 | + *r = if let Some(p) = &path { |
| 1366 | + RustfmtState::Downloaded(p.clone()) |
| 1367 | + } else { |
| 1368 | + RustfmtState::Unavailable |
| 1369 | + }; |
| 1370 | + path |
| 1371 | + } |
| 1372 | + } |
| 1373 | + } |
| 1374 | + |
1330 | 1375 | pub fn verbose(&self) -> bool {
|
1331 | 1376 | self.verbose > 0
|
1332 | 1377 | }
|
@@ -1437,6 +1482,44 @@ fn download_ci_rustc_commit(download_rustc: Option<StringOrBool>, verbose: bool)
|
1437 | 1482 | Some(commit.to_string())
|
1438 | 1483 | }
|
1439 | 1484 |
|
| 1485 | +fn maybe_download_rustfmt(builder: &Builder<'_>) -> Option<PathBuf> { |
| 1486 | + #[derive(Deserialize)] |
| 1487 | + struct Stage0Metadata { |
| 1488 | + dist_server: String, |
| 1489 | + rustfmt: Option<RustfmtMetadata>, |
| 1490 | + } |
| 1491 | + #[derive(Deserialize)] |
| 1492 | + struct RustfmtMetadata { |
| 1493 | + date: String, |
| 1494 | + version: String, |
| 1495 | + } |
| 1496 | + |
| 1497 | + let stage0_json = builder.read(&builder.src.join("src").join("stage0.json")); |
| 1498 | + let metadata = t!(serde_json::from_str::<Stage0Metadata>(&stage0_json)); |
| 1499 | + let RustfmtMetadata { date, version } = metadata.rustfmt?; |
| 1500 | + let channel = format!("{version}-{date}"); |
| 1501 | + let mut dist_server = env::var("RUSTUP_DIST_SERVER").unwrap_or(metadata.dist_server); |
| 1502 | + dist_server.push_str("/dist"); |
| 1503 | + |
| 1504 | + let host = builder.config.build; |
| 1505 | + let rustfmt_path = builder.config.initial_rustc.with_file_name(exe("rustfmt", host)); |
| 1506 | + let bin_root = builder.config.out.join(host.triple).join("stage0"); |
| 1507 | + let rustfmt_stamp = bin_root.join(".rustfmt-stamp"); |
| 1508 | + if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) { |
| 1509 | + return Some(rustfmt_path); |
| 1510 | + } |
| 1511 | + |
| 1512 | + let filename = format!("rustfmt-{version}-{build}.tar.xz", build = host.triple); |
| 1513 | + download_component(builder, &dist_server, filename, "rustfmt-preview", &date, "stage0"); |
| 1514 | + assert!(rustfmt_path.exists()); |
| 1515 | + |
| 1516 | + builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt")); |
| 1517 | + builder.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt")); |
| 1518 | + |
| 1519 | + builder.create(&rustfmt_stamp, &channel); |
| 1520 | + Some(rustfmt_path) |
| 1521 | +} |
| 1522 | + |
1440 | 1523 | fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
|
1441 | 1524 | builder.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})"));
|
1442 | 1525 | // FIXME: support downloading artifacts from the beta channel
|
@@ -1474,18 +1557,34 @@ fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
|
1474 | 1557 | /// Download a single component of a CI-built toolchain (not necessarily a published nightly).
|
1475 | 1558 | // NOTE: intentionally takes an owned string to avoid downloading multiple times by accident
|
1476 | 1559 | fn download_ci_component(builder: &Builder<'_>, filename: String, prefix: &str, commit: &str) {
|
| 1560 | + download_component( |
| 1561 | + builder, |
| 1562 | + "https://ci-artifacts.rust-lang.org/rustc-builds", |
| 1563 | + filename, |
| 1564 | + prefix, |
| 1565 | + commit, |
| 1566 | + "ci-rustc", |
| 1567 | + ) |
| 1568 | +} |
| 1569 | + |
| 1570 | +fn download_component( |
| 1571 | + builder: &Builder<'_>, |
| 1572 | + base_url: &str, |
| 1573 | + filename: String, |
| 1574 | + prefix: &str, |
| 1575 | + key: &str, |
| 1576 | + destination: &str, |
| 1577 | +) { |
1477 | 1578 | let cache_dst = builder.out.join("cache");
|
1478 |
| - let rustc_cache = cache_dst.join(commit); |
1479 |
| - if !rustc_cache.exists() { |
1480 |
| - t!(fs::create_dir_all(&rustc_cache)); |
| 1579 | + let cache_dir = cache_dst.join(key); |
| 1580 | + if !cache_dir.exists() { |
| 1581 | + t!(fs::create_dir_all(&cache_dir)); |
1481 | 1582 | }
|
1482 | 1583 |
|
1483 |
| - let base = "https://ci-artifacts.rust-lang.org"; |
1484 |
| - let url = format!("rustc-builds/{commit}"); |
1485 |
| - let tarball = rustc_cache.join(&filename); |
| 1584 | + let tarball = cache_dir.join(&filename); |
1486 | 1585 | if !tarball.exists() {
|
1487 |
| - builder.download_component(base, &format!("{url}/{filename}"), &tarball, ""); |
| 1586 | + builder.download_component(base_url, &format!("{key}/{filename}"), &tarball, ""); |
1488 | 1587 | }
|
1489 |
| - let bin_root = builder.out.join(builder.config.build.triple).join("ci-rustc"); |
| 1588 | + let bin_root = builder.out.join(builder.config.build.triple).join(destination); |
1490 | 1589 | builder.unpack(&tarball, &bin_root, prefix)
|
1491 | 1590 | }
|
0 commit comments