@@ -55,6 +55,15 @@ impl OverrideFile {
55
55
fn is_empty ( & self ) -> bool {
56
56
self . toolchain . is_empty ( )
57
57
}
58
+
59
+ fn has_toolchain ( & self ) -> bool {
60
+ self . toolchain . has_toolchain ( )
61
+ }
62
+
63
+ /// A left-biased merge of two [`OverrideFile`]s.
64
+ fn merge ( & mut self , other : Self ) {
65
+ self . toolchain . merge ( other. toolchain )
66
+ }
58
67
}
59
68
60
69
#[ derive( Debug , Default , Deserialize , PartialEq , Eq ) ]
@@ -69,9 +78,33 @@ struct ToolchainSection {
69
78
impl ToolchainSection {
70
79
fn is_empty ( & self ) -> bool {
71
80
self . channel . is_none ( )
81
+ && self . path . is_none ( )
72
82
&& self . components . is_none ( )
73
83
&& self . targets . is_none ( )
74
- && self . path . is_none ( )
84
+ }
85
+
86
+ fn has_toolchain ( & self ) -> bool {
87
+ self . channel . is_some ( ) || self . path . is_some ( )
88
+ }
89
+
90
+ /// A left-biased merge of two [`ToolchainSelection`]s.
91
+ ///
92
+ /// If a field appears in both operands, the one from the left-hand side is selected.
93
+ fn merge ( & mut self , other : Self ) {
94
+ if !self . has_toolchain ( ) {
95
+ // `channel` and `path` are mutually exclusive, so they need to be updated together,
96
+ // and this will happen only if `self` doesn't have a toolchain yet.
97
+ ( self . channel , self . path ) = ( other. channel , other. path ) ;
98
+ }
99
+ if self . components . is_none ( ) {
100
+ self . components = other. components ;
101
+ }
102
+ if self . targets . is_none ( ) {
103
+ self . targets = other. targets ;
104
+ }
105
+ if self . profile . is_none ( ) {
106
+ self . profile = other. profile ;
107
+ }
75
108
}
76
109
}
77
110
@@ -96,6 +129,7 @@ impl<T: Into<String>> From<T> for OverrideFile {
96
129
}
97
130
}
98
131
132
+ /// The reason for which the toolchain is overridden.
99
133
#[ derive( Debug ) ]
100
134
pub ( crate ) enum OverrideReason {
101
135
Environment ,
@@ -453,31 +487,46 @@ impl Cfg {
453
487
}
454
488
455
489
fn find_override_config ( & self , path : & Path ) -> Result < Option < ( OverrideCfg , OverrideReason ) > > {
456
- let mut override_ = None ;
490
+ let mut override_ = None :: < ( OverrideFile , OverrideReason ) > ;
491
+
492
+ let mut update_override = |file, reason| {
493
+ if let Some ( ( file1, reason1) ) = & mut override_ {
494
+ if file1. has_toolchain ( ) {
495
+ // Update the reason only if the override file has a toolchain.
496
+ * reason1 = reason
497
+ }
498
+ file1. merge ( file) ;
499
+ } else {
500
+ override_ = Some ( ( file, reason) )
501
+ } ;
502
+ } ;
503
+
504
+ // Check for all possible toolchain overrides below...
505
+ // See: <https://rust-lang.github.io/rustup/overrides.html>
457
506
458
- // First check toolchain override from command
507
+ // 1. Check toolchain override from command
459
508
if let Some ( ref name) = self . toolchain_override {
460
- override_ = Some ( ( name. to_string ( ) . into ( ) , OverrideReason :: CommandLine ) ) ;
509
+ update_override ( name. to_string ( ) . into ( ) , OverrideReason :: CommandLine ) ;
461
510
}
462
511
463
- // Check RUSTUP_TOOLCHAIN
512
+ // 2. Check RUSTUP_TOOLCHAIN
464
513
if let Some ( ref name) = self . env_override {
465
514
// Because path based toolchain files exist, this has to support
466
515
// custom, distributable, and absolute path toolchains otherwise
467
516
// rustup's export of a RUSTUP_TOOLCHAIN when running a process will
468
517
// error when a nested rustup invocation occurs
469
- override_ = Some ( ( name. to_string ( ) . into ( ) , OverrideReason :: Environment ) ) ;
518
+ update_override ( name. to_string ( ) . into ( ) , OverrideReason :: Environment ) ;
470
519
}
471
520
472
- // Then walk up the directory tree from 'path' looking for either the
473
- // directory in override database, or a `rust-toolchain` file.
474
- if override_ . is_none ( ) {
475
- self . settings_file . with ( |s| {
476
- override_ = self . find_override_from_dir_walk ( path, s) ?;
477
-
478
- Ok ( ( ) )
479
- } ) ? ;
480
- }
521
+ // 3. walk up the directory tree from 'path' looking for either the
522
+ // directory in override database, or
523
+ // 4. a `rust-toolchain` file.
524
+ self . settings_file . with ( |s| {
525
+ if let Some ( ( file , reason ) ) = self . find_override_from_dir_walk ( path, s) ? {
526
+ update_override ( file , reason ) ;
527
+ }
528
+ Ok ( ( ) )
529
+ } ) ? ;
481
530
482
531
if let Some ( ( file, reason) ) = override_ {
483
532
// This is hackishly using the error chain to provide a bit of
0 commit comments