@@ -458,23 +458,52 @@ 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+
470+ class RustBuild (object ):
471+ """Provide all the methods required to build Rust"""
472+ def __init__ (self , config_toml = "" , args = FakeArgs ()):
475473 self .git_version = None
476474 self .nix_deps_dir = None
477475 self ._should_fix_bins_and_dylibs = None
476+ self .rust_root = os .path .abspath (os .path .join (__file__ , '../../..' ))
477+
478+ self .config_toml = config_toml
479+
480+ self .verbose = args .verbose != 0
481+ self .clean = args .clean
482+ self .json_output = args .json_output
483+
484+ profile = self .get_toml ('profile' )
485+ if profile is not None :
486+ include_file = 'config.{}.toml' .format (profile )
487+ include_dir = os .path .join (self .rust_root , 'src' , 'bootstrap' , 'defaults' )
488+ include_path = os .path .join (include_dir , include_file )
489+ # HACK: This works because `self.get_toml()` returns the first match it finds for a
490+ # specific key, so appending our defaults at the end allows the user to override them
491+ with open (include_path ) as included_toml :
492+ self .config_toml += os .linesep + included_toml .read ()
493+
494+ self .use_vendored_sources = self .get_toml ('vendor' , 'build' ) == 'true'
495+ self .use_locked_deps = self .get_toml ('locked-deps' , 'build' ) == 'true'
496+
497+ build_dir = args .build_dir or self .get_toml ('build-dir' , 'build' ) or 'build'
498+ self .build_dir = os .path .abspath (build_dir )
499+
500+ with open (os .path .join (self .rust_root , "src" , "stage0.json" )) as f :
501+ data = json .load (f )
502+ self .checksums_sha256 = data ["checksums_sha256" ]
503+ self .stage0_compiler = Stage0Toolchain (data ["compiler" ])
504+ self .download_url = os .getenv ("RUSTUP_DIST_SERVER" ) or data ["config" ]["dist_server" ]
505+
506+ self .build = args .build or self .build_triple ()
478507
479508 def download_toolchain (self ):
480509 """Fetch the build system for Rust, written in Rust
@@ -704,9 +733,10 @@ def rustc_stamp(self):
704733 """Return the path for .rustc-stamp at the given stage
705734
706735 >>> rb = RustBuild()
736+ >>> rb.build = "host"
707737 >>> rb.build_dir = "build"
708- >>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp")
709- True
738+ >>> expected = os.path.join("build", "host ", "stage0", ".rustc-stamp")
739+ >>> assert rb.rustc_stamp() == expected, rb.rustc_stamp()
710740 """
711741 return os .path .join (self .bin_root (), '.rustc-stamp' )
712742
@@ -721,15 +751,9 @@ def bin_root(self):
721751 """Return the binary root directory for the given stage
722752
723753 >>> 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-
730754 >>> rb.build = "devel"
731- >>> rb.bin_root() == os.path.join("build", "devel", "stage0")
732- True
755+ >>> expected = os.path.abspath(os.path. join("build", "devel", "stage0") )
756+ >>> assert rb.bin_root() == expected, rb.bin_root()
733757 """
734758 subdir = "stage0"
735759 return os .path .join (self .build_dir , self .build , subdir )
@@ -842,6 +866,16 @@ def build_bootstrap(self, color, warnings, verbose_count):
842866 print ("::group::Building bootstrap" )
843867 else :
844868 print ("Building bootstrap" , file = sys .stderr )
869+
870+ args = self .build_bootstrap_cmd (env , color , warnings , verbose_count )
871+ # Run this from the source directory so cargo finds .cargo/config
872+ run (args , env = env , verbose = self .verbose , cwd = self .rust_root )
873+
874+ if "GITHUB_ACTIONS" in env :
875+ print ("::endgroup::" )
876+
877+ def build_bootstrap_cmd (self , env , color , warnings , verbose_count ):
878+ """For tests."""
845879 build_dir = os .path .join (self .build_dir , "bootstrap" )
846880 if self .clean and os .path .exists (build_dir ):
847881 shutil .rmtree (build_dir )
@@ -927,11 +961,7 @@ def build_bootstrap(self, color, warnings, verbose_count):
927961 except KeyError :
928962 pass
929963
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::" )
964+ return args
935965
936966 def build_triple (self ):
937967 """Build triple as in LLVM
@@ -981,7 +1011,7 @@ def check_vendored_status(self):
9811011 if os .path .exists (cargo_dir ):
9821012 shutil .rmtree (cargo_dir )
9831013
984- def parse_args ():
1014+ def parse_args (args ):
9851015 """Parse the command line arguments that the python script needs."""
9861016 parser = argparse .ArgumentParser (add_help = False )
9871017 parser .add_argument ('-h' , '--help' , action = 'store_true' )
@@ -994,16 +1024,11 @@ def parse_args():
9941024 parser .add_argument ('--warnings' , choices = ['deny' , 'warn' , 'default' ], default = 'default' )
9951025 parser .add_argument ('-v' , '--verbose' , action = 'count' , default = 0 )
9961026
997- return parser .parse_known_args (sys . argv )[0 ]
1027+ return parser .parse_known_args (args )[0 ]
9981028
9991029def bootstrap (args ):
10001030 """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
1031+ rust_root = os .path .abspath (os .path .join (__file__ , '../../..' ))
10071032
10081033 # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
10091034 # then `config.toml` in the root directory.
@@ -1012,45 +1037,23 @@ def bootstrap(args):
10121037 if using_default_path :
10131038 toml_path = 'config.toml'
10141039 if not os .path .exists (toml_path ):
1015- toml_path = os .path .join (build . rust_root , toml_path )
1040+ toml_path = os .path .join (rust_root , toml_path )
10161041
10171042 # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
10181043 # but not if `config.toml` hasn't been created.
10191044 if not using_default_path or os .path .exists (toml_path ):
10201045 with open (toml_path ) as config :
1021- build .config_toml = config .read ()
1022-
1023- profile = build .get_toml ('profile' )
1024- if profile is not None :
1025- include_file = 'config.{}.toml' .format (profile )
1026- include_dir = os .path .join (build .rust_root , 'src' , 'bootstrap' , 'defaults' )
1027- 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
1029- # specific key, so appending our defaults at the end allows the user to override them
1030- with open (include_path ) as included_toml :
1031- build .config_toml += os .linesep + included_toml .read ()
1046+ config_toml = config .read ()
1047+
1048+ # Configure initial bootstrap
1049+ build = RustBuild (config_toml , args )
1050+ build .check_vendored_status ()
10321051
10331052 verbose_count = args .verbose
10341053 config_verbose_count = build .get_toml ('verbose' , 'build' )
10351054 if config_verbose_count is not None :
10361055 verbose_count = max (args .verbose , int (config_verbose_count ))
10371056
1038- build .use_vendored_sources = build .get_toml ('vendor' , 'build' ) == 'true'
1039- build .use_locked_deps = build .get_toml ('locked-deps' , 'build' ) == 'true'
1040-
1041- build .check_vendored_status ()
1042-
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-
10541057 if not os .path .exists (build .build_dir ):
10551058 os .makedirs (build .build_dir )
10561059
@@ -1077,7 +1080,7 @@ def main():
10771080 if len (sys .argv ) > 1 and sys .argv [1 ] == 'help' :
10781081 sys .argv [1 ] = '-h'
10791082
1080- args = parse_args ()
1083+ args = parse_args (sys . argv )
10811084 help_triggered = args .help or len (sys .argv ) == 1
10821085
10831086 # If the user is asking for help, let them know that the whole download-and-build
0 commit comments