@@ -48,44 +48,45 @@ def eprint(*args, **kwargs):
48
48
print (* args , ** kwargs )
49
49
50
50
51
- def get (base , url , path , checksums , verbose = False ):
51
+ def get (base , url , path , checksums , verbose = False , verify_checksum = True ):
52
52
with tempfile .NamedTemporaryFile (delete = False ) as temp_file :
53
53
temp_path = temp_file .name
54
-
55
54
try :
56
- if url not in checksums :
55
+ if url not in checksums and verify_checksum :
57
56
raise RuntimeError (
58
57
(
59
- "src/stage0 doesn't contain a checksum for {}. "
58
+ "src/stage0.json doesn't contain a checksum for {}. "
60
59
"Pre-built artifacts might not be available for this "
61
60
"target at this time, see https://doc.rust-lang.org/nightly"
62
61
"/rustc/platform-support.html for more information."
63
62
).format (url )
64
63
)
65
- sha256 = checksums [url ]
66
- if os .path .exists (path ):
67
- if verify (path , sha256 , False ):
68
- if verbose :
69
- eprint ("using already-download file" , path )
70
- return
71
- else :
72
- if verbose :
73
- eprint (
74
- "ignoring already-download file" ,
75
- path ,
76
- "due to failed verification" ,
77
- )
78
- os .unlink (path )
64
+ if verify_checksum :
65
+ sha256 = checksums [url ]
66
+ if os .path .exists (path ):
67
+ if verify (path , sha256 , False ):
68
+ if verbose :
69
+ print ("using already-download file" , path , file = sys .stderr )
70
+ return
71
+ else :
72
+ if verbose :
73
+ print (
74
+ "ignoring already-download file" ,
75
+ path ,
76
+ "due to failed verification" ,
77
+ file = sys .stderr ,
78
+ )
79
+ os .unlink (path )
79
80
download (temp_path , "{}/{}" .format (base , url ), True , verbose )
80
- if not verify (temp_path , sha256 , verbose ):
81
+ if verify_checksum and not verify (temp_path , checksums [ url ] , verbose ):
81
82
raise RuntimeError ("failed verification" )
82
83
if verbose :
83
- eprint ("moving {} to {}" .format (temp_path , path ))
84
+ print ("moving {} to {}" .format (temp_path , path ), file = sys . stderr )
84
85
shutil .move (temp_path , path )
85
86
finally :
86
87
if os .path .isfile (temp_path ):
87
88
if verbose :
88
- eprint ("removing" , temp_path )
89
+ print ("removing" , temp_path , file = sys . stderr )
89
90
os .unlink (temp_path )
90
91
91
92
@@ -267,6 +268,12 @@ def require(cmd, exit=True, exception=False):
267
268
return None
268
269
269
270
271
+ def output_cmd (cmd ):
272
+ p = subprocess .Popen (cmd , stdout = subprocess .PIPE , text = True )
273
+ output = p .communicate ()[0 ].strip ('"' ).strip ()
274
+ return output
275
+
276
+
270
277
def format_build_time (duration ):
271
278
"""Return a nicer format for build time
272
279
@@ -531,6 +538,7 @@ class FakeArgs:
531
538
"""Used for unit tests to avoid updating all call sites"""
532
539
533
540
def __init__ (self ):
541
+ self .is_precompiled_bootstrap = False
534
542
self .build = ""
535
543
self .build_dir = ""
536
544
self .clean = False
@@ -558,6 +566,7 @@ def __init__(self, config_toml="", args=None):
558
566
self .verbose = args .verbose
559
567
self .color = args .color
560
568
self .warnings = args .warnings
569
+ self .is_precompiled_bootstrap = False
561
570
562
571
config_verbose_count = self .get_toml ("verbose" , "build" )
563
572
if config_verbose_count is not None :
@@ -724,6 +733,105 @@ def download_toolchain(self):
724
733
with output (self .rustc_stamp ()) as rust_stamp :
725
734
rust_stamp .write (key )
726
735
736
+ def is_bootstrap_modified (self ):
737
+ cmd = ["git" , "status" , "--porcelain" , "src/bootstrap" ]
738
+ try :
739
+ output = output_cmd (cmd )
740
+ return bool (output )
741
+ except subprocess .CalledProcessError :
742
+ return False
743
+
744
+ def download_or_build_bootstrap (self ):
745
+ try :
746
+ if self .is_bootstrap_modified ():
747
+ self .is_precompiled_bootstrap = False
748
+ self .build_bootstrap ()
749
+ return
750
+ last_commit = self .last_bootstrap_commit ()
751
+ if last_commit is None :
752
+ self .build_bootstrap ()
753
+ return
754
+ if self .bootstrap_out_of_date (last_commit ):
755
+ success = self .download_bootstrap (last_commit )
756
+ if success :
757
+ stamp = os .path .join (
758
+ self .build_dir , "bootstrap" , ".bootstrap-stamp"
759
+ )
760
+ with open (stamp , "w" ) as f :
761
+ f .write (last_commit )
762
+ self .is_precompiled_bootstrap = True
763
+
764
+ except Exception as e :
765
+ return
766
+
767
+ if not self .is_precompiled_bootstrap :
768
+ self .build_bootstrap ()
769
+
770
+ def download_bootstrap (self , commit_hash ):
771
+ filename = f"bootstrap-nightly-{ self .build_triple ()} .tar.gz"
772
+ tarball_suffix = "tar.gz"
773
+ key = commit_hash
774
+ pattern = "bootstrap"
775
+
776
+ bootstrap_path = os .path .join (
777
+ self .bin_root (),
778
+ f"nightly-{ self .build_triple ()} " ,
779
+ "bootstrap" ,
780
+ "bootstrap" ,
781
+ "bin" ,
782
+ "bootstrap" ,
783
+ )
784
+
785
+ if os .path .exists (bootstrap_path ):
786
+ return True
787
+
788
+ cache_dir = os .path .join (self .build_dir , "cache" )
789
+ tarball_path = os .path .join (cache_dir , filename )
790
+ base_url = self .stage0_data .get ("artifacts_server" )
791
+ download_url = f"{ key } /{ filename } "
792
+
793
+ if not os .path .exists (tarball_path ):
794
+ try :
795
+ get (
796
+ base_url ,
797
+ download_url ,
798
+ tarball_path ,
799
+ self .stage0_data ,
800
+ verbose = self .verbose ,
801
+ verify_checksum = False ,
802
+ )
803
+ except Exception as e :
804
+ return False
805
+
806
+ try :
807
+ unpack (
808
+ tarball_path ,
809
+ tarball_suffix ,
810
+ self .bin_root (),
811
+ match = pattern ,
812
+ verbose = self .verbose ,
813
+ )
814
+ except Exception as e :
815
+ return False
816
+
817
+ return True
818
+
819
+ def last_bootstrap_commit (self ):
820
+ cmd = ["git" , "log" , "-1" , "--pretty=format:%H" , "src/bootstrap" ]
821
+ try :
822
+ commit_hash = output_cmd (cmd )
823
+ return commit_hash .strip () if commit_hash else None
824
+ except subprocess .CalledProcessError :
825
+ return None
826
+
827
+ def bootstrap_out_of_date (self , commit : str ):
828
+ stamp_path = os .path .join (self .bin_root (), "bootstrap" , ".bootstrap-stamp" )
829
+ if not os .path .exists (stamp_path ):
830
+ return True
831
+ with open (stamp_path , "r" ) as f :
832
+ stamp_commit = f .read ().strip ()
833
+ return stamp_commit != commit
834
+
727
835
def should_fix_bins_and_dylibs (self ):
728
836
"""Whether or not `fix_bin_or_dylib` needs to be run; can only be True
729
837
on NixOS or if bootstrap.toml has `build.patch-binaries-for-nix` set.
@@ -995,7 +1103,14 @@ def bootstrap_binary(self):
995
1103
... "debug", "bootstrap")
996
1104
True
997
1105
"""
998
- return os .path .join (self .bootstrap_out (), "debug" , "bootstrap" )
1106
+ if self .is_precompiled_bootstrap :
1107
+ root = self .bin_root ()
1108
+ subfolder = "nightly-{}" .format (self .build_triple ())
1109
+ return os .path .join (
1110
+ root , subfolder , "bootstrap" , "bootstrap" , "bin" , "bootstrap"
1111
+ )
1112
+ else :
1113
+ return os .path .join (self .bootstrap_out (), "debug" , "bootstrap" )
999
1114
1000
1115
def build_bootstrap (self ):
1001
1116
"""Build bootstrap"""
@@ -1330,13 +1445,16 @@ def bootstrap(args):
1330
1445
build = RustBuild (config_toml , args )
1331
1446
build .check_vendored_status ()
1332
1447
1448
+ build_dir = args .build_dir or build .get_toml ("build_dir" , "build" ) or "build"
1449
+ build .build_dir = os .path .abspath (build_dir )
1450
+
1333
1451
if not os .path .exists (build .build_dir ):
1334
1452
os .makedirs (os .path .realpath (build .build_dir ))
1335
1453
1336
- # Fetch/build the bootstrap
1337
1454
build .download_toolchain ()
1338
1455
sys .stdout .flush ()
1339
- build .build_bootstrap ()
1456
+
1457
+ build .download_or_build_bootstrap ()
1340
1458
sys .stdout .flush ()
1341
1459
1342
1460
# Run the bootstrap
@@ -1362,8 +1480,8 @@ def main():
1362
1480
# process has to happen before anything is printed out.
1363
1481
if help_triggered :
1364
1482
eprint (
1365
- "INFO: Downloading and building bootstrap before processing --help command. \n "
1366
- " See src/bootstrap/README.md for help with common commands."
1483
+ "INFO: Checking if bootstrap needs to be downloaded or built before processing "
1484
+ "--help command. \n See src/bootstrap/README.md for help with common commands."
1367
1485
)
1368
1486
1369
1487
exit_code = 0
0 commit comments