Skip to content

Commit de692f1

Browse files
committed
Auto merge of #100557 - dawnofmidnight:tarball-commit-info, r=Mark-Simulacrum
fix: use git-commit-info for version information Fixes #33286. Fixes #86587. This PR changes the current `git-commit-hash` file that `./x.py` dist puts in the `rustc-{version}-src.tar.{x,g}z` to contain the hash, the short hash, and the commit date from which the tarball was created, assuming git was available when it was. It uses this for reading the version so that rustc has all the appropriate metadata. # Testing Testing this is kind of a pain. I did it with something like ```sh ./x.py dist # ensure that `ignore-git` is `false` in config.toml cp ./build/dist/rustc-1.65.0-dev-src.tar.gz ../rustc-1.65.0-dev-src.tar.gz cd .. && tar -xzf rustc-1.65.0-dev-src && cd rustc-1.65.0-dev-src ./x.py build ``` Then, the output of `rustc -vV` with the stage1 compiler should have the `commit-hash` and `commit-date` fields filled, rather than be `unknown`. To be completely sure, you can use `rustc --sysroot` with the stdlib that the original `./x.py dist` made, which will require that the metadata matches.
2 parents a8a847e + fdb3955 commit de692f1

File tree

8 files changed

+127
-47
lines changed

8 files changed

+127
-47
lines changed

config.toml.example

+6
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,12 @@ changelog-seen = 2
525525
# A descriptive string to be appended to `rustc --version` output, which is
526526
# also used in places like debuginfo `DW_AT_producer`. This may be useful for
527527
# supplementary build information, like distro-specific package versions.
528+
#
529+
# The Rust compiler will differentiate between versions of itself, including
530+
# based on this string, which means that if you wish to be compatible with
531+
# upstream Rust you need to set this to "". However, note that if you are not
532+
# actually compatible -- for example if you've backported patches that change
533+
# behavior -- this may lead to miscompilations or other bugs.
528534
#description = <none> (string)
529535

530536
# The root location of the musl installation directory. The library directory

src/bootstrap/channel.rs

+55-8
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
//! `package_vers`, and otherwise indicating to the compiler what it should
66
//! print out as part of its version information.
77
8+
use std::fs;
89
use std::path::Path;
910
use std::process::Command;
1011

1112
use crate::util::output;
13+
use crate::util::t;
1214
use crate::Build;
1315

1416
pub enum GitInfo {
@@ -18,19 +20,25 @@ pub enum GitInfo {
1820
/// If the info should be used (`ignore_git` is false), this will be
1921
/// `Some`, otherwise it will be `None`.
2022
Present(Option<Info>),
23+
/// This is not a git repostory, but the info can be fetched from the
24+
/// `git-commit-info` file.
25+
RecordedForTarball(Info),
2126
}
2227

2328
pub struct Info {
24-
commit_date: String,
25-
sha: String,
26-
short_sha: String,
29+
pub commit_date: String,
30+
pub sha: String,
31+
pub short_sha: String,
2732
}
2833

2934
impl GitInfo {
3035
pub fn new(ignore_git: bool, dir: &Path) -> GitInfo {
3136
// See if this even begins to look like a git dir
3237
if !dir.join(".git").exists() {
33-
return GitInfo::Absent;
38+
match read_commit_info_file(dir) {
39+
Some(info) => return GitInfo::RecordedForTarball(info),
40+
None => return GitInfo::Absent,
41+
}
3442
}
3543

3644
// Make sure git commands work
@@ -65,10 +73,11 @@ impl GitInfo {
6573
}))
6674
}
6775

