Skip to content

Commit 96ab7e6

Browse files
authored
Rollup merge of #112281 - jyn514:test-bootstrap-py, r=albertlarsan68
Test the cargo args generated by bootstrap.py I recommend reviewing this commit-by-commit using the instructions in https://rustc-dev-guide.rust-lang.org/git.html#moving-large-sections-of-code. - Test cargo arguments passed by bootstrap.py This moves a lot of code around, but the logic itself is not too terribly complicated. - Move almost all logic in `def bootstrap` to the `RustBuild` class, to avoid mixing setting configuration with running commands - Update various doctests to the new (more complete) RustBuild config. In particular, don't pretend that `bin_root` supports `build` being unset. - Change `parse_args` not to use a global, to allow testing it - Set BUILD_DIR appropriately so bootstrap.py doesn't panic because cargo isn't found - Allow passing arguments to `bootstrap_test.py` Previous, it used the built-in test runner, which doesn't support options unless they're manually passed in the script. - Fix progress messages for configure in bootstrap_test.py Before it would unconditionally print `configure-args = []`. r? `@albertlarsan68` cc #112089 #111979 (comment)
2 parents db3c394 + 1e7f037 commit 96ab7e6

File tree

4 files changed

+144
-107
lines changed

4 files changed

+144
-107
lines changed

src/bootstrap/bootstrap.py

+79-67
Original file line numberDiff line numberDiff line change
@@ -458,23 +458,51 @@ def unpack_component(download_info):
458458
verbose=download_info.verbose,
459459
)
460460

461-
class RustBuild(object):
462-
"""Provide all the methods required to build Rust"""
461+
class FakeArgs:
462+
"""Used for unit tests to avoid updating all call sites"""
463463
def __init__(self):
464-
self.checksums_sha256 = {}
465-
self.stage0_compiler = None
466-
self.download_url = ''
467464
self.build = ''
468465
self.build_dir = ''
469466
self.clean = False
470-
self.config_toml = ''
471-
self.rust_root = ''
472-
self.use_locked_deps = False
473-
self.use_vendored_sources = False
474467
self.verbose = False
468+
self.json_output = False
469+
self.color = 'auto'
470+
self.warnings = 'default'
471+
472+
class RustBuild(object):
473+
"""Provide all the methods required to build Rust"""
474+
def __init__(self, config_toml="", args=FakeArgs()):
475475
self.git_version = None
476476
self.nix_deps_dir = None
477477
self._should_fix_bins_and_dylibs = None
478+
self.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
479+
480+
self.config_toml = config_toml
481+
482+
self.clean = args.clean
483+
self.json_output = args.json_output
484+
self.verbose = args.verbose
485+
self.color = args.color
486+
self.warnings = args.warnings
487+
488+
config_verbose_count = self.get_toml('verbose', 'build')
489+
if config_verbose_count is not None:
490+
self.verbose = max(self.verbose, int(config_verbose_count))
491+
492+
self.use_vendored_sources = self.get_toml('vendor', 'build') == 'true'
493+
self.use_locked_deps = self.get_toml('locked-deps', 'build') == 'true'
494+
495+
build_dir = args.build_dir or self.get_toml('build-dir', 'build') or 'build'
496+
self.build_dir = os.path.abspath(build_dir)
497+
498+
with open(os.path.join(self.rust_root, "src", "stage0.json")) as f:
499+
data = json.load(f)
500+
self.checksums_sha256 = data["checksums_sha256"]
501+
self.stage0_compiler = Stage0Toolchain(data["compiler"])
502+
self.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
503+
504+
self.build = args.build or self.build_triple()
505+
478506

