about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-03-17 17:20:46 +0800
committerGitHub <noreply@github.com>2018-03-17 17:20:46 +0800
commitc78426bfc88062ec28664a309ff32d4b3c206a9f (patch)
treef413b0267a94782bb9c072a5f3957913307e5d8b
parenta2289dadb0f7e841dad57b7152bb323edac46e57 (diff)
parent72cb109bec8e73b1568c2f287ed08348453bf534 (diff)
downloadrust-c78426bfc88062ec28664a309ff32d4b3c206a9f.tar.gz
rust-c78426bfc88062ec28664a309ff32d4b3c206a9f.zip
Rollup merge of #49057 - Zoxc:fast-submodules, r=alexcrichton
Faster submodule updating

For the common case when there are no submodules which need updating, this takes 0.48 seconds instead of 47 seconds.

r? @alexcrichton
-rw-r--r--config.toml.example4
-rw-r--r--src/bootstrap/bootstrap.py62
2 files changed, 54 insertions, 12 deletions
diff --git a/config.toml.example b/config.toml.example
index b47f9163c0d..aec5e5a0e2c 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -118,6 +118,10 @@
 # Indicate whether submodules are managed and updated automatically.
 #submodules = true
 
+# Update submodules only when the checked out commit in the submodules differs
+# from what is committed in the main rustc repo.
+#fast-submodules = true
+
 # The path to (or name of) the GDB executable to use. This is only used for
 # executing the debuginfo test suite.
 #gdb = "gdb"
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 11f174a52a6..b55a133501d 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -612,20 +612,55 @@ class RustBuild(object):
             return config
         return default_build_triple()
 
+    def check_submodule(self, module, slow_submodules):
+        if not slow_submodules:
+            checked_out = subprocess.Popen(["git", "rev-parse", "HEAD"],
+                                           cwd=os.path.join(self.rust_root, module),
+                                           stdout=subprocess.PIPE)
+            return checked_out
+        else:
+            return None
+
+    def update_submodule(self, module, checked_out, recorded_submodules):
+        module_path = os.path.join(self.rust_root, module)
+
+        if checked_out != None:
+            default_encoding = sys.getdefaultencoding()
+            checked_out = checked_out.communicate()[0].decode(default_encoding).strip()
+            if recorded_submodules[module] == checked_out:
+                return
+
+        print("Updating submodule", module)
+
+        run(["git", "submodule", "-q", "sync", module],
+            cwd=self.rust_root, verbose=self.verbose)
+        run(["git", "submodule", "update",
+            "--init", "--recursive", module],
+            cwd=self.rust_root, verbose=self.verbose)
+        run(["git", "reset", "-q", "--hard"],
+            cwd=module_path, verbose=self.verbose)
+        run(["git", "clean", "-qdfx"],
+            cwd=module_path, verbose=self.verbose)
+
     def update_submodules(self):
         """Update submodules"""
         if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
                 self.get_toml('submodules') == "false":
             return
-        print('Updating submodules')
+        slow_submodules = self.get_toml('fast-submodule') == "false"
+        start_time = time()
+        if slow_submodules:
+            print('Unconditionally updating all submodules')
+        else:
+            print('Updating only changed submodules')
         default_encoding = sys.getdefaultencoding()
-        run(["git", "submodule", "-q", "sync"], cwd=self.rust_root, verbose=self.verbose)
         submodules = [s.split(' ', 1)[1] for s in subprocess.check_output(
             ["git", "config", "--file",
              os.path.join(self.rust_root, ".gitmodules"),
              "--get-regexp", "path"]
         ).decode(default_encoding).splitlines()]
         filtered_submodules = []
+        submodules_names = []
         for module in submodules:
             if module.endswith("llvm"):
                 if self.get_toml('llvm-config'):
@@ -643,16 +678,19 @@ class RustBuild(object):
                 config = self.get_toml('lld')
                 if config is None or config == 'false':
                     continue
-            filtered_submodules.append(module)
-        run(["git", "submodule", "update",
-             "--init", "--recursive"] + filtered_submodules,
-            cwd=self.rust_root, verbose=self.verbose)
-        run(["git", "submodule", "-q", "foreach", "git",
-             "reset", "-q", "--hard"],
-            cwd=self.rust_root, verbose=self.verbose)
-        run(["git", "submodule", "-q", "foreach", "git",
-             "clean", "-qdfx"],
-            cwd=self.rust_root, verbose=self.verbose)
+            check = self.check_submodule(module, slow_submodules)
+            filtered_submodules.append((module, check))
+            submodules_names.append(module)
+        recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
+                                    cwd=self.rust_root, stdout=subprocess.PIPE)
+        recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
+        recorded_submodules = {}
+        for data in recorded:
+            data = data.split()
+            recorded_submodules[data[3]] = data[2]
+        for module in filtered_submodules:
+            self.update_submodule(module[0], module[1], recorded_submodules)
+        print("Submodules updated in %.2f seconds" % (time() - start_time))
 
     def set_dev_environment(self):
         """Set download URL for development environment"""