Skip to content

Commit 07f1c16

Browse files
authored
Rollup merge of #97507 - jyn514:download-rustfmt, r=Mark-Simulacrum
Move rustfmt downloads from bootstrap.py to rustbuild - Allow verifying CI downloads using src/stage0.json - Change download functions not to hard-code `ci-artifacts.rust-lang.org` - Change `format::format` to take a `Builder` so it has access to `download_component`. I think we may want to reconsider the distinction between Build and Builder at some point; I don't think it's particularly useful. - Move rustfmt downloads out of bootstrap.py Fixes #95136. Helps with #94829. This is based on #96687 for simplicity.
2 parents 09d52bc + 6115f4e commit 07f1c16

File tree

8 files changed

+233
-109
lines changed

8 files changed

+233
-109
lines changed

Cargo.lock

+2
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,15 @@ dependencies = [
216216
"cmake",
217217
"filetime",
218218
"getopts",
219+
"hex 0.4.2",
219220
"ignore",
220221
"libc",
221222
"once_cell",
222223
"opener",
223224
"pretty_assertions 0.7.2",
224225
"serde",
225226
"serde_json",
227+
"sha2",
226228
"sysinfo",
227229
"tar",
228230
"toml",

src/bootstrap/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ filetime = "0.2"
4040
getopts = "0.2.19"
4141
cc = "1.0.69"
4242
libc = "0.2"
43+
hex = "0.4"
4344
serde = { version = "1.0.8", features = ["derive"] }
4445
serde_json = "1.0.2"
46+
sha2 = "0.10"
4547
tar = "0.4"
4648
toml = "0.5"
4749
ignore = "0.4.10"

src/bootstrap/bootstrap.py

+21-63
Original file line numberDiff line numberDiff line change
@@ -63,31 +63,30 @@ def support_xz():
6363
except tarfile.CompressionError:
6464
return False
6565

66-
def get(base, url, path, checksums, verbose=False, do_verify=True):
66+
def get(base, url, path, checksums, verbose=False):
6767
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
6868
temp_path = temp_file.name
6969

7070
try:
71-
if do_verify:
72-
if url not in checksums:
73-
raise RuntimeError(("src/stage0.json doesn't contain a checksum for {}. "
74-
"Pre-built artifacts might not available for this "
75-
"target at this time, see https://doc.rust-lang.org/nightly"
76-
"/rustc/platform-support.html for more information.")
77-
.format(url))
78-
sha256 = checksums[url]
79-
if os.path.exists(path):
80-
if verify(path, sha256, False):
81-
if verbose:
82-
print("using already-download file", path)
83-
return
84-
else:
85-
if verbose:
86-
print("ignoring already-download file",
87-
path, "due to failed verification")
88-
os.unlink(path)
71+
if url not in checksums:
72+
raise RuntimeError(("src/stage0.json doesn't contain a checksum for {}. "
73+
"Pre-built artifacts might not be available for this "
74+
"target at this time, see https://doc.rust-lang.org/nightly"
75+
"/rustc/platform-support.html for more information.")
76+
.format(url))
77+
sha256 = checksums[url]
78+
if os.path.exists(path):
79+
if verify(path, sha256, False):
80+
if verbose:
81+
print("using already-download file", path)
82+
return
83+
else:
84+
if verbose:
85+
print("ignoring already-download file",
86+
path, "due to failed verification")
87+
os.unlink(path)
8988
download(temp_path, "{}/{}".format(base, url), True, verbose)
90-
if do_verify and not verify(temp_path, sha256, verbose):
89+
if not verify(temp_path, sha256, verbose):
9190
raise RuntimeError("failed verification")
9291
if verbose:
9392
print("moving {} to {}".format(temp_path, path))
@@ -430,7 +429,6 @@ class RustBuild(object):
430429
def __init__(self):
431430
self.checksums_sha256 = {}
432431
self.stage0_compiler = None
433-
self.stage0_rustfmt = None
434432
self._download_url = ''
435433
self.build = ''
436434
self.build_dir = ''
@@ -484,31 +482,10 @@ def download_toolchain(self):
484482
with output(self.rustc_stamp()) as rust_stamp:
485483
rust_stamp.write(key)
486484

487-
if self.rustfmt() and self.rustfmt().startswith(bin_root) and (
488-
not os.path.exists(self.rustfmt())
489-
or self.program_out_of_date(
490-
self.rustfmt_stamp(),
491-
"" if self.stage0_rustfmt is None else self.stage0_rustfmt.channel()
492-
)
493-
):
494-
if self.stage0_rustfmt is not None:
495-
tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz'
496-
filename = "rustfmt-{}-{}{}".format(
497-
self.stage0_rustfmt.version, self.build, tarball_suffix,
498-
)
499-
self._download_component_helper(
500-
filename, "rustfmt-preview", tarball_suffix, key=self.stage0_rustfmt.date
501-
)
502-
self.fix_bin_or_dylib("{}/bin/rustfmt".format(bin_root))
503-
self.fix_bin_or_dylib("{}/bin/cargo-fmt".format(bin_root))
504-
with output(self.rustfmt_stamp()) as rustfmt_stamp:
505-
rustfmt_stamp.write(self.stage0_rustfmt.channel())
506-
507485
def _download_component_helper(
508-
self, filename, pattern, tarball_suffix, key=None
486+
self, filename, pattern, tarball_suffix,
509487
):
510-
if key is None:
511-
key = self.stage0_compiler.date
488+
key = self.stage0_compiler.date
512489
cache_dst = os.path.join(self.build_dir, "cache")
513490
rustc_cache = os.path.join(cache_dst, key)
514491
if not os.path.exists(rustc_cache):
@@ -524,7 +501,6 @@ def _download_component_helper(
524501
tarball,
525502
self.checksums_sha256,
526503
verbose=self.verbose,
527-
do_verify=True,
528504
)
529505
unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose)
530506

