@@ -24,7 +24,7 @@ use std::{cmp, env, fs};
24
24
25
25
use build_helper:: ci:: CiEnv ;
26
26
use build_helper:: exit;
27
- use build_helper:: git:: { GitConfig , PathFreshness , check_path_modifications, output_result } ;
27
+ use build_helper:: git:: { GitConfig , PathFreshness , check_path_modifications} ;
28
28
use serde:: Deserialize ;
29
29
#[ cfg( feature = "tracing" ) ]
30
30
use tracing:: { instrument, span} ;
@@ -47,8 +47,10 @@ use crate::core::config::{
47
47
} ;
48
48
use crate :: core:: download:: is_download_ci_available;
49
49
use crate :: utils:: channel;
50
+ use crate :: utils:: exec:: command;
51
+ use crate :: utils:: execution_context:: ExecutionContext ;
50
52
use crate :: utils:: helpers:: exe;
51
- use crate :: { Command , GitInfo , OnceLock , TargetSelection , check_ci_llvm, helpers, output , t} ;
53
+ use crate :: { GitInfo , OnceLock , TargetSelection , check_ci_llvm, helpers, t} ;
52
54
53
55
/// Each path from this function is considered "allowed" in the `download-rustc="if-unchanged"` logic.
54
56
/// This means they can be modified and changes to these paths should never trigger a compiler build
@@ -142,7 +144,6 @@ pub struct Config {
142
144
pub jobs : Option < u32 > ,
143
145
pub cmd : Subcommand ,
144
146
pub incremental : bool ,
145
- pub dry_run : DryRun ,
146
147
pub dump_bootstrap_shims : bool ,
147
148
/// Arguments appearing after `--` to be forwarded to tools,
148
149
/// e.g. `--fix-broken` or test arguments.
@@ -317,6 +318,8 @@ pub struct Config {
317
318
/// This is mostly for RA as building the stage1 compiler to check the library tree
318
319
/// on each code change might be too much for some computers.
319
320
pub skip_std_check_if_no_download_rustc : bool ,
321
+
322
+ pub exec_ctx : ExecutionContext ,
320
323
}
321
324
322
325
impl Config {
@@ -373,6 +376,14 @@ impl Config {
373
376
}
374
377
}
375
378
379
+ pub fn set_dry_run ( & mut self , dry_run : DryRun ) {
380
+ self . exec_ctx . set_dry_run ( dry_run) ;
381
+ }
382
+
383
+ pub fn get_dry_run ( & self ) -> & DryRun {
384
+ self . exec_ctx . get_dry_run ( )
385
+ }
386
+
376
387
#[ cfg_attr(
377
388
feature = "tracing" ,
378
389
instrument( target = "CONFIG_HANDLING" , level = "trace" , name = "Config::parse" , skip_all)
@@ -395,6 +406,11 @@ impl Config {
395
406
get_toml : impl Fn ( & Path ) -> Result < TomlConfig , toml:: de:: Error > ,
396
407
) -> Config {
397
408
let mut config = Config :: default_opts ( ) ;
409
+ let mut exec_ctx = ExecutionContext :: new ( ) ;
410
+ exec_ctx. set_verbose ( flags. verbose ) ;
411
+ exec_ctx. set_fail_fast ( flags. cmd . fail_fast ( ) ) ;
412
+
413
+ config. exec_ctx = exec_ctx;
398
414
399
415
// Set flags.
400
416
config. paths = std:: mem:: take ( & mut flags. paths ) ;
@@ -423,7 +439,7 @@ impl Config {
423
439
config. on_fail = flags. on_fail ;
424
440
config. cmd = flags. cmd ;
425
441
config. incremental = flags. incremental ;
426
- config. dry_run = if flags. dry_run { DryRun :: UserSelected } else { DryRun :: Disabled } ;
442
+ config. set_dry_run ( if flags. dry_run { DryRun :: UserSelected } else { DryRun :: Disabled } ) ;
427
443
config. dump_bootstrap_shims = flags. dump_bootstrap_shims ;
428
444
config. keep_stage = flags. keep_stage ;
429
445
config. keep_stage_std = flags. keep_stage_std ;
@@ -453,14 +469,9 @@ impl Config {
453
469
// has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
454
470
cmd. arg ( "rev-parse" ) . arg ( "--show-cdup" ) ;
455
471
// Discard stderr because we expect this to fail when building from a tarball.
456
- let output = cmd
457
- . as_command_mut ( )
458
- . stderr ( std:: process:: Stdio :: null ( ) )
459
- . output ( )
460
- . ok ( )
461
- . and_then ( |output| if output. status . success ( ) { Some ( output) } else { None } ) ;
462
- if let Some ( output) = output {
463
- let git_root_relative = String :: from_utf8 ( output. stdout ) . unwrap ( ) ;
472
+ let output = cmd. allow_failure ( ) . run_capture_stdout ( & config) ;
473
+ if output. is_success ( ) {
474
+ let git_root_relative = output. stdout ( ) ;
464
475
// We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
465
476
// and to resolve any relative components.
466
477
let git_root = env:: current_dir ( )
@@ -555,7 +566,7 @@ impl Config {
555
566
build. cargo = build. cargo . take ( ) . or ( std:: env:: var_os ( "CARGO" ) . map ( |p| p. into ( ) ) ) ;
556
567
}
557
568
558
- if GitInfo :: new ( false , & config. src ) . is_from_tarball ( ) && toml. profile . is_none ( ) {
569
+ if config . git_info ( false , & config. src ) . is_from_tarball ( ) && toml. profile . is_none ( ) {
559
570
toml. profile = Some ( "dist" . into ( ) ) ;
560
571
}
561
572
@@ -762,7 +773,12 @@ impl Config {
762
773
} ;
763
774
764
775
config. initial_sysroot = t ! ( PathBuf :: from_str(
765
- output( Command :: new( & config. initial_rustc) . args( [ "--print" , "sysroot" ] ) ) . trim( )
776
+ command( & config. initial_rustc)
777
+ . args( [ "--print" , "sysroot" ] )
778
+ . run_always( )
779
+ . run_capture_stdout( & config)
780
+ . stdout( )
781
+ . trim( )
766
782
) ) ;
767
783
768
784
config. initial_cargo_clippy = cargo_clippy;
@@ -858,19 +874,21 @@ impl Config {
858
874
let default = config. channel == "dev" ;
859
875
config. omit_git_hash = toml. rust . as_ref ( ) . and_then ( |r| r. omit_git_hash ) . unwrap_or ( default) ;
860
876
861
- config. rust_info = GitInfo :: new ( config. omit_git_hash , & config. src ) ;
862
- config. cargo_info = GitInfo :: new ( config. omit_git_hash , & config. src . join ( "src/tools/cargo" ) ) ;
877
+ config. rust_info = config. git_info ( config. omit_git_hash , & config. src ) ;
878
+ config. cargo_info =
879
+ config. git_info ( config. omit_git_hash , & config. src . join ( "src/tools/cargo" ) ) ;
863
880
config. rust_analyzer_info =
864
- GitInfo :: new ( config. omit_git_hash , & config. src . join ( "src/tools/rust-analyzer" ) ) ;
881
+ config . git_info ( config. omit_git_hash , & config. src . join ( "src/tools/rust-analyzer" ) ) ;
865
882
config. clippy_info =
866
- GitInfo :: new ( config. omit_git_hash , & config. src . join ( "src/tools/clippy" ) ) ;
867
- config. miri_info = GitInfo :: new ( config. omit_git_hash , & config. src . join ( "src/tools/miri" ) ) ;
883
+ config. git_info ( config. omit_git_hash , & config. src . join ( "src/tools/clippy" ) ) ;
884
+ config. miri_info =
885
+ config. git_info ( config. omit_git_hash , & config. src . join ( "src/tools/miri" ) ) ;
868
886
config. rustfmt_info =
869
- GitInfo :: new ( config. omit_git_hash , & config. src . join ( "src/tools/rustfmt" ) ) ;
887
+ config . git_info ( config. omit_git_hash , & config. src . join ( "src/tools/rustfmt" ) ) ;
870
888
config. enzyme_info =
871
- GitInfo :: new ( config. omit_git_hash , & config. src . join ( "src/tools/enzyme" ) ) ;
872
- config. in_tree_llvm_info = GitInfo :: new ( false , & config. src . join ( "src/llvm-project" ) ) ;
873
- config. in_tree_gcc_info = GitInfo :: new ( false , & config. src . join ( "src/gcc" ) ) ;
889
+ config . git_info ( config. omit_git_hash , & config. src . join ( "src/tools/enzyme" ) ) ;
890
+ config. in_tree_llvm_info = config . git_info ( false , & config. src . join ( "src/llvm-project" ) ) ;
891
+ config. in_tree_gcc_info = config . git_info ( false , & config. src . join ( "src/gcc" ) ) ;
874
892
875
893
config. vendor = vendor. unwrap_or (
876
894
config. rust_info . is_from_tarball ( )
@@ -1030,28 +1048,13 @@ impl Config {
1030
1048
}
1031
1049
1032
1050
pub fn dry_run ( & self ) -> bool {
1033
- match self . dry_run {
1034
- DryRun :: Disabled => false ,
1035
- DryRun :: SelfCheck | DryRun :: UserSelected => true ,
1036
- }
1051
+ self . exec_ctx . dry_run ( )
1037
1052
}
1038
1053
1039
1054
pub fn is_explicit_stage ( & self ) -> bool {
1040
1055
self . explicit_stage_from_cli || self . explicit_stage_from_config
1041
1056
}
1042
1057
1043
- /// Runs a command, printing out nice contextual information if it fails.
1044
- /// Exits if the command failed to execute at all, otherwise returns its
1045
- /// `status.success()`.
1046
- #[ deprecated = "use `Builder::try_run` instead where possible" ]
1047
- pub ( crate ) fn try_run ( & self , cmd : & mut Command ) -> Result < ( ) , ( ) > {
1048
- if self . dry_run ( ) {
1049
- return Ok ( ( ) ) ;
1050
- }
1051
- self . verbose ( || println ! ( "running: {cmd:?}" ) ) ;
1052
- build_helper:: util:: try_run ( cmd, self . is_verbose ( ) )
1053
- }
1054
-
1055
1058
pub ( crate ) fn test_args ( & self ) -> Vec < & str > {
1056
1059
let mut test_args = match self . cmd {
1057
1060
Subcommand :: Test { ref test_args, .. }
@@ -1085,7 +1088,7 @@ impl Config {
1085
1088
1086
1089
let mut git = helpers:: git ( Some ( & self . src ) ) ;
1087
1090
git. arg ( "show" ) . arg ( format ! ( "{commit}:{}" , file. to_str( ) . unwrap( ) ) ) ;
1088
- output ( git. as_command_mut ( ) )
1091
+ git. run_capture_stdout ( self ) . stdout ( )
1089
1092
}
1090
1093
1091
1094
/// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
@@ -1273,9 +1276,7 @@ impl Config {
1273
1276
1274
1277
/// Runs a function if verbosity is greater than 0
1275
1278
pub fn verbose ( & self , f : impl Fn ( ) ) {
1276
- if self . is_verbose ( ) {
1277
- f ( )
1278
- }
1279
+ self . exec_ctx . verbose ( f) ;
1279
1280
}
1280
1281
1281
1282
pub fn any_sanitizers_to_build ( & self ) -> bool {
@@ -1337,7 +1338,7 @@ impl Config {
1337
1338
1338
1339
// NOTE: The check for the empty directory is here because when running x.py the first time,
1339
1340
// the submodule won't be checked out. Check it out now so we can build it.
1340
- if !GitInfo :: new ( false , & absolute_path) . is_managed_git_subrepository ( )
1341
+ if !self . git_info ( false , & absolute_path) . is_managed_git_subrepository ( )
1341
1342
&& !helpers:: dir_is_empty ( & absolute_path)
1342
1343
{
1343
1344
return ;
@@ -1356,16 +1357,16 @@ impl Config {
1356
1357
} ;
1357
1358
1358
1359
// Determine commit checked out in submodule.
1359
- let checked_out_hash = output ( submodule_git ( ) . args ( [ "rev-parse" , "HEAD" ] ) . as_command_mut ( ) ) ;
1360
+ let checked_out_hash =
1361
+ submodule_git ( ) . args ( [ "rev-parse" , "HEAD" ] ) . run_capture_stdout ( self ) . stdout ( ) ;
1360
1362
let checked_out_hash = checked_out_hash. trim_end ( ) ;
1361
1363
// Determine commit that the submodule *should* have.
1362
- let recorded = output (
1363
- helpers:: git ( Some ( & self . src ) )
1364
- . run_always ( )
1365
- . args ( [ "ls-tree" , "HEAD" ] )
1366
- . arg ( relative_path)
1367
- . as_command_mut ( ) ,
1368
- ) ;
1364
+ let recorded = helpers:: git ( Some ( & self . src ) )
1365
+ . run_always ( )
1366
+ . args ( [ "ls-tree" , "HEAD" ] )
1367
+ . arg ( relative_path)
1368
+ . run_capture_stdout ( self )
1369
+ . stdout ( ) ;
1369
1370
1370
1371
let actual_hash = recorded
1371
1372
. split_whitespace ( )
@@ -1389,20 +1390,18 @@ impl Config {
1389
1390
let update = |progress : bool | {
1390
1391
// Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
1391
1392
// even though that has no relation to the upstream for the submodule.
1392
- let current_branch = output_result (
1393
- helpers:: git ( Some ( & self . src ) )
1394
- . allow_failure ( )
1395
- . run_always ( )
1396
- . args ( [ "symbolic-ref" , "--short" , "HEAD" ] )
1397
- . as_command_mut ( ) ,
1398
- )
1399
- . map ( |b| b. trim ( ) . to_owned ( ) ) ;
1393
+ let current_branch = helpers:: git ( Some ( & self . src ) )
1394
+ . allow_failure ( )
1395
+ . run_always ( )
1396
+ . args ( [ "symbolic-ref" , "--short" , "HEAD" ] )
1397
+ . run_capture ( self ) ;
1400
1398
1401
1399
let mut git = helpers:: git ( Some ( & self . src ) ) . allow_failure ( ) ;
1402
1400
git. run_always ( ) ;
1403
- if let Ok ( branch ) = current_branch {
1401
+ if current_branch . is_success ( ) {
1404
1402
// If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
1405
1403
// This syntax isn't accepted by `branch.{branch}`. Strip it.
1404
+ let branch = current_branch. stdout ( ) ;
1406
1405
let branch = branch. strip_prefix ( "heads/" ) . unwrap_or ( & branch) ;
1407
1406
git. arg ( "-c" ) . arg ( format ! ( "branch.{branch}.remote=origin" ) ) ;
1408
1407
}
@@ -1448,7 +1447,8 @@ impl Config {
1448
1447
return ;
1449
1448
}
1450
1449
1451
- let stage0_output = output ( Command :: new ( program_path) . arg ( "--version" ) ) ;
1450
+ let stage0_output =
1451
+ command ( program_path) . arg ( "--version" ) . run_capture_stdout ( self ) . stdout ( ) ;
1452
1452
let mut stage0_output = stage0_output. lines ( ) . next ( ) . unwrap ( ) . split ( ' ' ) ;
1453
1453
1454
1454
let stage0_name = stage0_output. next ( ) . unwrap ( ) ;
@@ -1754,4 +1754,18 @@ impl Config {
1754
1754
_ => !self . is_system_llvm ( target) ,
1755
1755
}
1756
1756
}
1757
+
1758
+ pub fn exec_ctx ( & self ) -> & ExecutionContext {
1759
+ & self . exec_ctx
1760
+ }
1761
+
1762
+ pub fn git_info ( & self , omit_git_hash : bool , dir : & Path ) -> GitInfo {
1763
+ GitInfo :: new ( omit_git_hash, dir, self )
1764
+ }
1765
+ }
1766
+
1767
+ impl AsRef < ExecutionContext > for Config {
1768
+ fn as_ref ( & self ) -> & ExecutionContext {
1769
+ & self . exec_ctx
1770
+ }
1757
1771
}
0 commit comments