479507
def download_toolchain(self):
480508
"""Fetch the build system for Rust, written in Rust
@@ -704,9 +732,10 @@ def rustc_stamp(self):
704732
"""Return the path for .rustc-stamp at the given stage
705733
706734
>>> rb = RustBuild()
735+
>>> rb.build = "host"
707736
>>> rb.build_dir = "build"
708-
>>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp")
709-
True
737+
>>> expected = os.path.join("build", "host", "stage0", ".rustc-stamp")
738+
>>> assert rb.rustc_stamp() == expected, rb.rustc_stamp()
710739
"""
711740
return os.path.join(self.bin_root(), '.rustc-stamp')
712741

@@ -721,15 +750,9 @@ def bin_root(self):
721750
"""Return the binary root directory for the given stage
722751
723752
>>> rb = RustBuild()
724-
>>> rb.build_dir = "build"
725-
>>> rb.bin_root() == os.path.join("build", "stage0")
726-
True
727-
728-
When the 'build' property is given should be a nested directory:
729-
730753
>>> rb.build = "devel"
731-
>>> rb.bin_root() == os.path.join("build", "devel", "stage0")
732-
True
754+
>>> expected = os.path.abspath(os.path.join("build", "devel", "stage0"))
755+
>>> assert rb.bin_root() == expected, rb.bin_root()
733756
"""
734757
subdir = "stage0"
735758
return os.path.join(self.build_dir, self.build, subdir)
@@ -761,9 +784,12 @@ def get_toml(self, key, section=None):
761784
>>> rb.get_toml("key1")
762785
'true'
763786
"""
787+
return RustBuild.get_toml_static(self.config_toml, key, section)
764788

789+
@staticmethod
790+
def get_toml_static(config_toml, key, section=None):
765791
cur_section = None
766-
for line in self.config_toml.splitlines():
792+
for line in config_toml.splitlines():
767793
section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
768794
if section_match is not None:
769795
cur_section = section_match.group(1)
@@ -772,7 +798,7 @@ def get_toml(self, key, section=None):
772798
if match is not None:
773799
value = match.group(1)
774800
if section is None or section == cur_section:
775-
return self.get_string(value) or value.strip()
801+
return RustBuild.get_string(value) or value.strip()
776802
return None
777803

778804
def cargo(self):
@@ -835,13 +861,23 @@ def bootstrap_binary(self):
835861
"""
836862
return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap")
837863

838-
def build_bootstrap(self, color, warnings, verbose_count):
864+
def build_bootstrap(self):
839865
"""Build bootstrap"""
840866
env = os.environ.copy()
841867
if "GITHUB_ACTIONS" in env:
842868
print("::group::Building bootstrap")
843869
else:
844870
print("Building bootstrap", file=sys.stderr)
871+
872+
args = self.build_bootstrap_cmd(env)
873+
# Run this from the source directory so cargo finds .cargo/config
874+
run(args, env=env, verbose=self.verbose, cwd=self.rust_root)
875+
876+
if "GITHUB_ACTIONS" in env:
877+
print("::endgroup::")
878+
879+
def build_bootstrap_cmd(self, env):
880+
"""For tests."""
845881
build_dir = os.path.join(self.build_dir, "bootstrap")
846882
if self.clean and os.path.exists(build_dir):
847883
shutil.rmtree(build_dir)
@@ -894,10 +930,10 @@ def build_bootstrap(self, color, warnings, verbose_count):
894930
if target_linker is not None:
895931
env["RUSTFLAGS"] += " -C linker=" + target_linker
896932
env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
897-
if warnings == "default":
933+
if self.warnings == "default":
898934
deny_warnings = self.get_toml("deny-warnings", "rust") != "false"
899935
else:
900-
deny_warnings = warnings == "deny"
936+
deny_warnings = self.warnings == "deny"
901937
if deny_warnings:
902938
env["RUSTFLAGS"] += " -Dwarnings"
903939

@@ -908,7 +944,7 @@ def build_bootstrap(self, color, warnings, verbose_count):
908944
self.cargo()))
909945
args = [self.cargo(), "build", "--manifest-path",
910946
os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
911-
args.extend("--verbose" for _ in range(verbose_count))
947+
args.extend("--verbose" for _ in range(self.verbose))
912948
if self.use_locked_deps:
913949
args.append("--locked")
914950
if self.use_vendored_sources:
@@ -918,20 +954,16 @@ def build_bootstrap(self, color, warnings, verbose_count):
918954
args.append("build-metrics")
919955
if self.json_output:
920956
args.append("--message-format=json")
921-
if color == "always":
957+
if self.color == "always":
922958
args.append("--color=always")
923-
elif color == "never":
959+
elif self.color == "never":
924960
args.append("--color=never")
925961
try:
926962
args += env["CARGOFLAGS"].split()
927963
except KeyError:
928964
pass
929965

930-
# Run this from the source directory so cargo finds .cargo/config
931-
run(args, env=env, verbose=self.verbose, cwd=self.rust_root)
932-
933-
if "GITHUB_ACTIONS" in env:
934-
print("::endgroup::")
966+
return args
935967

936968
def build_triple(self):
937969
"""Build triple as in LLVM
@@ -981,7 +1013,7 @@ def check_vendored_status(self):
9811013
if os.path.exists(cargo_dir):
9821014
shutil.rmtree(cargo_dir)
9831015

