Skip to content

Commit b861629

Browse files
committed
Auto merge of #13832 - ferrocene:pa-source-tarball-git, r=weihanglo
Populate git information when building Cargo from Rust's source tarball ### What does this PR try to resolve? Right now Cargo doesn't populate the commit hash or date in its version output when it's built from Rust's plain source tarball (like `rustc-1.77.2-src.tar.xz`). That's because Cargo's build script only looks for information in the `.git` directory, which is missing from that tarball. I opened rust-lang/rust#124553 to have bootstrap inject a `git-commit-info` file in `src/tools/cargo` when building the plain source tarball, containing the correct git information. This is the approach also used by the compiler. This PR updates the build script to read the information from that file if there is no `.git` and the file is present. ### How should we test and review this PR? To test the PR you need to move the `.git` directory somewhere else and create a `git-commit-info` file like this: ``` 25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04 25ef9e3d8 2024-04-09 ``` Then clearing the build cache and running `cargo run -- -vV` should show the git information in the `git-commit-info` file. ### Additional information This PR can be merged independently from rust-lang/rust#124553
2 parents 05066fe + bd752e9 commit b861629

File tree

1 file changed

+66
-15
lines changed

1 file changed

+66
-15
lines changed

build.rs

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,15 @@ fn compress_man() {
4747
encoder.finish().unwrap();
4848
}
4949

50-
fn commit_info() {
51-
if !Path::new(".git").exists() {
52-
return;
53-
}
50+
struct CommitInfo {
51+
hash: String,
52+
short_hash: String,
53+
date: String,
54+
}
5455

55-
// Var set by bootstrap whenever omit-git-hash is enabled in rust-lang/rust's config.toml.
56-
println!("cargo:rerun-if-env-changed=CFG_OMIT_GIT_HASH");
57-
#[allow(clippy::disallowed_methods)]
58-
if std::env::var_os("CFG_OMIT_GIT_HASH").is_some() {
59-
return;
56+
fn commit_info_from_git() -> Option<CommitInfo> {
57+
if !Path::new(".git").exists() {
58+
return None;
6059
}
6160

6261
let output = match Command::new("git")
@@ -68,14 +67,66 @@ fn commit_info() {
6867
.output()
6968
{
7069
Ok(output) if output.status.success() => output,
71-
_ => return,
70+
_ => return None,
7271
};
72+
7373
let stdout = String::from_utf8(output.stdout).unwrap();
74-
let mut parts = stdout.split_whitespace();
75-
let mut next = || parts.next().unwrap();
76-
println!("cargo:rustc-env=CARGO_COMMIT_HASH={}", next());
77-
println!("cargo:rustc-env=CARGO_COMMIT_SHORT_HASH={}", next());
78-
println!("cargo:rustc-env=CARGO_COMMIT_DATE={}", next())
74+
let mut parts = stdout.split_whitespace().map(|s| s.to_string());
75+
76+
Some(CommitInfo {
77+
hash: parts.next()?,
78+
short_hash: parts.next()?,
79+
date: parts.next()?,
80+
})
81+
}
82+
83+
// The rustc source tarball is meant to contain all the source code to build an exact copy of the
84+
// toolchain, but it doesn't include the git repository itself. It wouldn't thus be possible to
85+
// populate the version information with the commit hash and the commit date.
86+
//
87+
// To work around this, the rustc build process obtains the git information when creating the
88+
// source tarball and writes it to the `git-commit-info` file. The build process actually creates
89+
// at least *two* of those files, one for Rust as a whole (in the root of the tarball) and one
90+
// specifically for Cargo (in src/tools/cargo). This function loads that file.
91+
//
92+
// The file is a newline-separated list of full commit hash, short commit hash, and commit date.
93+
fn commit_info_from_rustc_source_tarball() -> Option<CommitInfo> {
94+
let path = Path::new("git-commit-info");
95+
if !path.exists() {
96+
return None;
97+
}
98+
99+
// Dependency tracking is a nice to have for this (git doesn't do it), so if the path is not
100+
// valid UTF-8 just avoid doing it rather than erroring out.
101+
if let Some(utf8) = path.to_str() {
102+
println!("cargo:rerun-if-changed={utf8}");
103+
}
104+
105+
let content = std::fs::read_to_string(&path).ok()?;
106+
let mut parts = content.split('\n').map(|s| s.to_string());
107+
Some(CommitInfo {
108+
hash: parts.next()?,
109+
short_hash: parts.next()?,
110+
date: parts.next()?,
111+
})
112+
}
113+
114+
fn commit_info() {
115+
// Var set by bootstrap whenever omit-git-hash is enabled in rust-lang/rust's config.toml.
116+
println!("cargo:rerun-if-env-changed=CFG_OMIT_GIT_HASH");
117+
// ALLOWED: Accessing environment during build time shouldn't be prohibited.
118+
#[allow(clippy::disallowed_methods)]
119+
if std::env::var_os("CFG_OMIT_GIT_HASH").is_some() {
120+
return;
121+
}
122+
123+
let Some(git) = commit_info_from_git().or_else(commit_info_from_rustc_source_tarball) else {
124+
return;
125+
};
126+
127+
println!("cargo:rustc-env=CARGO_COMMIT_HASH={}", git.hash);
128+
println!("cargo:rustc-env=CARGO_COMMIT_SHORT_HASH={}", git.short_hash);
129+
println!("cargo:rustc-env=CARGO_COMMIT_DATE={}", git.date);
79130
}
80131

81132
#[allow(clippy::disallowed_methods)]

0 commit comments

Comments
 (0)