68-
fn info(&self) -> Option<&Info> {
76+
pub fn info(&self) -> Option<&Info> {
6977
match self {
70-
GitInfo::Present(info) => info.as_ref(),
7178
GitInfo::Absent => None,
79+
GitInfo::Present(info) => info.as_ref(),
80+
GitInfo::RecordedForTarball(info) => Some(info),
7281
}
7382
}
7483

@@ -96,10 +105,48 @@ impl GitInfo {
96105
version
97106
}
98107

99-
pub fn is_git(&self) -> bool {
108+
/// Returns whether this directory has a `.git` directory which should be managed by bootstrap.
109+
pub fn is_managed_git_subrepository(&self) -> bool {
100110
match self {
101-
GitInfo::Absent => false,
111+
GitInfo::Absent | GitInfo::RecordedForTarball(_) => false,
102112
GitInfo::Present(_) => true,
103113
}
104114
}
115+
116+
/// Returns whether this is being built from a tarball.
117+
pub fn is_from_tarball(&self) -> bool {
118+
match self {
119+
GitInfo::Absent | GitInfo::Present(_) => false,
120+
GitInfo::RecordedForTarball(_) => true,
121+
}
122+
}
123+
}
124+
125+
/// Read the commit information from the `git-commit-info` file given the
126+
/// project root.
127+
pub fn read_commit_info_file(root: &Path) -> Option<Info> {
128+
if let Ok(contents) = fs::read_to_string(root.join("git-commit-info")) {
129+
let mut lines = contents.lines();
130+
let sha = lines.next();
131+
let short_sha = lines.next();
132+
let commit_date = lines.next();
133+
let info = match (commit_date, sha, short_sha) {
134+
(Some(commit_date), Some(sha), Some(short_sha)) => Info {
135+
commit_date: commit_date.to_owned(),
136+
sha: sha.to_owned(),
137+
short_sha: short_sha.to_owned(),
138+
},
139+
_ => panic!("the `git-comit-info` file is malformed"),
140+
};
141+
Some(info)
142+
} else {
143+
None
144+
}
145+
}
146+
147+
/// Write the commit information to the `git-commit-info` file given the project
148+
/// root.
149+
pub fn write_commit_info_file(root: &Path, info: &Info) {
150+
let commit_info = format!("{}\n{}\n{}\n", info.sha, info.short_sha, info.commit_date);
151+
t!(fs::write(root.join("git-commit-info"), &commit_info));
105152
}

src/bootstrap/config.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -1334,11 +1334,22 @@ impl Config {
13341334
git
13351335
}
13361336

1337-
pub(crate) fn artifact_channel(&self, commit: &str) -> String {
1338-
let mut channel = self.git();
1339-
channel.arg("show").arg(format!("{}:src/ci/channel", commit));
1340-
let channel = output(&mut channel);
1341-
channel.trim().to_owned()
1337+
pub(crate) fn artifact_channel(&self, builder: &Builder<'_>, commit: &str) -> String {
1338+
if builder.rust_info.is_managed_git_subrepository() {
1339+
let mut channel = self.git();
1340+
channel.arg("show").arg(format!("{}:src/ci/channel", commit));
1341+
let channel = output(&mut channel);
1342+
channel.trim().to_owned()
1343+
} else if let Ok(channel) = fs::read_to_string(builder.src.join("src/ci/channel")) {
1344+
channel.trim().to_owned()
1345+
} else {
1346+
let src = builder.src.display();
1347+
eprintln!("error: failed to determine artifact channel");
1348+
eprintln!(
1349+
"help: either use git or ensure that {src}/src/ci/channel contains the name of the channel to use"
1350+
);
1351+
panic!();
1352+
}
13421353
}
13431354

13441355
/// Try to find the relative path of `bindir`, otherwise return it in full.
@@ -1475,7 +1486,7 @@ impl Config {
14751486
}
14761487

14771488
pub fn submodules(&self, rust_info: &GitInfo) -> bool {
1478-
self.submodules.unwrap_or(rust_info.is_git())
1489+
self.submodules.unwrap_or(rust_info.is_managed_git_subrepository())
14791490
}
14801491
}
14811492

@@ -1580,7 +1591,7 @@ fn maybe_download_rustfmt(builder: &Builder<'_>) -> Option<PathBuf> {
15801591

15811592
fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
15821593
builder.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})"));
1583-
let channel = builder.config.artifact_channel(commit);
1594+
let channel = builder.config.artifact_channel(builder, commit);
15841595
let host = builder.config.build.triple;
15851596
let bin_root = builder.out.join(host).join("ci-rustc");
15861597
let rustc_stamp = bin_root.join(".rustc-stamp");

src/bootstrap/dist.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::process::Command;
1616

