]> git.lizzy.rs Git - rust.git/blobdiff - src/bootstrap/bootstrap.py
Rollup merge of #94831 - yaahc:lib-tracking-issue-template-update, r=JohnTitor
[rust.git] / src / bootstrap / bootstrap.py
index 3b2b507b062371a3c8e68d285cfd5d7d4d9ac5aa..3c2f1bdb142a7307896cb7e885d40a1d666f0c76 100644 (file)
@@ -15,44 +15,6 @@ import tempfile
 
 from time import time, sleep
 
-# Acquire a lock on the build directory to make sure that
-# we don't cause a race condition while building
-# Lock is created in `build_dir/lock.db`
-def acquire_lock(build_dir):
-    try:
-        import sqlite3
-
-        path = os.path.join(build_dir, "lock.db")
-        try:
-            con = sqlite3.Connection(path, timeout=0)
-            curs = con.cursor()
-            curs.execute("BEGIN EXCLUSIVE")
-            # The lock is released when the cursor is dropped
-            return curs
-        # If the database is busy then lock has already been acquired
-        # so we wait for the lock.
-        # We retry every quarter second so that execution is passed back to python
-        # so that it can handle signals
-        except sqlite3.OperationalError:
-            del con
-            del curs
-            print("Waiting for lock on build directory")
-            con = sqlite3.Connection(path, timeout=0.25)
-            curs = con.cursor()
-            while True:
-                try:
-                    curs.execute("BEGIN EXCLUSIVE")
-                    break
-                except sqlite3.OperationalError:
-                    pass
-                sleep(0.25)
-            return curs
-    except ImportError:
-        print("warning: sqlite3 not available in python, skipping build directory lock")
-        print("please file an issue on rust-lang/rust")
-        print("this is not a problem for non-concurrent x.py invocations")
-        return None
-
 def support_xz():
     try:
         with tempfile.NamedTemporaryFile(delete=False) as temp_file:
@@ -743,7 +705,7 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap")
 
-    def build_bootstrap(self):
+    def build_bootstrap(self, color):
         """Build bootstrap"""
         print("Building rustbuild")
         build_dir = os.path.join(self.build_dir, "bootstrap")
@@ -800,6 +762,11 @@ class RustBuild(object):
         if self.get_toml("metrics", "build"):
             args.append("--features")
             args.append("build-metrics")
+        if color == "always":
+            args.append("--color=always")
+        elif color == "never":
+            args.append("--color=never")
+
         run(args, env=env, verbose=self.verbose)
 
     def build_triple(self):
@@ -813,110 +780,6 @@ class RustBuild(object):
             return config
         return default_build_triple(self.verbose)
 
