@@ -121,6 +121,20 @@ macro_rules! get_value_typed {
121
121
} ;
122
122
}
123
123
124
+ /// Indicates why a config value is being loaded.
125
+ #[ derive( Clone , Copy , Debug ) ]
126
+ enum WhyLoad {
127
+ /// Loaded due to a request from the global cli arg `--config`
128
+ ///
129
+ /// Indirect configs loaded via [`config-include`] are also seen as from cli args,
130
+ /// if the initial config is being loaded from cli.
131
+ ///
132
+ /// [`config-include`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#config-include
133
+ Cli ,
134
+ /// Loaded due to config file discovery.
135
+ FileDiscovery ,
136
+ }
137
+
124
138
/// Configuration information for cargo. This is not specific to a build, it is information
125
139
/// relating to cargo itself.
126
140
#[ derive( Debug ) ]
@@ -1005,12 +1019,15 @@ impl Config {
1005
1019
self . load_values_from ( & self . cwd )
1006
1020
}
1007
1021
1022
+ /// Like [`load_values`](Config::load_values) but without merging config values.
1023
+ ///
1024
+ /// This is primarily crafted for `cargo config` command.
1008
1025
pub ( crate ) fn load_values_unmerged ( & self ) -> CargoResult < Vec < ConfigValue > > {
1009
1026
let mut result = Vec :: new ( ) ;
1010
1027
let mut seen = HashSet :: new ( ) ;
1011
1028
let home = self . home_path . clone ( ) . into_path_unlocked ( ) ;
1012
1029
self . walk_tree ( & self . cwd , & home, |path| {
1013
- let mut cv = self . _load_file ( path, & mut seen, false ) ?;
1030
+ let mut cv = self . _load_file ( path, & mut seen, false , WhyLoad :: FileDiscovery ) ?;
1014
1031
if self . cli_unstable ( ) . config_include {
1015
1032
self . load_unmerged_include ( & mut cv, & mut seen, & mut result) ?;
1016
1033
}
@@ -1021,6 +1038,9 @@ impl Config {
1021
1038
Ok ( result)
1022
1039
}
1023
1040
1041
+ /// Like [`load_includes`](Config::load_includes) but without merging config values.
1042
+ ///
1043
+ /// This is primarily crafted for `cargo config` command.
1024
1044
fn load_unmerged_include (
1025
1045
& self ,
1026
1046
cv : & mut CV ,
@@ -1029,23 +1049,26 @@ impl Config {
1029
1049
) -> CargoResult < ( ) > {
1030
1050
let includes = self . include_paths ( cv, false ) ?;
1031
1051
for ( path, abs_path, def) in includes {
1032
- let mut cv = self . _load_file ( & abs_path, seen, false ) . with_context ( || {
1033
- format ! ( "failed to load config include `{}` from `{}`" , path, def)
1034
- } ) ?;
1052
+ let mut cv = self
1053
+ . _load_file ( & abs_path, seen, false , WhyLoad :: FileDiscovery )
1054
+ . with_context ( || {
1055
+ format ! ( "failed to load config include `{}` from `{}`" , path, def)
1056
+ } ) ?;
1035
1057
self . load_unmerged_include ( & mut cv, seen, output) ?;
1036
1058
output. push ( cv) ;
1037
1059
}
1038
1060
Ok ( ( ) )
1039
1061
}
1040
1062
1063
+ /// Start a config file discovery from a path and merges all config values found.
1041
1064
fn load_values_from ( & self , path : & Path ) -> CargoResult < HashMap < String , ConfigValue > > {
1042
1065
// This definition path is ignored, this is just a temporary container
1043
1066
// representing the entire file.
1044
1067
let mut cfg = CV :: Table ( HashMap :: new ( ) , Definition :: Path ( PathBuf :: from ( "." ) ) ) ;
1045
1068
let home = self . home_path . clone ( ) . into_path_unlocked ( ) ;
1046
1069
1047
1070
self . walk_tree ( path, & home, |path| {
1048
- let value = self . load_file ( path, true ) ?;
1071
+ let value = self . load_file ( path) ?;
1049
1072
cfg. merge ( value, false ) . with_context ( || {
1050
1073
format ! ( "failed to merge configuration at `{}`" , path. display( ) )
1051
1074
} ) ?;
@@ -1059,15 +1082,28 @@ impl Config {
1059
1082
}
1060
1083
}
1061
1084
1062
- fn load_file ( & self , path : & Path , includes : bool ) -> CargoResult < ConfigValue > {
1063
- self . _load_file ( path, & mut HashSet :: new ( ) , includes)
1085
+ /// Loads a config value from a path.
1086
+ ///
1087
+ /// This is used during config file discovery.
1088
+ fn load_file ( & self , path : & Path ) -> CargoResult < ConfigValue > {
1089
+ self . _load_file ( path, & mut HashSet :: new ( ) , true , WhyLoad :: FileDiscovery )
1064
1090
}
1065
1091
1092
+ /// Loads a config value from a path with options.
1093
+ ///
1094
+ /// This is actual implementation of loading a config value from a path.
1095
+ ///
1096
+ /// * `includes` determines whether to load configs from [`config-include`].
1097
+ /// * `seen` is used to check for cyclic includes.
1098
+ /// * `why_load` tells why a config is being loaded.
1099
+ ///
1100
+ /// [`config-include`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#config-include
1066
1101
fn _load_file (
1067
1102
& self ,
1068
1103
path : & Path ,
1069
1104
seen : & mut HashSet < PathBuf > ,
1070
1105
includes : bool ,
1106
+ why_load : WhyLoad ,
1071
1107
) -> CargoResult < ConfigValue > {
1072
1108
if !seen. insert ( path. to_path_buf ( ) ) {
1073
1109
bail ! (
@@ -1080,15 +1116,18 @@ impl Config {
1080
1116
let toml = cargo_toml:: parse ( & contents, path, self ) . with_context ( || {
1081
1117
format ! ( "could not parse TOML configuration in `{}`" , path. display( ) )
1082
1118
} ) ?;
1083
- let value =
1084
- CV :: from_toml ( Definition :: Path ( path. to_path_buf ( ) ) , toml) . with_context ( || {
1085
- format ! (
1086
- "failed to load TOML configuration from `{}`" ,
1087
- path. display( )
1088
- )
1089
- } ) ?;
1119
+ let def = match why_load {
1120
+ WhyLoad :: Cli => Definition :: Cli ( Some ( path. into ( ) ) ) ,
1121
+ WhyLoad :: FileDiscovery => Definition :: Path ( path. into ( ) ) ,
1122
+ } ;
1123
+ let value = CV :: from_toml ( def, toml) . with_context ( || {
1124
+ format ! (
1125
+ "failed to load TOML configuration from `{}`" ,
1126
+ path. display( )
1127
+ )
1128
+ } ) ?;
1090
1129
if includes {
1091
- self . load_includes ( value, seen)
1130
+ self . load_includes ( value, seen, why_load )
1092
1131
} else {
1093
1132
Ok ( value)
1094
1133
}
@@ -1098,8 +1137,14 @@ impl Config {
1098
1137
///
1099
1138
/// Returns `value` with the given include files merged into it.
1100
1139
///
1101
- /// `seen` is used to check for cyclic includes.
1102
- fn load_includes ( & self , mut value : CV , seen : & mut HashSet < PathBuf > ) -> CargoResult < CV > {
1140
+ /// * `seen` is used to check for cyclic includes.
1141
+ /// * `why_load` tells why a config is being loaded.
1142
+ fn load_includes (
1143
+ & self ,
1144
+ mut value : CV ,
1145
+ seen : & mut HashSet < PathBuf > ,
1146
+ why_load : WhyLoad ,
1147
+ ) -> CargoResult < CV > {
1103
1148
// Get the list of files to load.
1104
1149
let includes = self . include_paths ( & mut value, true ) ?;
1105
1150
// Check unstable.
@@ -1109,7 +1154,7 @@ impl Config {
1109
1154
// Accumulate all values here.
1110
1155
let mut root = CV :: Table ( HashMap :: new ( ) , value. definition ( ) . clone ( ) ) ;
1111
1156
for ( path, abs_path, def) in includes {
1112
- self . _load_file ( & abs_path, seen, true )
1157
+ self . _load_file ( & abs_path, seen, true , why_load )
1113
1158
. and_then ( |include| root. merge ( include, true ) )
1114
1159
. with_context ( || {
1115
1160
format ! ( "failed to load config include `{}` from `{}`" , path, def)
@@ -1127,8 +1172,8 @@ impl Config {
1127
1172
) -> CargoResult < Vec < ( String , PathBuf , Definition ) > > {
1128
1173
let abs = |path : & str , def : & Definition | -> ( String , PathBuf , Definition ) {
1129
1174
let abs_path = match def {
1130
- Definition :: Path ( p) => p. parent ( ) . unwrap ( ) . join ( & path) ,
1131
- Definition :: Environment ( _) | Definition :: Cli => self . cwd ( ) . join ( & path) ,
1175
+ Definition :: Path ( p) | Definition :: Cli ( Some ( p ) ) => p. parent ( ) . unwrap ( ) . join ( & path) ,
1176
+ Definition :: Environment ( _) | Definition :: Cli ( None ) => self . cwd ( ) . join ( & path) ,
1132
1177
} ;
1133
1178
( path. to_string ( ) , abs_path, def. clone ( ) )
1134
1179
} ;
@@ -1162,7 +1207,7 @@ impl Config {
1162
1207
1163
1208
/// Parses the CLI config args and returns them as a table.
1164
1209
pub ( crate ) fn cli_args_as_table ( & self ) -> CargoResult < ConfigValue > {
1165
- let mut loaded_args = CV :: Table ( HashMap :: new ( ) , Definition :: Cli ) ;
1210
+ let mut loaded_args = CV :: Table ( HashMap :: new ( ) , Definition :: Cli ( None ) ) ;
1166
1211
let cli_args = match & self . cli_config {
1167
1212
Some ( cli_args) => cli_args,
1168
1213
None => return Ok ( loaded_args) ,
@@ -1178,7 +1223,7 @@ impl Config {
1178
1223
anyhow:: format_err!( "config path {:?} is not utf-8" , arg_as_path)
1179
1224
} ) ?
1180
1225
. to_string ( ) ;
1181
- self . _load_file ( & self . cwd ( ) . join ( & str_path) , & mut seen, true )
1226
+ self . _load_file ( & self . cwd ( ) . join ( & str_path) , & mut seen, true , WhyLoad :: Cli )
1182
1227
. with_context ( || format ! ( "failed to load config from `{}`" , str_path) ) ?
1183
1228
} else {
1184
1229
// We only want to allow "dotted key" (see https://toml.io/en/v1.0.0#keys)
@@ -1273,11 +1318,11 @@ impl Config {
1273
1318
) ;
1274
1319
}
1275
1320
1276
- CV :: from_toml ( Definition :: Cli , toml_v)
1321
+ CV :: from_toml ( Definition :: Cli ( None ) , toml_v)
1277
1322
. with_context ( || format ! ( "failed to convert --config argument `{arg}`" ) ) ?
1278
1323
} ;
1279
1324
let tmp_table = self
1280
- . load_includes ( tmp_table, & mut HashSet :: new ( ) )
1325
+ . load_includes ( tmp_table, & mut HashSet :: new ( ) , WhyLoad :: Cli )
1281
1326
. with_context ( || "failed to load --config include" . to_string ( ) ) ?;
1282
1327
loaded_args
1283
1328
. merge ( tmp_table, true )
@@ -1431,7 +1476,7 @@ impl Config {
1431
1476
None => return Ok ( ( ) ) ,
1432
1477
} ;
1433
1478
1434
- let mut value = self . load_file ( & credentials, true ) ?;
1479
+ let mut value = self . load_file ( & credentials) ?;
1435
1480
// Backwards compatibility for old `.cargo/credentials` layout.
1436
1481
{
1437
1482
let ( value_map, def) = match value {
0 commit comments