Skip to content

Commit 0e58792

Browse files
committed
Allow using download-ci-llvm = true outside the git checkout
@bjorn3 noticed that this is already allowed today when download-llvm is disabled, but breaks with it enabled: ``` $ ./rust2/x.py build fatal: not a git repository (or any of the parent directories): .git thread 'main' panicked at 'command did not execute successfully: "git" "rev-list" "[email protected]" "-n1" "--first-parent" "HEAD" "--" "/home/jnelson/rust-lang/rust2/src/llvm-project" "/home/jnelson/rust-lang/rust2/src/bootstrap/download-ci-llvm-stamp" "/home/jnelson/rust-lang/rust2/src/version" expected success, got: exit status: 128', src/bootstrap/native.rs:134:20 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` Support it too for consistency. It's unclear to me when anyone would need to use this, but @bjorn3 feels we should support it, and it's not much additional effort to get it working. This also updates a bunch of other git commands that were similarly depending on the current directory.
1 parent a09c668 commit 0e58792

File tree

6 files changed

+52
-50
lines changed

6 files changed

+52
-50
lines changed

src/bootstrap/config.rs

+18-12
Original file line numberDiff line numberDiff line change
@@ -1128,11 +1128,7 @@ impl Config {
11281128
config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
11291129
config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
11301130
config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
1131-
config.download_rustc_commit = download_ci_rustc_commit(
1132-
&config.stage0_metadata,
1133-
rust.download_rustc,
1134-
config.verbose > 0,
1135-
);
1131+
config.download_rustc_commit = download_ci_rustc_commit(&config, rust.download_rustc);
11361132
} else {
11371133
config.rust_profile_use = flags.rust_profile_use;
11381134
config.rust_profile_generate = flags.rust_profile_generate;
@@ -1304,6 +1300,15 @@ impl Config {
13041300
config
13051301
}
13061302

1303+
/// A git invocation which runs inside the source directory.
1304+
///
1305+
/// Use this rather than `Command::new("git")` in order to support out-of-tree builds.
1306+
pub(crate) fn git(&self) -> Command {
1307+
let mut git = Command::new("git");
1308+
git.current_dir(&self.src);
1309+
git
1310+
}
1311+
13071312
/// Try to find the relative path of `bindir`, otherwise return it in full.
13081313
pub fn bindir_relative(&self) -> &Path {
13091314
let bindir = &self.bindir;
@@ -1453,9 +1458,8 @@ fn threads_from_config(v: u32) -> u32 {
14531458

14541459
/// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
14551460
fn download_ci_rustc_commit(
1456-
stage0_metadata: &Stage0Metadata,
1461+
config: &Config,
14571462
download_rustc: Option<StringOrBool>,
1458-
verbose: bool,
14591463
) -> Option<String> {
14601464
// If `download-rustc` is not set, default to rebuilding.
14611465
let if_unchanged = match download_rustc {
@@ -1468,17 +1472,18 @@ fn download_ci_rustc_commit(
14681472
};
14691473

14701474
// Handle running from a directory other than the top level
1471-
let top_level = output(Command::new("git").args(&["rev-parse", "--show-toplevel"]));
1475+
let top_level = output(config.git().args(&["rev-parse", "--show-toplevel"]));
14721476
let top_level = top_level.trim_end();
14731477
let compiler = format!("{top_level}/compiler/");
14741478
let library = format!("{top_level}/library/");
14751479

14761480
// Look for a version to compare to based on the current commit.
14771481
// Only commits merged by bors will have CI artifacts.
14781482
let merge_base = output(
1479-
Command::new("git")
1483+
config
1484+
.git()
14801485
.arg("rev-list")
1481-
.arg(format!("--author={}", stage0_metadata.config.git_merge_commit_email))
1486+
.arg(format!("--author={}", config.stage0_metadata.config.git_merge_commit_email))
14821487
.args(&["-n1", "--first-parent", "HEAD"]),
14831488
);
14841489
let commit = merge_base.trim_end();
@@ -1491,13 +1496,14 @@ fn download_ci_rustc_commit(
14911496
}
14921497

14931498
// Warn if there were changes to the compiler or standard library since the ancestor commit.
1494-
let has_changes = !t!(Command::new("git")
1499+
let has_changes = !t!(config
1500+
.git()
14951501
.args(&["diff-index", "--quiet", &commit, "--", &compiler, &library])
14961502
.status())
14971503
.success();
14981504
if has_changes {
14991505
if if_unchanged {
1500-
if verbose {
1506+
if config.verbose > 0 {
15011507
println!(
15021508
"warning: saw changes to compiler/ or library/ since {commit}; \
15031509
ignoring `download-rustc`"

src/bootstrap/format.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
7272
Err(_) => false,
7373
};
7474
if git_available {
75-
let in_working_tree = match Command::new("git")
75+
let in_working_tree = match build
76+
.config
77+
.git()
7678
.arg("rev-parse")
7779
.arg("--is-inside-work-tree")
7880
.stdout(Stdio::null())
@@ -84,10 +86,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
8486
};
8587
if in_working_tree {
8688
let untracked_paths_output = output(
87-
Command::new("git")
88-
.arg("status")
89-
.arg("--porcelain")
90-
.arg("--untracked-files=normal"),
89+
build.config.git().arg("status").arg("--porcelain").arg("--untracked-files=normal"),
9190
);
9291
let untracked_paths = untracked_paths_output
9392
.lines()

src/bootstrap/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,8 @@ impl Build {
634634
return;
635635
}
636636
let output = output(
637-
Command::new("git")
637+
self.config
638+
.git()
638639
.args(&["config", "--file"])
639640
.arg(&self.config.src.join(".gitmodules"))
640641
.args(&["--get-regexp", "path"]),
@@ -1271,12 +1272,12 @@ impl Build {
12711272
// That's our beta number!
12721273
// (Note that we use a `..` range, not the `...` symmetric difference.)
12731274
let count = output(
1274-
Command::new("git")
1275+
self.config
1276+
.git()
12751277
.arg("rev-list")
12761278
.arg("--count")
12771279
.arg("--merges")
1278-
.arg("refs/remotes/origin/master..HEAD")
1279-
.current_dir(&self.src),
1280+
.arg("refs/remotes/origin/master..HEAD"),
12801281
);
12811282
let n = count.trim().parse().unwrap();
12821283
self.prerelease_version.set(Some(n));

src/bootstrap/native.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
118118
if !config.llvm_from_ci {
119119
return;
120120
}
121-
let mut rev_list = Command::new("git");
121+
let mut rev_list = config.git();
122122
rev_list.args(&[
123123
PathBuf::from("rev-list"),
124124
format!("--author={}", builder.config.stage0_metadata.config.git_merge_commit_email).into(),

src/bootstrap/setup.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub fn setup(config: &Config, profile: Profile) {
136136

137137
println!();
138138

139-
t!(install_git_hook_maybe(&config.src));
139+
t!(install_git_hook_maybe(&config));
140140

141141
println!();
142142

@@ -302,7 +302,7 @@ pub fn interactive_path() -> io::Result<Profile> {
302302
}
303303

304304
// install a git hook to automatically run tidy --bless, if they want
305-
fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
305+
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
306306
let mut input = String::new();
307307
println!(
308308
"Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
@@ -328,13 +328,12 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
328328
};
329329

330330
if should_install {
331-
let src = src_path.join("src").join("etc").join("pre-push.sh");
332-
let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map(
333-
|output| {
331+
let src = config.src.join("src").join("etc").join("pre-push.sh");
332+
let git =
333+
t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
334334
assert!(output.status.success(), "failed to run `git`");
335335
PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
336-
}
337-
));
336+
}));
338337
let dst = git.join("hooks").join("pre-push");
339338
match fs::hard_link(src, &dst) {
340339
Err(e) => eprintln!(

src/bootstrap/toolstate.rs

+18-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
22
use crate::util::t;
3+
use crate::Config;
34
use serde::{Deserialize, Serialize};
45
use std::collections::HashMap;
56
use std::env;
@@ -96,14 +97,9 @@ fn print_error(tool: &str, submodule: &str) {
9697
std::process::exit(3);
9798
}
9899

99-
fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
100+
fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>, config: &Config) {
100101
// Changed files
101-
let output = std::process::Command::new("git")
102-
.arg("diff")
103-
.arg("--name-status")
104-
.arg("HEAD")
105-
.arg("HEAD^")
106-
.output();
102+
let output = config.git().arg("diff").arg("--name-status").arg("HEAD").arg("HEAD^").output();
107103
let output = match output {
108104
Ok(o) => o,
109105
Err(e) => {
@@ -182,8 +178,8 @@ impl Step for ToolStateCheck {
182178
std::process::exit(1);
183179
}
184180

185-
check_changed_files(&toolstates);
186-
checkout_toolstate_repo();
181+
check_changed_files(&toolstates, &builder.config);
182+
checkout_toolstate_repo(&builder.config);
187183
let old_toolstate = read_old_toolstate();
188184

189185
for (tool, _) in STABLE_TOOLS.iter() {
@@ -229,7 +225,7 @@ impl Step for ToolStateCheck {
229225
}
230226

231227
if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() {
232-
commit_toolstate_change(&toolstates);
228+
commit_toolstate_change(&toolstates, &builder.config);
233229
}
234230
}
235231

@@ -302,16 +298,17 @@ fn toolstate_repo() -> String {
302298
const TOOLSTATE_DIR: &str = "rust-toolstate";
303299

304300
/// Checks out the toolstate repo into `TOOLSTATE_DIR`.
305-
fn checkout_toolstate_repo() {
301+
fn checkout_toolstate_repo(config: &Config) {
306302
if let Ok(token) = env::var("TOOLSTATE_REPO_ACCESS_TOKEN") {
307-
prepare_toolstate_config(&token);
303+
prepare_toolstate_config(&token, config);
308304
}
309305
if Path::new(TOOLSTATE_DIR).exists() {
310306
eprintln!("Cleaning old toolstate directory...");
311307
t!(fs::remove_dir_all(TOOLSTATE_DIR));
312308
}
313309

314-
let status = Command::new("git")
310+
let status = config
311+
.git()
315312
.arg("clone")
316313
.arg("--depth=1")
317314
.arg(toolstate_repo())
@@ -327,17 +324,17 @@ fn checkout_toolstate_repo() {
327324
}
328325

329326
/// Sets up config and authentication for modifying the toolstate repo.
330-
fn prepare_toolstate_config(token: &str) {
331-
fn git_config(key: &str, value: &str) {
332-
let status = Command::new("git").arg("config").arg("--global").arg(key).arg(value).status();
327+
fn prepare_toolstate_config(token: &str, config: &Config) {
328+
let git_config = |key: &str, value: &str| {
329+
let status = config.git().arg("config").arg("--global").arg(key).arg(value).status();
333330
let success = match status {
334331
Ok(s) => s.success(),
335332
Err(_) => false,
336333
};
337334
if !success {
338335
panic!("git config key={} value={} failed (status: {:?})", key, value, status);
339336
}
340-
}
337+
};
341338

342339
// If changing anything here, then please check that `src/ci/publish_toolstate.sh` is up to date
343340
// as well.
@@ -383,14 +380,14 @@ fn read_old_toolstate() -> Vec<RepoState> {
383380
///
384381
/// * See <https://help.github.com/articles/about-commit-email-addresses/>
385382
/// if a private email by GitHub is wanted.
386-
fn commit_toolstate_change(current_toolstate: &ToolstateData) {
383+
fn commit_toolstate_change(current_toolstate: &ToolstateData, config: &Config) {
387384
let message = format!("({} CI update)", OS.expect("linux/windows only"));
388385
let mut success = false;
389386
for _ in 1..=5 {
390387
// Upload the test results (the new commit-to-toolstate mapping) to the toolstate repo.
391388
// This does *not* change the "current toolstate"; that only happens post-landing
392389
// via `src/ci/docker/publish_toolstate.sh`.
393-
publish_test_results(&current_toolstate);
390+
publish_test_results(&current_toolstate, config);
394391

395392
// `git commit` failing means nothing to commit.
396393
let status = t!(Command::new("git")
@@ -444,8 +441,8 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
444441
/// These results will later be promoted to `latest.json` by the
445442
/// `publish_toolstate.py` script if the PR passes all tests and is merged to
446443
/// master.
447-
fn publish_test_results(current_toolstate: &ToolstateData) {
448-
let commit = t!(std::process::Command::new("git").arg("rev-parse").arg("HEAD").output());
444+
fn publish_test_results(current_toolstate: &ToolstateData, config: &Config) {
445+
let commit = t!(config.git().arg("rev-parse").arg("HEAD").output());
449446
let commit = t!(String::from_utf8(commit.stdout));
450447

451448
let toolstate_serialized = t!(serde_json::to_string(&current_toolstate));

0 commit comments

Comments
 (0)