1717
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
1818
use crate::cache::{Interned, INTERNER};
19+
use crate::channel;
1920
use crate::compile;
2021
use crate::config::TargetSelection;
2122
use crate::tarball::{GeneratedTarball, OverlayKind, Tarball};
@@ -918,12 +919,12 @@ impl Step for PlainSourceTarball {
918919

919920
// Create the version file
920921
builder.create(&plain_dst_src.join("version"), &builder.rust_version());
921-
if let Some(sha) = builder.rust_sha() {
922-
builder.create(&plain_dst_src.join("git-commit-hash"), &sha);
922+
if let Some(info) = builder.rust_info.info() {
923+
channel::write_commit_info_file(&plain_dst_src, info);
923924
}
924925

925926
// If we're building from git sources, we need to vendor a complete distribution.
926-
if builder.rust_info.is_git() {
927+
if builder.rust_info.is_managed_git_subrepository() {
927928
// Ensure we have the submodules checked out.
928929
builder.update_submodule(Path::new("src/tools/rust-analyzer"));
929930

src/bootstrap/lib.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ impl Build {
400400
/// line and the filesystem `config`.
401401
///
402402
/// By default all build output will be placed in the current directory.
403-
pub fn new(config: Config) -> Build {
403+
pub fn new(mut config: Config) -> Build {
404404
let src = config.src.clone();
405405
let out = config.out.clone();
406406

@@ -474,6 +474,10 @@ impl Build {
474474
)
475475
}
476476

477+
if rust_info.is_from_tarball() && config.description.is_none() {
478+
config.description = Some("built from a source tarball".to_owned());
479+
}
480+
477481
let mut build = Build {
478482
initial_rustc: config.initial_rustc.clone(),
479483
initial_cargo: config.initial_cargo.clone(),
@@ -573,7 +577,9 @@ impl Build {
573577

574578
// NOTE: The check for the empty directory is here because when running x.py the first time,
575579
// the submodule won't be checked out. Check it out now so we can build it.
576-
if !channel::GitInfo::new(false, &absolute_path).is_git() && !dir_is_empty(&absolute_path) {
580+
if !channel::GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
581+
&& !dir_is_empty(&absolute_path)
582+
{
577583
return;
578584
}
579585

@@ -644,7 +650,7 @@ impl Build {
644650
// Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
645651
let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
646652
// Don't update the submodule unless it's already been cloned.
647-
if channel::GitInfo::new(false, submodule).is_git() {
653+
if channel::GitInfo::new(false, submodule).is_managed_git_subrepository() {
648654
self.update_submodule(submodule);
649655
}
650656
}
@@ -1260,7 +1266,7 @@ impl Build {
12601266
match &self.config.channel[..] {
12611267
"stable" => num.to_string(),
12621268
"beta" => {
1263-
if self.rust_info.is_git() && !self.config.ignore_git {
1269+
if self.rust_info.is_managed_git_subrepository() && !self.config.ignore_git {
12641270
format!("{}-beta.{}", num, self.beta_prerelease_version())
12651271
} else {
12661272
format!("{}-beta", num)

src/bootstrap/native.rs

+30-22
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::path::{Path, PathBuf};
1717
use std::process::Command;
1818

1919
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
20+
use crate::channel;
2021
use crate::config::TargetSelection;
2122
use crate::util::get_clang_cl_resource_dir;
2223
use crate::util::{self, exe, output, program_out_of_date, t, up_to_date};
@@ -115,32 +116,37 @@ pub fn prebuilt_llvm_config(
115116
}
116117

117118
/// This retrieves the LLVM sha we *want* to use, according to git history.
118-
pub(crate) fn detect_llvm_sha(config: &crate::config::Config) -> String {
119-
let mut rev_list = config.git();
120-
rev_list.args(&[
121-
PathBuf::from("rev-list"),
122-
format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
123-
"-n1".into(),
124-
"--first-parent".into(),
125-
"HEAD".into(),
126-
"--".into(),
127-
config.src.join("src/llvm-project"),
128-
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
129-
// the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
130-
config.src.join("src/version"),
131-
]);
132-
let llvm_sha = output(&mut rev_list);
133-
let llvm_sha = llvm_sha.trim();
134-
135-
if llvm_sha == "" {
119+
pub(crate) fn detect_llvm_sha(config: &crate::config::Config, is_git: bool) -> String {
120+
let llvm_sha = if is_git {
121+
let mut rev_list = config.git();
122+
rev_list.args(&[
123+
PathBuf::from("rev-list"),
124+
format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
125+
"-n1".into(),
126+
"--first-parent".into(),
127+
"HEAD".into(),
128+
"--".into(),
129+
config.src.join("src/llvm-project"),
130+
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
131+
// the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
132+
config.src.join("src/version"),
133+
]);
134+
output(&mut rev_list).trim().to_owned()
135+
} else if let Some(info) = channel::read_commit_info_file(&config.src) {
136+
info.sha.trim().to_owned()
137+
} else {
138+
"".to_owned()
139+
};
140+
141+
if &llvm_sha == "" {
136142
eprintln!("error: could not find commit hash for downloading LLVM");
137143
eprintln!("help: maybe your repository history is too shallow?");
138144
eprintln!("help: consider disabling `download-ci-llvm`");
139145
eprintln!("help: or fetch enough history to include one upstream commit");
140146
panic!();
141147
}
142148

143-
llvm_sha.to_owned()
149+
llvm_sha
144150
}
145151

146152
/// Returns whether the CI-found LLVM is currently usable.
@@ -194,7 +200,9 @@ pub(crate) fn is_ci_llvm_available(config: &crate::config::Config, asserts: bool
194200
}
195201

196202
if crate::util::CiEnv::is_ci() {
197-
let llvm_sha = detect_llvm_sha(config);
203+
// We assume we have access to git, so it's okay to unconditionally pass
204+
// `true` here.
205+
let llvm_sha = detect_llvm_sha(config, true);
198206
let head_sha = output(config.git().arg("rev-parse").arg("HEAD"));
199207
let head_sha = head_sha.trim();
200208
if llvm_sha == head_sha {
@@ -215,7 +223,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
215223
}
216224
let llvm_root = config.ci_llvm_root();
217225
let llvm_stamp = llvm_root.join(".llvm-stamp");
218-
let llvm_sha = detect_llvm_sha(&config);
226+
let llvm_sha = detect_llvm_sha(&config, builder.rust_info.is_managed_git_subrepository());
219227
let key = format!("{}{}", llvm_sha, config.llvm_assertions);
220228
if program_out_of_date(&llvm_stamp, &key) && !config.dry_run {
221229
download_ci_llvm(builder, &llvm_sha);
@@ -260,7 +268,7 @@ fn download_ci_llvm(builder: &Builder<'_>, llvm_sha: &str) {
260268
} else {
261269
&builder.config.stage0_metadata.config.artifacts_server
262270
};
263-
let channel = builder.config.artifact_channel(llvm_sha);
271+
let channel = builder.config.artifact_channel(builder, llvm_sha);
264272
let filename = format!("rust-dev-{}-{}.tar.xz", channel, builder.build.build.triple);
265273
let tarball = rustc_cache.join(&filename);
266274
if !tarball.exists() {

src/bootstrap/sanity.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub fn check(build: &mut Build) {
7474
let mut cmd_finder = Finder::new();
7575
// If we've got a git directory we're gonna need git to update
7676
// submodules and learn about various other aspects.
77-
if build.rust_info.is_git() {
77+
if build.rust_info.is_managed_git_subrepository() {
7878
cmd_finder.must_have("git");
7979
}
8080

src/bootstrap/tarball.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
};
55

66
use crate::builder::Builder;
7+
use crate::channel;
78
use crate::util::t;
89

910
#[derive(Copy, Clone)]
@@ -297,8 +298,8 @@ impl<'a> Tarball<'a> {
297298
fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTarball {
298299
t!(std::fs::create_dir_all(&self.overlay_dir));
299300
self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder));
300-
if let Some(sha) = self.builder.rust_sha() {
301-
self.builder.create(&self.overlay_dir.join("git-commit-hash"), &sha);
301+
if let Some(info) = self.builder.rust_info.info() {
302+
channel::write_commit_info_file(&self.overlay_dir, info);
302303
}
303304
for file in self.overlay.legal_and_readme() {
304305
self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);

0 commit comments

Comments
 (0)