@@ -19,6 +19,7 @@ use std::process::Command;
1919use std:: str:: FromStr ;
2020
2121use crate :: core:: build_steps:: compile:: CODEGEN_BACKEND_PREFIX ;
22+ use crate :: core:: build_steps:: llvm;
2223use crate :: core:: config:: flags:: { Color , Flags , Warnings } ;
2324use crate :: utils:: cache:: { Interned , INTERNER } ;
2425use crate :: utils:: channel:: { self , GitInfo } ;
@@ -1526,17 +1527,7 @@ impl Config {
15261527 config. llvm_build_config = llvm. build_config . clone ( ) . unwrap_or ( Default :: default ( ) ) ;
15271528
15281529 let asserts = llvm_assertions. unwrap_or ( false ) ;
1529- config. llvm_from_ci = match llvm. download_ci_llvm {
1530- Some ( StringOrBool :: String ( s) ) => {
1531- assert_eq ! ( s, "if-available" , "unknown option `{s}` for download-ci-llvm" ) ;
1532- crate :: core:: build_steps:: llvm:: is_ci_llvm_available ( & config, asserts)
1533- }
1534- Some ( StringOrBool :: Bool ( b) ) => b,
1535- None => {
1536- config. channel == "dev"
1537- && crate :: core:: build_steps:: llvm:: is_ci_llvm_available ( & config, asserts)
1538- }
1539- } ;
1530+ config. llvm_from_ci = config. parse_download_ci_llvm ( llvm. download_ci_llvm , asserts) ;
15401531
15411532 if config. llvm_from_ci {
15421533 // None of the LLVM options, except assertions, are supported
@@ -2100,6 +2091,90 @@ impl Config {
21002091
21012092 Some ( commit. to_string ( ) )
21022093 }
2094+
2095+ fn parse_download_ci_llvm (
2096+ & self ,
2097+ download_ci_llvm : Option < StringOrBool > ,
2098+ asserts : bool ,
2099+ ) -> bool {
2100+ match download_ci_llvm {
2101+ None => self . channel == "dev" && llvm:: is_ci_llvm_available ( & self , asserts) ,
2102+ Some ( StringOrBool :: Bool ( b) ) => b,
2103+ Some ( StringOrBool :: String ( s) ) if s == "if-available" => {
2104+ llvm:: is_ci_llvm_available ( & self , asserts)
2105+ }
2106+ Some ( StringOrBool :: String ( s) ) if s == "if-unchanged" => {
2107+ if self
2108+ . last_modified_commit ( & [ "src/llvm-project" ] , "download-ci-llvm" , true )
2109+ . is_none ( )
2110+ {
2111+ // there are some untracked changes in the the given paths.
2112+ false
2113+ } else {
2114+ llvm:: is_ci_llvm_available ( & self , asserts)
2115+ }
2116+ }
2117+ Some ( StringOrBool :: String ( other) ) => {
2118+ panic ! ( "unrecognized option for download-ci-llvm: {:?}" , other)
2119+ }
2120+ }
2121+ }
2122+
2123+ /// Returns the last commit in which any of `modified_paths` were changed,
2124+ /// or `None` if there are untracked changes in the working directory and `if_unchanged` is true.
2125+ pub fn last_modified_commit (
2126+ & self ,
2127+ modified_paths : & [ & str ] ,
2128+ option_name : & str ,
2129+ if_unchanged : bool ,
2130+ ) -> Option < String > {
2131+ // Handle running from a directory other than the top level
2132+ let top_level = output ( self . git ( ) . args ( & [ "rev-parse" , "--show-toplevel" ] ) ) ;
2133+ let top_level = top_level. trim_end ( ) ;
2134+
2135+ // Look for a version to compare to based on the current commit.
2136+ // Only commits merged by bors will have CI artifacts.
2137+ let merge_base = output (
2138+ self . git ( )
2139+ . arg ( "rev-list" )
2140+ . arg ( format ! ( "--author={}" , self . stage0_metadata. config. git_merge_commit_email) )
2141+ . args ( & [ "-n1" , "--first-parent" , "HEAD" ] ) ,
2142+ ) ;
2143+ let commit = merge_base. trim_end ( ) ;
2144+ if commit. is_empty ( ) {
2145+ println ! ( "error: could not find commit hash for downloading components from CI" ) ;
2146+ println ! ( "help: maybe your repository history is too shallow?" ) ;
2147+ println ! ( "help: consider disabling `{option_name}`" ) ;
2148+ println ! ( "help: or fetch enough history to include one upstream commit" ) ;
2149+ crate :: exit!( 1 ) ;
2150+ }
2151+
2152+ // Warn if there were changes to the compiler or standard library since the ancestor commit.
2153+ let mut git = self . git ( ) ;
2154+ git. args ( & [ "diff-index" , "--quiet" , & commit, "--" ] ) ;
2155+
2156+ for path in modified_paths {
2157+ git. arg ( format ! ( "{top_level}/{path}" ) ) ;
2158+ }
2159+
2160+ let has_changes = !t ! ( git. status( ) ) . success ( ) ;
2161+ if has_changes {
2162+ if if_unchanged {
2163+ if self . verbose > 0 {
2164+ println ! (
2165+ "warning: saw changes to one of {modified_paths:?} since {commit}; \
2166+ ignoring `{option_name}`"
2167+ ) ;
2168+ }
2169+ return None ;
2170+ }
2171+ println ! (
2172+ "warning: `{option_name}` is enabled, but there are changes to one of {modified_paths:?}"
2173+ ) ;
2174+ }
2175+
2176+ Some ( commit. to_string ( ) )
2177+ }
21032178}
21042179
21052180fn set < T > ( field : & mut T , val : Option < T > ) {
0 commit comments