-    def check_submodule(self, module):
-        checked_out = subprocess.Popen(["git", "rev-parse", "HEAD"],
-                                        cwd=os.path.join(self.rust_root, module),
-                                        stdout=subprocess.PIPE)
-        return checked_out
-
-    def update_submodule(self, module, checked_out, recorded_submodules):
-        module_path = os.path.join(self.rust_root, module)
-
-        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)
-
-        update_args = ["git", "submodule", "update", "--init", "--recursive", "--depth=1"]
-        if self.git_version >= distutils.version.LooseVersion("2.11.0"):
-            update_args.append("--progress")
-        update_args.append(module)
-        try:
-            run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)
-        except RuntimeError:
-            print("Failed updating submodule. This is probably due to uncommitted local changes.")
-            print('Either stash the changes by running "git stash" within the submodule\'s')
-            print('directory, reset them by running "git reset --hard", or commit them.')
-            print("To reset all submodules' changes run", end=" ")
-            print('"git submodule foreach --recursive git reset --hard".')
-            raise SystemExit(1)
-
-        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"""
-        has_git = os.path.exists(os.path.join(self.rust_root, ".git"))
-        # This just arbitrarily checks for cargo, but any workspace member in
-        # a submodule would work.
-        has_submodules = os.path.exists(os.path.join(self.rust_root, "src/tools/cargo/Cargo.toml"))
-        if not has_git and not has_submodules:
-            print("This is not a git repository, and the requisite git submodules were not found.")
-            print("If you downloaded the source from https://github.com/rust-lang/rust/releases,")
-            print("those sources will not work. Instead, consider downloading from the source")
-            print("releases linked at")
-            print("https://forge.rust-lang.org/infra/other-installation-methods.html#source-code")
-            print("or clone the repository at https://github.com/rust-lang/rust/.")
-            raise SystemExit(1)
-        if not has_git or self.get_toml('submodules') == "false":
-            return
-
-        default_encoding = sys.getdefaultencoding()
-
-        # check the existence and version of 'git' command
-        git_version_str = require(['git', '--version']).split()[2].decode(default_encoding)
-        self.git_version = distutils.version.LooseVersion(git_version_str)
-
-        start_time = time()
-        print('Updating only changed submodules')
-        default_encoding = sys.getdefaultencoding()
-        # Only update submodules that are needed to build bootstrap.  These are needed because Cargo
-        # currently requires everything in a workspace to be "locally present" when starting a
-        # build, and will give a hard error if any Cargo.toml files are missing.
-        # FIXME: Is there a way to avoid cloning these eagerly? Bootstrap itself doesn't need to
-        #   share a workspace with any tools - maybe it could be excluded from the workspace?
-        #   That will still require cloning the submodules the second you check the standard
-        #   library, though...
-        # FIXME: Is there a way to avoid hard-coding the submodules required?
-        # WARNING: keep this in sync with the submodules hard-coded in bootstrap/lib.rs
-        submodules = [
-            "src/tools/rust-installer",
-            "src/tools/cargo",
-            "src/tools/rls",
-            "src/tools/miri",
-            "library/backtrace",
-            "library/stdarch"
-        ]
-        # If build.vendor is set in config.toml, we must update rust-analyzer also.
-        # Otherwise, the bootstrap will fail (#96456).
-        if self.use_vendored_sources:
-            submodules.append("src/tools/rust-analyzer")
-        filtered_submodules = []
-        submodules_names = []
-        for module in submodules:
-            check = self.check_submodule(module)
-            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()
-        # { filename: hash }
-        recorded_submodules = {}
-        for data in recorded:
-            # [mode, kind, hash, filename]
-            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_dist_environment(self, url):
         """Set download URL for normal environment"""
         if 'RUSTUP_DIST_SERVER' in os.environ:
@@ -926,54 +789,32 @@ class RustBuild(object):
 
     def check_vendored_status(self):
         """Check that vendoring is configured properly"""
-        vendor_dir = os.path.join(self.rust_root, 'vendor')
         if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
             if os.getuid() == 0:
                 self.use_vendored_sources = True
                 print('info: looks like you\'re trying to run this command as root')
                 print('      and so in order to preserve your $HOME this will now')
                 print('      use vendored sources by default.')
-                if not os.path.exists(vendor_dir):
-                    print('error: vendoring required, but vendor directory does not exist.')
-                    print('       Run `cargo vendor` without sudo to initialize the '
-                          'vendor directory.')
-                    raise Exception("{} not found".format(vendor_dir))
 
+        cargo_dir = os.path.join(self.rust_root, '.cargo')
         if self.use_vendored_sources:
-            config = ("[source.crates-io]\n"
-                      "replace-with = 'vendored-sources'\n"
-                      "registry = 'https://example.com'\n"
-                      "\n"
-                      "[source.vendored-sources]\n"
-                      "directory = '{}/vendor'\n"
-                      .format(self.rust_root))
-            if not os.path.exists('.cargo'):
-                os.makedirs('.cargo')
-                with output('.cargo/config') as cargo_config:
-                    cargo_config.write(config)
-            else:
-                print('info: using vendored source, but .cargo/config is already present.')
-                print('      Reusing the current configuration file. But you may want to '
-                      'configure vendoring like this:')
-                print(config)
+            vendor_dir = os.path.join(self.rust_root, 'vendor')
+            if not os.path.exists(vendor_dir):
+                sync_dirs = "--sync ./src/tools/rust-analyzer/Cargo.toml " \
+                            "--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \
+                            "--sync ./src/bootstrap/Cargo.toml "
+                print('error: vendoring required, but vendor directory does not exist.')
+                print('       Run `cargo vendor {}` to initialize the '
+                      'vendor directory.'.format(sync_dirs))
+                print('Alternatively, use the pre-vendored `rustc-src` dist component.')
+                raise Exception("{} not found".format(vendor_dir))
+
+            if not os.path.exists(cargo_dir):
+                print('error: vendoring required, but .cargo/config does not exist.')
+                raise Exception("{} not found".format(cargo_dir))
         else:
-            if os.path.exists('.cargo'):
-                shutil.rmtree('.cargo')
-
-    def ensure_vendored(self):
-        """Ensure that the vendored sources are available if needed"""
-        vendor_dir = os.path.join(self.rust_root, 'vendor')
-        # Note that this does not handle updating the vendored dependencies if
-        # the rust git repository is updated. Normal development usually does
-        # not use vendoring, so hopefully this isn't too much of a problem.
-        if self.use_vendored_sources and not os.path.exists(vendor_dir):
-            run([
-                self.cargo(),
-                "vendor",
-                "--sync=./src/tools/rust-analyzer/Cargo.toml",
-                "--sync=./compiler/rustc_codegen_cranelift/Cargo.toml",
-            ], verbose=self.verbose, cwd=self.rust_root)
-
+            if os.path.exists(cargo_dir):
+                shutil.rmtree(cargo_dir)
 
 def bootstrap(help_triggered):
     """Configure, fetch, build and run the initial bootstrap"""
@@ -987,7 +828,9 @@ def bootstrap(help_triggered):
 
     parser = argparse.ArgumentParser(description='Build rust')
     parser.add_argument('--config')
+    parser.add_argument('--build-dir')
     parser.add_argument('--build')
+    parser.add_argument('--color', choices=['always', 'never', 'auto'])
     parser.add_argument('--clean', action='store_true')
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
@@ -1035,7 +878,7 @@ def bootstrap(help_triggered):
 
     build.check_vendored_status()
 
-    build_dir = build.get_toml('build-dir', 'build') or 'build'
+    build_dir = args.build_dir or build.get_toml('build-dir', 'build') or 'build'
     build.build_dir = os.path.abspath(build_dir)
 
     with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
@@ -1047,18 +890,13 @@ def bootstrap(help_triggered):
 
     build.build = args.build or build.build_triple()
 
-    # Acquire the lock before doing any build actions
-    # The lock is released when `lock` is dropped
     if not os.path.exists(build.build_dir):
         os.makedirs(build.build_dir)
-    lock = acquire_lock(build.build_dir)
-    build.update_submodules()
 
     # Fetch/build the bootstrap
     build.download_toolchain()
     sys.stdout.flush()
-    build.ensure_vendored()
-    build.build_bootstrap()
+    build.build_bootstrap(args.color)
     sys.stdout.flush()
 
     # Run the bootstrap