Skip to content

Commit 6b233ea

Browse files
committed
build-manifest: refactor detecting package versions
1 parent 3bddfea commit 6b233ea

File tree

4 files changed

+119
-132
lines changed

4 files changed

+119
-132
lines changed

Cargo.lock

+2
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,10 @@ name = "build-manifest"
231231
version = "0.1.0"
232232
dependencies = [
233233
"anyhow",
234+
"flate2",
234235
"serde",
235236
"serde_json",
237+
"tar",
236238
"toml",
237239
]
238240

src/tools/build-manifest/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ toml = "0.5"
99
serde = { version = "1.0", features = ["derive"] }
1010
serde_json = "1.0"
1111
anyhow = "1.0.32"
12+
flate2 = "1.0.16"
13+
tar = "0.4.29"

src/tools/build-manifest/src/main.rs

+12-131
Original file line numberDiff line numberDiff line change
@@ -236,24 +236,6 @@ struct Builder {
236236
s3_address: String,
237237
date: String,
238238

239-
rust_version: Option<String>,
240-
cargo_version: Option<String>,
241-
rls_version: Option<String>,
242-
rust_analyzer_version: Option<String>,
243-
clippy_version: Option<String>,
244-
rustfmt_version: Option<String>,
245-
llvm_tools_version: Option<String>,
246-
miri_version: Option<String>,
247-
248-
rust_git_commit_hash: Option<String>,
249-
cargo_git_commit_hash: Option<String>,
250-
rls_git_commit_hash: Option<String>,
251-
rust_analyzer_git_commit_hash: Option<String>,
252-
clippy_git_commit_hash: Option<String>,
253-
rustfmt_git_commit_hash: Option<String>,
254-
llvm_tools_git_commit_hash: Option<String>,
255-
miri_git_commit_hash: Option<String>,
256-
257239
should_sign: bool,
258240
}
259241

@@ -286,7 +268,7 @@ fn main() {
286268
}
287269

288270
Builder {
289-
versions: Versions::new(&channel, Path::new(&monorepo_path)).unwrap(),
271+
versions: Versions::new(&channel, &input, Path::new(&monorepo_path)).unwrap(),
290272

291273
input,
292274
output,
@@ -295,51 +277,13 @@ fn main() {
295277
s3_address,
296278
date,
297279

298-
rust_version: None,
299-
cargo_version: None,
300-
rls_version: None,
301-
rust_analyzer_version: None,
302-
clippy_version: None,
303-
rustfmt_version: None,
304-
llvm_tools_version: None,
305-
miri_version: None,
306-
307-
rust_git_commit_hash: None,
308-
cargo_git_commit_hash: None,
309-
rls_git_commit_hash: None,
310-
rust_analyzer_git_commit_hash: None,
311-
clippy_git_commit_hash: None,
312-
rustfmt_git_commit_hash: None,
313-
llvm_tools_git_commit_hash: None,
314-
miri_git_commit_hash: None,
315-
316280
should_sign,
317281
}
318282
.build();
319283
}
320284

