Skip to content

Commit 6fb4b55

Browse files
committed
build_manifest: use prebuilt build-manifest from tarballs
1 parent 98003b2 commit 6fb4b55

File tree

5 files changed

+127
-37
lines changed

5 files changed

+127
-37
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ authors = ["Alex Crichton <[email protected]>"]
55
license = "MIT OR Apache-2.0"
66
edition = "2018"
77

8+
build = "build.rs"
9+
810
[dependencies]
911
curl = "0.4"
1012
flate2 = "1"

build.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
// Prevent a rebuild every time a non-Rust file is changed.
3+
println!("cargo:rerun-if-changed=build.rs");
4+
5+
// Provide the current target as environment variable.
6+
println!("cargo:rustc-env=TARGET={}", std::env::var("TARGET").unwrap());
7+
}

local/run.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ RUSTC_DEFAULT_BRANCH="master"
1313
DOWNLOAD_BASE="https://ci-artifacts.rust-lang.org/rustc-builds"
1414
# Rustup components to download for each target we want to release.
1515
DOWNLOAD_COMPONENTS=(
16+
"build-manifest"
1617
"cargo"
1718
"rust"
1819
"rust-docs"

src/build_manifest.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use crate::{config::Channel, Context};
2+
use anyhow::{Context as _, Error};
3+
use std::{
4+
fs::File,
5+
io::BufReader,
6+
path::{Path, PathBuf},
7+
process::Command,
8+
};
9+
use tar::Archive;
10+
use tempfile::NamedTempFile;
11+
use xz2::read::XzDecoder;
12+
13+
pub(crate) struct BuildManifest<'a> {
14+
builder: &'a Context,
15+
tarball_name: String,
16+
tarball_path: PathBuf,
17+
}
18+
19+
impl<'a> BuildManifest<'a> {
20+
pub(crate) fn new(builder: &'a Context) -> Self {
21+
// Precalculate paths used later.
22+
let release = match builder.config.channel {
23+
Channel::Stable => builder.current_version.clone().unwrap(),
24+
channel => channel.to_string(),
25+
};
26+
let tarball_name = format!("build-manifest-{}-{}", release, crate::TARGET);
27+
let tarball_path = builder.dl_dir().join(format!("{}.tar.xz", tarball_name));
28+
29+
Self {
30+
builder,
31+
tarball_name,
32+
tarball_path,
33+
}
34+
}
35+
36+
pub(crate) fn exists(&self) -> bool {
37+
self.tarball_path.is_file()
38+
}
39+
40+
pub(crate) fn run(&self) -> Result<(), Error> {
41+
let config = &self.builder.config;
42+
let bin = self
43+
.extract()
44+
.context("failed to extract build-manifest from the tarball")?;
45+
46+
println!("running build-manifest...");
47+
let upload_addr = format!("{}/{}", config.upload_addr, config.upload_dir);
48+
// build-manifest <input-dir> <output-dir> <date> <upload-addr> <channel>
49+
let status = Command::new(bin.path())
50+
.arg(self.builder.dl_dir())
51+
.arg(self.builder.dl_dir())
52+
.arg(&self.builder.date)
53+
.arg(upload_addr)
54+
.arg(config.channel.to_string())
55+
.status()
56+
.context("failed to execute build-manifest")?;
57+
58+
if status.success() {
59+
return Ok(());
60+
} else {
61+
anyhow::bail!("build-manifest failed with status {:?}", status);
62+
}
63+
}
64+
65+
fn extract(&self) -> Result<NamedTempFile, Error> {
66+
let binary_path = Path::new(&self.tarball_name)
67+
.join("build-manifest")
68+
.join("bin")
69+
.join("build-manifest");
70+
71+
let tarball_file = BufReader::new(File::open(&self.tarball_path)?);
72+
let mut tarball = Archive::new(XzDecoder::new(tarball_file));
73+
74+
let bin = NamedTempFile::new()?;
75+
tarball
76+
.entries()?
77+
.filter_map(|e| e.ok())
78+
.filter(|e| e.path().ok().as_deref() == Some(&binary_path))
79+
.next()
80+
.ok_or_else(|| anyhow::anyhow!("missing build-manifest binary inside the tarball"))?
81+
.unpack(bin.path())?;
82+
83+
Ok(bin)
84+
}
85+
}

src/main.rs

Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod build_manifest;
12
mod config;
23
mod sign;
34

@@ -9,14 +10,18 @@ use std::process::Command;
910
use std::time::Instant;
1011

1112
use anyhow::Error;
13+
use build_manifest::BuildManifest;
14+
use chrono::Utc;
1215
use curl::easy::Easy;
1316
use fs2::FileExt;
1417
use rayon::prelude::*;
15-
use chrono::Utc;
1618
use sign::Signer;
19+
use xz2::read::XzDecoder;
1720

1821
use crate::config::{Channel, Config};
1922