984-
def parse_args():
1016+
def parse_args(args):
9851017
"""Parse the command line arguments that the python script needs."""
9861018
parser = argparse.ArgumentParser(add_help=False)
9871019
parser.add_argument('-h', '--help', action='store_true')
@@ -994,16 +1026,11 @@ def parse_args():
9941026
parser.add_argument('--warnings', choices=['deny', 'warn', 'default'], default='default')
9951027
parser.add_argument('-v', '--verbose', action='count', default=0)
9961028

997-
return parser.parse_known_args(sys.argv)[0]
1029+
return parser.parse_known_args(args)[0]
9981030

9991031
def bootstrap(args):
10001032
"""Configure, fetch, build and run the initial bootstrap"""
1001-
# Configure initial bootstrap
1002-
build = RustBuild()
1003-
build.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
1004-
build.verbose = args.verbose != 0
1005-
build.clean = args.clean
1006-
build.json_output = args.json_output
1033+
rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
10071034

10081035
# Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
10091036
# then `config.toml` in the root directory.
@@ -1012,52 +1039,37 @@ def bootstrap(args):
10121039
if using_default_path:
10131040
toml_path = 'config.toml'
10141041
if not os.path.exists(toml_path):
1015-
toml_path = os.path.join(build.rust_root, toml_path)
1042+
toml_path = os.path.join(rust_root, toml_path)
10161043

10171044
# Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
10181045
# but not if `config.toml` hasn't been created.
10191046
if not using_default_path or os.path.exists(toml_path):
10201047
with open(toml_path) as config:
1021-
build.config_toml = config.read()
1048+
config_toml = config.read()
1049+
else:
1050+
config_toml = ''
10221051

1023-
profile = build.get_toml('profile')
1052+
profile = RustBuild.get_toml_static(config_toml, 'profile')
10241053
if profile is not None:
10251054
include_file = 'config.{}.toml'.format(profile)
1026-
include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults')
1055+
include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults')
10271056
include_path = os.path.join(include_dir, include_file)
1028-
# HACK: This works because `build.get_toml()` returns the first match it finds for a
1057+
# HACK: This works because `self.get_toml()` returns the first match it finds for a
10291058
# specific key, so appending our defaults at the end allows the user to override them
10301059
with open(include_path) as included_toml:
1031-
build.config_toml += os.linesep + included_toml.read()
1032-
1033-
verbose_count = args.verbose
1034-
config_verbose_count = build.get_toml('verbose', 'build')
1035-
if config_verbose_count is not None:
1036-
verbose_count = max(args.verbose, int(config_verbose_count))
1037-
1038-
build.use_vendored_sources = build.get_toml('vendor', 'build') == 'true'
1039-
build.use_locked_deps = build.get_toml('locked-deps', 'build') == 'true'
1060+
config_toml += os.linesep + included_toml.read()
10401061

1062+
# Configure initial bootstrap
1063+
build = RustBuild(config_toml, args)
10411064
build.check_vendored_status()
10421065

1043-
build_dir = args.build_dir or build.get_toml('build-dir', 'build') or 'build'
1044-
build.build_dir = os.path.abspath(build_dir)
1045-
1046-
with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
1047-
data = json.load(f)
1048-
build.checksums_sha256 = data["checksums_sha256"]
1049-
build.stage0_compiler = Stage0Toolchain(data["compiler"])
1050-
build.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
1051-
1052-
build.build = args.build or build.build_triple()
1053-
10541066
if not os.path.exists(build.build_dir):
10551067
os.makedirs(build.build_dir)
10561068

10571069
# Fetch/build the bootstrap
10581070
build.download_toolchain()
10591071
sys.stdout.flush()
1060-
build.build_bootstrap(args.color, args.warnings, verbose_count)
1072+
build.build_bootstrap()
10611073
sys.stdout.flush()
10621074

10631075
# Run the bootstrap
@@ -1077,7 +1089,7 @@ def main():
10771089
if len(sys.argv) > 1 and sys.argv[1] == 'help':
10781090
sys.argv[1] = '-h'
10791091

1080-
args = parse_args()
1092+
args = parse_args(sys.argv)
10811093
help_triggered = args.help or len(sys.argv) == 1
10821094

10831095
# If the user is asking for help, let them know that the whole download-and-build

0 commit comments

Comments
 (0)