Skip to content

Commit

Permalink
fix checking git submodules during a commit hook
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jun 11, 2024
1 parent d402830 commit f768fc8
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 45 deletions.
61 changes: 29 additions & 32 deletions src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,12 @@ impl Build {
if !self.config.submodules(self.rust_info()) {
return;
}
if env::var_os("GIT_DIR").is_some() {
// GIT_DIR is set when we are running inside a git invocation, e.g. in a commit hook.
// Skip submodule processing as messing with the git state here can have "fun" results.
// Also see the discussion in <https://github.com/rust-lang/rust/pull/126255>.
return;
}

let absolute_path = self.config.src.join(relative_path);

Expand All @@ -520,34 +526,29 @@ impl Build {
return;
}

// check_submodule
let checked_out_hash =
output(Command::new("git").args(["rev-parse", "HEAD"]).current_dir(&absolute_path));
// update_submodules
let recorded = output(
Command::new("git")
.args(["ls-tree", "HEAD"])
.arg(relative_path)
.current_dir(&self.config.src),
);
let submodule_git = || {
let mut cmd = Command::new("git");
cmd.current_dir(&absolute_path);
cmd
};

// Determine commit checked out in submodule.
let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]));
let checked_out_hash = checked_out_hash.trim_end();
// Determine commit that the submodule *should* have.
let recorded = output(self.config.git().args(["ls-tree", "HEAD"]).arg(relative_path));
let actual_hash = recorded
.split_whitespace()
.nth(2)
.unwrap_or_else(|| panic!("unexpected output `{}`", recorded));

// update_submodule
if actual_hash == checked_out_hash.trim_end() {
if actual_hash == checked_out_hash {
// already checked out
return;
}

println!("Updating submodule {}", relative_path.display());
self.run(
Command::new("git")
.args(["submodule", "-q", "sync"])
.arg(relative_path)
.current_dir(&self.config.src),
);
self.run(self.config.git().args(["submodule", "-q", "sync"]).arg(relative_path));

// Try passing `--progress` to start, then run git again without if that fails.
let update = |progress: bool| {
Expand Down Expand Up @@ -590,26 +591,22 @@ impl Build {
// Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error).
// diff-index reports the modifications through the exit status
let has_local_modifications = !self.run_cmd(
BootstrapCommand::from(
Command::new("git")
.args(["diff-index", "--quiet", "HEAD"])
.current_dir(&absolute_path),
)
.allow_failure()
.output_mode(match self.is_verbose() {
true => OutputMode::PrintAll,
false => OutputMode::PrintOutput,
}),
BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"]))
.allow_failure()
.output_mode(match self.is_verbose() {
true => OutputMode::PrintAll,
false => OutputMode::PrintOutput,
}),
);
if has_local_modifications {
self.run(Command::new("git").args(["stash", "push"]).current_dir(&absolute_path));
self.run(submodule_git().args(["stash", "push"]));
}

self.run(Command::new("git").args(["reset", "-q", "--hard"]).current_dir(&absolute_path));
self.run(Command::new("git").args(["clean", "-qdfx"]).current_dir(&absolute_path));
self.run(submodule_git().args(["reset", "-q", "--hard"]));
self.run(submodule_git().args(["clean", "-qdfx"]));

if has_local_modifications {
self.run(Command::new("git").args(["stash", "pop"]).current_dir(absolute_path));
self.run(submodule_git().args(["stash", "pop"]));
}
}

Expand Down
26 changes: 13 additions & 13 deletions src/bootstrap/src/utils/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,17 @@ impl GitInfo {
None => return GitInfo::Absent,
}
}
let git = || {
let mut cmd = Command::new("git");
cmd.current_dir(dir);
// If we are running inside git (e.g. via a hook), `GIT_DIR` is set and takes precedence
// over the current dir. Un-set it to make the current dir matter.
cmd.env_remove("GIT_DIR");
cmd
};

// Make sure git commands work
match Command::new("git").arg("rev-parse").current_dir(dir).output() {
match git().arg("rev-parse").output() {
Ok(ref out) if out.status.success() => {}
_ => return GitInfo::Absent,
}
Expand All @@ -56,18 +64,10 @@ impl GitInfo {
}

// Ok, let's scrape some info
let ver_date = output(
Command::new("git")
.current_dir(dir)
.arg("log")
.arg("-1")
.arg("--date=short")
.arg("--pretty=format:%cd"),
);
let ver_hash = output(Command::new("git").current_dir(dir).arg("rev-parse").arg("HEAD"));
let short_ver_hash = output(
Command::new("git").current_dir(dir).arg("rev-parse").arg("--short=9").arg("HEAD"),
);
let ver_date =
output(git().arg("log").arg("-1").arg("--date=short").arg("--pretty=format:%cd"));
let ver_hash = output(git().arg("rev-parse").arg("HEAD"));
let short_ver_hash = output(git().arg("rev-parse").arg("--short=9").arg("HEAD"));
GitInfo::Present(Some(Info {
commit_date: ver_date.trim().to_string(),
sha: ver_hash.trim().to_string(),
Expand Down

0 comments on commit f768fc8

Please sign in to comment.