@@ -634,16 +610,6 @@ def rustc_stamp(self):
634610
"""
635611
return os.path.join(self.bin_root(), '.rustc-stamp')
636612

637-
def rustfmt_stamp(self):
638-
"""Return the path for .rustfmt-stamp
639-
640-
>>> rb = RustBuild()
641-
>>> rb.build_dir = "build"
642-
>>> rb.rustfmt_stamp() == os.path.join("build", "stage0", ".rustfmt-stamp")
643-
True
644-
"""
645-
return os.path.join(self.bin_root(), '.rustfmt-stamp')
646-
647613
def program_out_of_date(self, stamp_path, key):
648614
"""Check if the given program stamp is out of date"""
649615
if not os.path.exists(stamp_path) or self.clean:
@@ -717,12 +683,6 @@ def rustc(self):
717683
"""Return config path for rustc"""
718684
return self.program_config('rustc')
719685

720-
def rustfmt(self):
721-
"""Return config path for rustfmt"""
722-
if self.stage0_rustfmt is None:
723-
return None
724-
return self.program_config('rustfmt')
725-
726686
def program_config(self, program):
727687
"""Return config path for the given program at the given stage
728688
@@ -1082,8 +1042,6 @@ def bootstrap(help_triggered):
10821042
data = json.load(f)
10831043
build.checksums_sha256 = data["checksums_sha256"]
10841044
build.stage0_compiler = Stage0Toolchain(data["compiler"])
1085-
if data.get("rustfmt") is not None:
1086-
build.stage0_rustfmt = Stage0Toolchain(data["rustfmt"])
10871045

10881046
build.set_dist_environment(data["dist_server"])
10891047

src/bootstrap/builder.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,8 @@ impl<'a> Builder<'a> {
728728
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
729729
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
730730
Subcommand::Run { ref paths } => (Kind::Run, &paths[..]),
731-
Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
731+
Subcommand::Format { .. } => (Kind::Format, &[][..]),
732+
Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
732733
panic!()
733734
}
734735
};
@@ -878,7 +879,6 @@ impl<'a> Builder<'a> {
878879
) {
879880
// Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
880881
let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
881-
// FIXME: support `do_verify` (only really needed for nightly rustfmt)
882882
self.download_with_retries(&tempfile, &format!("{}/{}", base, url), help_on_error);
883883
t!(std::fs::rename(&tempfile, dest_path));
884884
}
@@ -970,6 +970,28 @@ impl<'a> Builder<'a> {
970970
t!(fs::remove_dir_all(dst.join(directory_prefix)));
971971
}
972972

973+
/// Returns whether the SHA256 checksum of `path` matches `expected`.
974+
pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool {
975+
use sha2::Digest;
976+
977+
self.verbose(&format!("verifying {}", path.display()));
978+
let mut hasher = sha2::Sha256::new();
979+
// FIXME: this is ok for rustfmt (4.1 MB large at time of writing), but it seems memory-intensive for rustc and larger components.
980+
// Consider using streaming IO instead?
981+
let contents = if self.config.dry_run { vec![] } else { t!(fs::read(path)) };
982+
hasher.update(&contents);
983+
let found = hex::encode(hasher.finalize().as_slice());
984+
let verified = found == expected;
985+
if !verified && !self.config.dry_run {
986+
println!(
987+
"invalid checksum: \n\
988+
found: {found}\n\
989+
expected: {expected}",
990+
);
991+
}
992+
return verified;
993+
}
994+
973995
/// Obtain a compiler at a given stage and for a given host. Explicitly does
974996
/// not take `Compiler` since all `Compiler` instances are meant to be
975997
/// obtained through this function, since it ensures that they are valid
@@ -1192,6 +1214,10 @@ impl<'a> Builder<'a> {
11921214
Config::download_rustc(self)
11931215
}
11941216

1217+
pub(crate) fn initial_rustfmt(&self) -> Option<PathBuf> {
1218+
Config::initial_rustfmt(self)
1219+
}
1220+
11951221
/// Prepares an invocation of `cargo` to be run.
11961222
///
11971223
/// This will create a `Command` that represents a pending execution of

0 commit comments

Comments
 (0)