321285
impl Builder {
322286
fn build(&mut self) {
323-
self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu");
324-
self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu");
325-
self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu");
326-
self.rust_analyzer_version = self.version("rust-analyzer", "x86_64-unknown-linux-gnu");
327-
self.clippy_version = self.version("clippy", "x86_64-unknown-linux-gnu");
328-
self.rustfmt_version = self.version("rustfmt", "x86_64-unknown-linux-gnu");
329-
self.llvm_tools_version = self.version("llvm-tools", "x86_64-unknown-linux-gnu");
330-
self.miri_version = self.version("miri", "x86_64-unknown-linux-gnu");
331-
332-
self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu");
333-
self.cargo_git_commit_hash = self.git_commit_hash("cargo", "x86_64-unknown-linux-gnu");
334-
self.rls_git_commit_hash = self.git_commit_hash("rls", "x86_64-unknown-linux-gnu");
335-
self.rust_analyzer_git_commit_hash =
336-
self.git_commit_hash("rust-analyzer", "x86_64-unknown-linux-gnu");
337-
self.clippy_git_commit_hash = self.git_commit_hash("clippy", "x86_64-unknown-linux-gnu");
338-
self.rustfmt_git_commit_hash = self.git_commit_hash("rustfmt", "x86_64-unknown-linux-gnu");
339-
self.llvm_tools_git_commit_hash =
340-
self.git_commit_hash("llvm-tools", "x86_64-unknown-linux-gnu");
341-
self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu");
342-
343287
self.check_toolstate();
344288
self.digest_and_sign();
345289
let manifest = self.build_manifest();
@@ -368,8 +312,7 @@ impl Builder {
368312
// Mark some tools as missing based on toolstate.
369313
if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") {
370314
println!("Miri tests are not passing, removing component");
371-
self.miri_version = None;
372-
self.miri_git_commit_hash = None;
315+
self.versions.disable_version(&PkgType::Miri);
373316
}
374317
}
375318

@@ -471,13 +414,10 @@ impl Builder {
471414
}
472415

473416
fn rust_package(&mut self, manifest: &Manifest) -> Package {
417+
let version_info = self.versions.version(&PkgType::Rust).expect("missing Rust tarball");
474418
let mut pkg = Package {
475-
version: self
476-
.cached_version("rust")
477-
.as_ref()
478-
.expect("Couldn't find Rust version")
479-
.clone(),
480-
git_commit_hash: self.cached_git_commit_hash("rust").clone(),
419+
version: version_info.version.expect("missing Rust version"),
420+
git_commit_hash: version_info.git_commit,
481421
target: BTreeMap::new(),
482422
};
483423
for host in HOSTS {
@@ -583,12 +523,11 @@ impl Builder {
583523
}
584524

585525
fn package(&mut self, pkgname: &str, dst: &mut BTreeMap<String, Package>, targets: &[&str]) {
586-
let (version, mut is_present) = self
587-
.cached_version(pkgname)
588-
.as_ref()
589-
.cloned()
590-
.map(|version| (version, true))
591-
.unwrap_or_default(); // `is_present` defaults to `false` here.
526+
let version_info = self
527+
.versions
528+
.version(&PkgType::from_component(pkgname))
529+
.expect("failed to load package version");
530+
let mut is_present = version_info.present;
592531

593532
// Never ship nightly-only components for other trains.
594533
if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) {
@@ -635,8 +574,8 @@ impl Builder {
635574
dst.insert(
636575
pkgname.to_string(),
637576
Package {
638-
version,
639-
git_commit_hash: self.cached_git_commit_hash(pkgname).clone(),
577+
version: version_info.version.unwrap_or_default(),
578+
git_commit_hash: version_info.git_commit,
640579
target: targets,
641580
},
642581
);
@@ -646,64 +585,6 @@ impl Builder {
646585
format!("{}/{}/{}", self.s3_address, self.date, filename)
647586
}
648587

649-
fn cached_version(&self, component: &str) -> &Option<String> {
650-
use PkgType::*;
651-
match PkgType::from_component(component) {
652-
Cargo => &self.cargo_version,
653-
Rls => &self.rls_version,
654-
RustAnalyzer => &self.rust_analyzer_version,
655-
Clippy => &self.clippy_version,
656-
Rustfmt => &self.rustfmt_version,
657-
LlvmTools => &self.llvm_tools_version,
658-
Miri => &self.miri_version,
659-
_ => &self.rust_version,
660-
}
661-
}
662-
663-
fn cached_git_commit_hash(&self, component: &str) -> &Option<String> {
664-
use PkgType::*;
665-
match PkgType::from_component(component) {
666-
Cargo => &self.cargo_git_commit_hash,
667-
Rls => &self.rls_git_commit_hash,
668-
RustAnalyzer => &self.rust_analyzer_git_commit_hash,
669-
Clippy => &self.clippy_git_commit_hash,
670-
Rustfmt => &self.rustfmt_git_commit_hash,
671-
LlvmTools => &self.llvm_tools_git_commit_hash,
672-
Miri => &self.miri_git_commit_hash,
673-
_ => &self.rust_git_commit_hash,
674-
}
675-
}
676-
677-
fn version(&mut self, component: &str, target: &str) -> Option<String> {
678-
self.untar(component, target, |filename| format!("{}/version", filename))
679-
}
680-
681-
fn git_commit_hash(&mut self, component: &str, target: &str) -> Option<String> {
682-
self.untar(component, target, |filename| format!("{}/git-commit-hash", filename))
683-
}
684-
685-
fn untar<F>(&mut self, component: &str, target: &str, dir: F) -> Option<String>
686-
where
687-
F: FnOnce(String) -> String,
688-
{
689-
let filename = self
690-
.versions
691-
.tarball_name(&PkgType::from_component(component), target)
692-
.expect("failed to retrieve the tarball path");
693-
694-
let mut cmd = Command::new("tar");
695-
cmd.arg("xf")
696-
.arg(self.input.join(&filename))
697-
.arg(dir(filename.replace(".tar.gz", "")))
698-
.arg("-O");
699-
let output = t!(cmd.output());
700-
if output.status.success() {
701-
Some(String::from_utf8_lossy(&output.stdout).trim().to_string())
702-
} else {
703-
None
704-
}
705-
}
706-
707588
fn hash(&self, path: &Path) -> String {
708589
let sha = t!(Command::new("shasum")
709590
.arg("-a")

src/tools/build-manifest/src/versions.rs

+103-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
use anyhow::{Context, Error};
2+
use flate2::read::GzDecoder;
23
use std::collections::HashMap;
4+
use std::fs::File;
5+
use std::io::Read;
36
use std::path::{Path, PathBuf};
7+
use tar::Archive;
8+
9+
const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";
410

511
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
612
pub(crate) enum PkgType {
@@ -61,32 +67,128 @@ impl PkgType {
6167
PkgType::Other(component) => component,
6268
}
6369
}
70+
71+
fn should_use_rust_version(&self) -> bool {
72+
match self {
73+
PkgType::Cargo => false,
74+
PkgType::Rls => false,
75+
PkgType::RustAnalyzer => false,
76+
PkgType::Clippy => false,
77+
PkgType::Rustfmt => false,
78+
PkgType::LlvmTools => false,
79+
PkgType::Miri => false,
80+
81+
PkgType::Rust => true,
82+
PkgType::RustSrc => true,
83+
PkgType::Other(_) => true,
84+
}
85+
}
86+
}
87+
88+
#[derive(Debug, Default, Clone)]
89+
pub(crate) struct VersionInfo {
90+
pub(crate) version: Option<String>,
91+
pub(crate) git_commit: Option<String>,
92+
pub(crate) present: bool,
6493
}
6594

6695
pub(crate) struct Versions {
6796
channel: String,
6897
rustc_version: String,
6998
monorepo_root: PathBuf,
99+
dist_path: PathBuf,
70100
package_versions: HashMap<PkgType, String>,
101+
versions: HashMap<PkgType, VersionInfo>,
71102
}
72103

73104
impl Versions {
74-
pub(crate) fn new(channel: &str, monorepo_root: &Path) -> Result<Self, Error> {
105+
pub(crate) fn new(
106+
channel: &str,
107+
dist_path: &Path,
108+
monorepo_root: &Path,
109+
) -> Result<Self, Error> {
75110
Ok(Self {
76111
channel: channel.into(),
77112
rustc_version: std::fs::read_to_string(monorepo_root.join("src").join("version"))
78113
.context("failed to read the rustc version from src/version")?
79114
.trim()
80115
.to_string(),
81116
monorepo_root: monorepo_root.into(),
117+
dist_path: dist_path.into(),
82118
package_versions: HashMap::new(),
119+
versions: HashMap::new(),
83120
})
84121
}
85122

86123
pub(crate) fn channel(&self) -> &str {
87124
&self.channel
88125
}
89126

127+
pub(crate) fn version(&mut self, mut package: &PkgType) -> Result<VersionInfo, Error> {
128+
if package.should_use_rust_version() {
129+
package = &PkgType::Rust;
130+
}
131+
132+
match self.versions.get(package) {
133+
Some(version) => Ok(version.clone()),
134+
None => {
135+
let version_info = self.load_version_from_tarball(package)?;
136+
self.versions.insert(package.clone(), version_info.clone());
137+
println!("{:?} => {:?}", package, &version_info);
138+
Ok(version_info)
139+
}
140+
}
141+
}
142+
143+
fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> {
144+
let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?;
145+
let tarball = self.dist_path.join(tarball_name);
146+
147+
let file = match File::open(&tarball) {
148+
Ok(file) => file,
149+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
150+
// Missing tarballs do not return an error, but return empty data.
151+
return Ok(VersionInfo::default());
152+
}
153+
Err(err) => return Err(err.into()),
154+
};
155+
let mut tar = Archive::new(GzDecoder::new(file));
156+
157+
let mut version = None;
158+
let mut git_commit = None;
159+
for entry in tar.entries()? {
160+
let mut entry = entry?;
161+
162+
let dest;
163+
match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) {
164+
Some("version") => dest = &mut version,
165+
Some("git-commit-hash") => dest = &mut git_commit,
166+
_ => continue,
167+
}
168+
let mut buf = String::new();
169+
entry.read_to_string(&mut buf)?;
170+
*dest = Some(buf);
171+
172+
// Short circuit to avoid reading the whole tar file if not necessary.
173+
if version.is_some() && git_commit.is_some() {
174+
break;
175+
}
176+
}
177+
178+
Ok(VersionInfo { version, git_commit, present: true })
179+
}
180+
181+
pub(crate) fn disable_version(&mut self, package: &PkgType) {
182+
match self.versions.get_mut(package) {
183+
Some(version) => {
184+
*version = VersionInfo::default();
185+
}
186+
None => {
187+
self.versions.insert(package.clone(), VersionInfo::default());
188+
}
189+
}
190+
}
191+
90192
pub(crate) fn tarball_name(
91193
&mut self,
92194
package: &PkgType,

0 commit comments

Comments
 (0)