Skip to content

Commit a375799

Browse files
author
Jorge Aparicio
committed
rustbuild: smarter git submodule-ing
With this commit, if one bootstraps rust against system llvm then the src/llvm submodule is not updated/checked-out. This saves considerable network bandwith when starting from a fresh clone of rust-lang/rust as the llvm submodule is never cloned. cc #30107
1 parent 1194695 commit a375799

File tree

1 file changed

+72
-11
lines changed

1 file changed

+72
-11
lines changed

src/bootstrap/lib.rs

+72-11
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use std::cell::RefCell;
3232
use std::collections::HashMap;
3333
use std::env;
3434
use std::fs::{self, File};
35-
use std::path::{PathBuf, Path};
35+
use std::path::{Component, PathBuf, Path};
3636
use std::process::Command;
3737

3838
use build_helper::{run_silent, output};
@@ -475,12 +475,32 @@ impl Build {
475475
/// This will detect if any submodules are out of date an run the necessary
476476
/// commands to sync them all with upstream.
477477
fn update_submodules(&self) {
478+
struct Submodule<'a> {
479+
path: &'a Path,
480+
state: State,
481+
}
482+
483+
enum State {
484+
// The submodule may have staged/unstaged changes
485+
MaybeDirty,
486+
// Or could be initialized but never updated
487+
NotInitialized,
488+
// The submodule, itself, has extra commits but those changes haven't been commited to
489+
// the (outer) git repository
490+
OutOfSync,
491+
}
492+
478493
if !self.config.submodules {
479494
return
480495
}
481496
if fs::metadata(self.src.join(".git")).is_err() {
482497
return
483498
}
499+
let git = || {
500+
let mut cmd = Command::new("git");
501+
cmd.current_dir(&self.src);
502+
return cmd
503+
};
484504
let git_submodule = || {
485505
let mut cmd = Command::new("git");
486506
cmd.current_dir(&self.src).arg("submodule");
@@ -492,19 +512,60 @@ impl Build {
492512
// of detecting whether we need to run all the submodule commands
493513
// below.
494514
let out = output(git_submodule().arg("status"));
495-
if !out.lines().any(|l| l.starts_with("+") || l.starts_with("-")) {
496-
return
515+
let mut submodules = vec![];
516+
for line in out.lines() {
517+
// NOTE `git submodule status` output looks like this:
518+
//
519+
// -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc
520+
// +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/rust-llvm-2016-07-18-1-gb37ef24)
521+
// e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6)
522+
//
523+
// The first character can be '-', '+' or ' ' and denotes the `State` of the submodule
524+
// Right next to this character is the SHA-1 of the submodule HEAD
525+
// And after that comes the path to the submodule
526+
let path = Path::new(line[1..].split(' ').skip(1).next().unwrap());
527+
let state = if line.starts_with('-') {
528+
State::NotInitialized
529+
} else if line.starts_with('*') {
530+
State::OutOfSync
531+
} else if line.starts_with(' ') {
532+
State::MaybeDirty
533+
} else {
534+
panic!("unexpected git submodule state: {:?}", line.chars().next());
535+
};
536+
537+
submodules.push(Submodule { path: path, state: state })
497538
}
498539

499540
self.run(git_submodule().arg("sync"));
500-
self.run(git_submodule().arg("init"));
501-
self.run(git_submodule().arg("update"));
502-
self.run(git_submodule().arg("update").arg("--recursive"));
503-
self.run(git_submodule().arg("status").arg("--recursive"));
504-
self.run(git_submodule().arg("foreach").arg("--recursive")
505-
.arg("git").arg("clean").arg("-fdx"));
506-
self.run(git_submodule().arg("foreach").arg("--recursive")
507-
.arg("git").arg("checkout").arg("."));
541+
542+
for submodule in submodules {
543+
// If using llvm-root then don't touch the llvm submodule.
544+
if submodule.path.components().any(|c| c == Component::Normal("llvm".as_ref())) &&
545+
self.config.target_config.get(&self.config.build).and_then(|c| c.llvm_config.as_ref()).is_some()
546+
{
547+
continue
548+
}
549+
550+
match submodule.state {
551+
State::MaybeDirty => {
552+
// drop staged changes
553+
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
554+
// drops unstaged changes
555+
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
556+
},
557+
State::NotInitialized => {
558+
self.run(git_submodule().arg("init").arg(submodule.path));
559+
self.run(git_submodule().arg("update").arg(submodule.path));
560+
},
561+
State::OutOfSync => {
562+
// drops submodule commits that weren't reported to the (outer) git repository
563+
self.run(git_submodule().arg("update").arg(submodule.path));
564+
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
565+
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
566+
},
567+
}
568+
}
508569
}
509570

510571
/// Clear out `dir` if `input` is newer.

0 commit comments

Comments
 (0)