@@ -458,23 +458,51 @@ def unpack_component(download_info):
458
458
verbose = download_info .verbose ,
459
459
)
460
460
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 """
463
463
def __init__ (self ):
464
- self .checksums_sha256 = {}
465
- self .stage0_compiler = None
466
- self .download_url = ''
467
464
self .build = ''
468
465
self .build_dir = ''
469
466
self .clean = False
470
- self .config_toml = ''
471
- self .rust_root = ''
472
- self .use_locked_deps = False
473
- self .use_vendored_sources = False
474
467
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 ()):
475
475
self .git_version = None
476
476
self .nix_deps_dir = None
477
477
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
+
478
506
479
507
def download_toolchain (self ):
480
508
"""Fetch the build system for Rust, written in Rust
@@ -704,9 +732,10 @@ def rustc_stamp(self):
704
732
"""Return the path for .rustc-stamp at the given stage
705
733
706
734
>>> rb = RustBuild()
735
+ >>> rb.build = "host"
707
736
>>> 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()
710
739
"""
711
740
return os .path .join (self .bin_root (), '.rustc-stamp' )
712
741
@@ -721,15 +750,9 @@ def bin_root(self):
721
750
"""Return the binary root directory for the given stage
722
751
723
752
>>> 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
-
730
753
>>> 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()
733
756
"""
734
757
subdir = "stage0"
735
758
return os .path .join (self .build_dir , self .build , subdir )
@@ -761,9 +784,12 @@ def get_toml(self, key, section=None):
761
784
>>> rb.get_toml("key1")
762
785
'true'
763
786
"""
787
+ return RustBuild .get_toml_static (self .config_toml , key , section )
764
788
789
+ @staticmethod
790
+ def get_toml_static (config_toml , key , section = None ):
765
791
cur_section = None
766
- for line in self . config_toml .splitlines ():
792
+ for line in config_toml .splitlines ():
767
793
section_match = re .match (r'^\s*\[(.*)\]\s*$' , line )
768
794
if section_match is not None :
769
795
cur_section = section_match .group (1 )
@@ -772,7 +798,7 @@ def get_toml(self, key, section=None):
772
798
if match is not None :
773
799
value = match .group (1 )
774
800
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 ()
776
802
return None
777
803
778
804
def cargo (self ):
@@ -835,13 +861,23 @@ def bootstrap_binary(self):
835
861
"""
836
862
return os .path .join (self .build_dir , "bootstrap" , "debug" , "bootstrap" )
837
863
838
- def build_bootstrap (self , color , warnings , verbose_count ):
864
+ def build_bootstrap (self ):
839
865
"""Build bootstrap"""
840
866
env = os .environ .copy ()
841
867
if "GITHUB_ACTIONS" in env :
842
868
print ("::group::Building bootstrap" )
843
869
else :
844
870
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."""
845
881
build_dir = os .path .join (self .build_dir , "bootstrap" )
846
882
if self .clean and os .path .exists (build_dir ):
847
883
shutil .rmtree (build_dir )
@@ -894,10 +930,10 @@ def build_bootstrap(self, color, warnings, verbose_count):
894
930
if target_linker is not None :
895
931
env ["RUSTFLAGS" ] += " -C linker=" + target_linker
896
932
env ["RUSTFLAGS" ] += " -Wrust_2018_idioms -Wunused_lifetimes"
897
- if warnings == "default" :
933
+ if self . warnings == "default" :
898
934
deny_warnings = self .get_toml ("deny-warnings" , "rust" ) != "false"
899
935
else :
900
- deny_warnings = warnings == "deny"
936
+ deny_warnings = self . warnings == "deny"
901
937
if deny_warnings :
902
938
env ["RUSTFLAGS" ] += " -Dwarnings"
903
939
@@ -908,7 +944,7 @@ def build_bootstrap(self, color, warnings, verbose_count):
908
944
self .cargo ()))
909
945
args = [self .cargo (), "build" , "--manifest-path" ,
910
946
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 ))
912
948
if self .use_locked_deps :
913
949
args .append ("--locked" )
914
950
if self .use_vendored_sources :
@@ -918,20 +954,16 @@ def build_bootstrap(self, color, warnings, verbose_count):
918
954
args .append ("build-metrics" )
919
955
if self .json_output :
920
956
args .append ("--message-format=json" )
921
- if color == "always" :
957
+ if self . color == "always" :
922
958
args .append ("--color=always" )
923
- elif color == "never" :
959
+ elif self . color == "never" :
924
960
args .append ("--color=never" )
925
961
try :
926
962
args += env ["CARGOFLAGS" ].split ()
927
963
except KeyError :
928
964
pass
929
965
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
935
967
936
968
def build_triple (self ):
937
969
"""Build triple as in LLVM
@@ -981,7 +1013,7 @@ def check_vendored_status(self):
981
1013
if os .path .exists (cargo_dir ):
982
1014
shutil .rmtree (cargo_dir )
983
1015
984
- def parse_args ():
1016
+ def parse_args (args ):
985
1017
"""Parse the command line arguments that the python script needs."""
986
1018
parser = argparse .ArgumentParser (add_help = False )
987
1019
parser .add_argument ('-h' , '--help' , action = 'store_true' )
@@ -994,16 +1026,11 @@ def parse_args():
994
1026
parser .add_argument ('--warnings' , choices = ['deny' , 'warn' , 'default' ], default = 'default' )
995
1027
parser .add_argument ('-v' , '--verbose' , action = 'count' , default = 0 )
996
1028
997
- return parser .parse_known_args (sys . argv )[0 ]
1029
+ return parser .parse_known_args (args )[0 ]
998
1030
999
1031
def bootstrap (args ):
1000
1032
"""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__ , '../../..' ))
1007
1034
1008
1035
# Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
1009
1036
# then `config.toml` in the root directory.
@@ -1012,52 +1039,37 @@ def bootstrap(args):
1012
1039
if using_default_path :
1013
1040
toml_path = 'config.toml'
1014
1041
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 )
1016
1043
1017
1044
# Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
1018
1045
# but not if `config.toml` hasn't been created.
1019
1046
if not using_default_path or os .path .exists (toml_path ):
1020
1047
with open (toml_path ) as config :
1021
- build .config_toml = config .read ()
1048
+ config_toml = config .read ()
1049
+ else :
1050
+ config_toml = ''
1022
1051
1023
- profile = build . get_toml ( 'profile' )
1052
+ profile = RustBuild . get_toml_static ( config_toml , 'profile' )
1024
1053
if profile is not None :
1025
1054
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' )
1027
1056
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
1029
1058
# specific key, so appending our defaults at the end allows the user to override them
1030
1059
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 ()
1040
1061
1062
+ # Configure initial bootstrap
1063
+ build = RustBuild (config_toml , args )
1041
1064
build .check_vendored_status ()
1042
1065
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
-
1054
1066
if not os .path .exists (build .build_dir ):
1055
1067
os .makedirs (build .build_dir )
1056
1068
1057
1069
# Fetch/build the bootstrap
1058
1070
build .download_toolchain ()
1059
1071
sys .stdout .flush ()
1060
- build .build_bootstrap (args . color , args . warnings , verbose_count )
1072
+ build .build_bootstrap ()
1061
1073
sys .stdout .flush ()
1062
1074
1063
1075
# Run the bootstrap
@@ -1077,7 +1089,7 @@ def main():
1077
1089
if len (sys .argv ) > 1 and sys .argv [1 ] == 'help' :
1078
1090
sys .argv [1 ] = '-h'
1079
1091
1080
- args = parse_args ()
1092
+ args = parse_args (sys . argv )
1081
1093
help_triggered = args .help or len (sys .argv ) == 1
1082
1094
1083
1095
# If the user is asking for help, let them know that the whole download-and-build
0 commit comments