@@ -947,7 +947,14 @@ impl Config {
947947 ) ;
948948 }
949949
950- config. download_rustc_commit = config. download_ci_rustc_commit (
950+ config. download_rustc_commit = download_ci_rustc_commit (
951+ & config. stage0_metadata ,
952+ config. path_modification_cache . clone ( ) ,
953+ & config. src ,
954+ config. is_running_on_ci ,
955+ & config. exec_ctx ,
956+ & config. rust_info ,
957+ & config. host_target ,
951958 rust_download_rustc,
952959 debug_assertions_requested,
953960 config. llvm_assertions ,
@@ -2340,3 +2347,123 @@ pub fn check_stage0_version(
23402347 ) ) ;
23412348 }
23422349}
2350+
2351+ pub fn download_ci_rustc_commit (
2352+ stage0_metadata : & build_helper:: stage0_parser:: Stage0 ,
2353+ path_modification_cache : Arc < Mutex < HashMap < Vec < & ' static str > , PathFreshness > > > ,
2354+ src : & Path ,
2355+ is_running_on_ci : bool ,
2356+ exec_ctx : & ExecutionContext ,
2357+ rust_info : & channel:: GitInfo ,
2358+ host_target : & TargetSelection ,
2359+ download_rustc : Option < StringOrBool > ,
2360+ debug_assertions_requested : bool ,
2361+ llvm_assertions : bool ,
2362+ ) -> Option < String > {
2363+ if !is_download_ci_available ( & host_target. triple , llvm_assertions) {
2364+ return None ;
2365+ }
2366+
2367+ // If `download-rustc` is not set, default to rebuilding.
2368+ let if_unchanged = match download_rustc {
2369+ // Globally default `download-rustc` to `false`, because some contributors don't use
2370+ // profiles for reasons such as:
2371+ // - They need to seamlessly switch between compiler/library work.
2372+ // - They don't want to use compiler profile because they need to override too many
2373+ // things and it's easier to not use a profile.
2374+ None | Some ( StringOrBool :: Bool ( false ) ) => return None ,
2375+ Some ( StringOrBool :: Bool ( true ) ) => false ,
2376+ Some ( StringOrBool :: String ( s) ) if s == "if-unchanged" => {
2377+ if !rust_info. is_managed_git_subrepository ( ) {
2378+ println ! (
2379+ "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
2380+ ) ;
2381+ crate :: exit!( 1 ) ;
2382+ }
2383+
2384+ true
2385+ }
2386+ Some ( StringOrBool :: String ( other) ) => {
2387+ panic ! ( "unrecognized option for download-rustc: {other}" )
2388+ }
2389+ } ;
2390+
2391+ let commit = if rust_info. is_managed_git_subrepository ( ) {
2392+ // Look for a version to compare to based on the current commit.
2393+ // Only commits merged by bors will have CI artifacts.
2394+ let freshness = check_path_modifications_ (
2395+ stage0_metadata,
2396+ src,
2397+ path_modification_cache,
2398+ RUSTC_IF_UNCHANGED_ALLOWED_PATHS ,
2399+ ) ;
2400+ exec_ctx. verbose ( || {
2401+ eprintln ! ( "rustc freshness: {freshness:?}" ) ;
2402+ } ) ;
2403+ match freshness {
2404+ PathFreshness :: LastModifiedUpstream { upstream } => upstream,
2405+ PathFreshness :: HasLocalModifications { upstream } => {
2406+ if if_unchanged {
2407+ return None ;
2408+ }
2409+
2410+ if is_running_on_ci {
2411+ eprintln ! ( "CI rustc commit matches with HEAD and we are in CI." ) ;
2412+ eprintln ! (
2413+ "`rustc.download-ci` functionality will be skipped as artifacts are not available."
2414+ ) ;
2415+ return None ;
2416+ }
2417+
2418+ upstream
2419+ }
2420+ PathFreshness :: MissingUpstream => {
2421+ eprintln ! ( "No upstream commit found" ) ;
2422+ return None ;
2423+ }
2424+ }
2425+ } else {
2426+ channel:: read_commit_info_file ( src)
2427+ . map ( |info| info. sha . trim ( ) . to_owned ( ) )
2428+ . expect ( "git-commit-info is missing in the project root" )
2429+ } ;
2430+
2431+ if debug_assertions_requested {
2432+ eprintln ! (
2433+ "WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \
2434+ rustc is not currently built with debug assertions."
2435+ ) ;
2436+ return None ;
2437+ }
2438+
2439+ Some ( commit)
2440+ }
2441+
2442+ pub fn check_path_modifications_ (
2443+ stage0_metadata : & build_helper:: stage0_parser:: Stage0 ,
2444+ src : & Path ,
2445+ path_modification_cache : Arc < Mutex < HashMap < Vec < & ' static str > , PathFreshness > > > ,
2446+ paths : & [ & ' static str ] ,
2447+ ) -> PathFreshness {
2448+ // Checking path modifications through git can be relatively expensive (>100ms).
2449+ // We do not assume that the sources would change during bootstrap's execution,
2450+ // so we can cache the results here.
2451+ // Note that we do not use a static variable for the cache, because it would cause problems
2452+ // in tests that create separate `Config` instsances.
2453+ path_modification_cache
2454+ . lock ( )
2455+ . unwrap ( )
2456+ . entry ( paths. to_vec ( ) )
2457+ . or_insert_with ( || {
2458+ check_path_modifications ( src, & git_config ( stage0_metadata) , paths, CiEnv :: current ( ) )
2459+ . unwrap ( )
2460+ } )
2461+ . clone ( )
2462+ }
2463+
2464+ pub fn git_config ( stage0_metadata : & build_helper:: stage0_parser:: Stage0 ) -> GitConfig < ' _ > {
2465+ GitConfig {
2466+ nightly_branch : & stage0_metadata. config . nightly_branch ,
2467+ git_merge_commit_email : & stage0_metadata. config . git_merge_commit_email ,
2468+ }
2469+ }
0 commit comments