23+
const TARGET: &str = env!("TARGET");
24+
2025
struct Context {
2126
work: PathBuf,
2227
handle: Easy,
@@ -51,7 +56,6 @@ impl Context {
5156

5257
fn run(&mut self) -> Result<(), Error> {
5358
let _lock = self.lock()?;
54-
self.update_repo()?;
5559
self.do_release()?;
5660

5761
Ok(())
@@ -73,7 +77,7 @@ impl Context {
7377

7478
/// Update the rust repository we have cached, either cloning a fresh one or
7579
/// fetching remote references
76-
fn update_repo(&mut self) -> Result<(), Error> {
80+
fn legacy_update_repo(&mut self) -> Result<(), Error> {
7781
// Clone/update the repo
7882
let dir = self.rust_dir();
7983
if dir.is_dir() {
@@ -168,34 +172,23 @@ impl Context {
168172

169173
self.assert_all_components_present()?;
170174

171-
// Ok we've now determined that a release needs to be done. Let's
172-
// configure rust, build a manifest and sign the artifacts we just downloaded, and upload the
173-
// signatures and manifest to the CI bucket.
174-
175-
self.configure_rust(&rev)?;
175+
// Ok we've now determined that a release needs to be done.
176176

177-
let is_legacy_build_manifest = !self
178-
.rust_dir()
179-
.join("src/tools/build-manifest/src/manifest.rs")
180-
.exists();
181-
println!("is legacy build-manifest: {}", is_legacy_build_manifest);
182-
183-
if is_legacy_build_manifest {
184-
self.sign_artifacts()?;
185-
} else {
186-
self.build_manifest()?;
187-
}
177+
let build_manifest = BuildManifest::new(self);
178+
if build_manifest.exists() {
179+
// Generate the channel manifest
180+
build_manifest.run()?;
188181

189-
// Merge all the signatures with the download files, and then sync that
190-
// whole dir up to the release archives
191-
for file in self.build_dir().join("build/dist/").read_dir()? {
192-
let file = file?;
193-
fs::copy(file.path(), self.dl_dir().join(file.file_name()))?;
194-
}
195-
196-
if !is_legacy_build_manifest {
182+
// Generate checksums and sign all the files we're about to ship.
197183
let signer = Signer::new(&self.config)?;
198184
signer.sign_directory(&self.dl_dir())?;
185+
} else {
186+
// For releases using the legacy build-manifest, we need to clone the rustc monorepo
187+
// and invoke `./x.py dist hash-and-sign` in it. This won't be needed after 1.48.0 is
188+
// out in the stable channel.
189+
self.legacy_update_repo()?;
190+
self.legacy_configure_rust(&rev)?;
191+
self.legacy_sign_artifacts()?;
199192
}
200193

201194
self.publish_archive()?;
@@ -211,7 +204,7 @@ impl Context {
211204
Ok(())
212205
}
213206

214-
fn configure_rust(&mut self, rev: &str) -> Result<(), Error> {
207+
fn legacy_configure_rust(&mut self, rev: &str) -> Result<(), Error> {
215208
let build = self.build_dir();
216209
// Only delete the dist artifacts when running the tool locally, to avoid rebuilding
217210
// bootstrap over and over again.
@@ -428,7 +421,7 @@ upload-addr = \"{}/{}\"
428421
println!("recompressing {}...", gz_path.display());
429422

430423
let xz = File::open(xz_path)?;
431-
let mut xz = xz2::read::XzDecoder::new(xz);
424+
let mut xz = XzDecoder::new(xz);
432425
let gz = File::create(gz_path)?;
433426
let mut gz = flate2::write::GzEncoder::new(gz, compression_level);
434427
io::copy(&mut xz, &mut gz)?;
@@ -448,20 +441,22 @@ upload-addr = \"{}/{}\"
448441
}
449442

450443
/// Create manifest and sign the artifacts.
451-
fn sign_artifacts(&mut self) -> Result<(), Error> {
444+
fn legacy_sign_artifacts(&mut self) -> Result<(), Error> {
452445
let build = self.build_dir();
453446
// This calls `src/tools/build-manifest` from the rustc repo.
454447
run(Command::new(self.rust_dir().join("x.py"))
455448
.current_dir(&build)
456449
.arg("dist")
457-
.arg("hash-and-sign"))
458-
}
450+
.arg("hash-and-sign"))?;
459451

460-
fn build_manifest(&mut self) -> Result<(), Error> {
461-
run(Command::new(self.rust_dir().join("x.py"))
462-
.current_dir(&self.build_dir())
463-
.arg("run")
464-
.arg("src/tools/build-manifest"))
452+
// Merge all the signatures with the download files, and then sync that
453+
// whole dir up to the release archives
454+
for file in self.build_dir().join("build/dist/").read_dir()? {
455+
let file = file?;
456+
fs::copy(file.path(), self.dl_dir().join(file.file_name()))?;
457+
}
458+
459+
Ok(())
465460
}
466461

467462
fn publish_archive(&mut self) -> Result<(), Error> {

0 commit comments

Comments
 (0)