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