@@ -117,12 +117,131 @@ macro_rules! get_value_typed {
117
117
} ;
118
118
}
119
119
120
+ /// The purpose of this function is to aid in the transition to using
121
+ /// .toml extensions on Cargo's config files, which were historically not used.
122
+ /// Both 'config.toml' and 'credentials.toml' should be valid with or without extension.
123
+ /// When both exist, we want to prefer the one without an extension for
124
+ /// backwards compatibility, but warn the user appropriately.
125
+ fn get_file_path (
126
+ dir : & Path ,
127
+ filename_without_extension : & str ,
128
+ warn : bool ,
129
+ shell : & RefCell < Shell > ,
130
+ ) -> CargoResult < Option < PathBuf > > {
131
+ let possible = dir. join ( filename_without_extension) ;
132
+ let possible_with_extension = dir. join ( format ! ( "{}.toml" , filename_without_extension) ) ;
133
+
134
+ if possible. exists ( ) {
135
+ if warn && possible_with_extension. exists ( ) {
136
+ // We don't want to print a warning if the version
137
+ // without the extension is just a symlink to the version
138
+ // WITH an extension, which people may want to do to
139
+ // support multiple Cargo versions at once and not
140
+ // get a warning.
141
+ let skip_warning = if let Ok ( target_path) = fs:: read_link ( & possible) {
142
+ target_path == possible_with_extension
143
+ } else {
144
+ false
145
+ } ;
146
+
147
+ if !skip_warning {
148
+ shell. borrow_mut ( ) . warn ( format ! (
149
+ "Both `{}` and `{}` exist. Using `{}`" ,
150
+ possible. display( ) ,
151
+ possible_with_extension. display( ) ,
152
+ possible. display( )
153
+ ) ) ?;
154
+ }
155
+ }
156
+
157
+ Ok ( Some ( possible) )
158
+ } else if possible_with_extension. exists ( ) {
159
+ Ok ( Some ( possible_with_extension) )
160
+ } else {
161
+ Ok ( None )
162
+ }
163
+ }
164
+
165
+ /// Select how config files are found
166
+ #[ derive( Debug ) ]
167
+ pub enum ConfigResolver {
168
+ /// Default heirarchical algorithm: walk up from current dir towards root, and
169
+ /// also fall back to home directory.
170
+ Heirarchical { cwd : PathBuf , home : Option < PathBuf > } ,
171
+ /// Search a list of paths in the specified order
172
+ ConfigPath { path : Vec < PathBuf > } ,
173
+ }
174
+
175
+ impl ConfigResolver {
176
+ fn from_env ( cwd : & Path , home : Option < & Path > , env : & HashMap < String , String > ) -> Self {
177
+ if let Some ( path) = env. get ( "CARGO_CONFIG_PATH" ) {
178
+ Self :: with_path ( & path)
179
+ } else {
180
+ ConfigResolver :: Heirarchical {
181
+ cwd : cwd. to_path_buf ( ) ,
182
+ home : home. map ( Path :: to_path_buf) ,
183
+ }
184
+ }
185
+ }
186
+
187
+ fn with_path ( path : & str ) -> Self {
188
+ ConfigResolver :: ConfigPath {
189
+ path : path. split ( ':' ) . map ( PathBuf :: from) . collect ( ) ,
190
+ }
191
+ }
192
+
193
+ fn resolve < F > ( & self , shell : & RefCell < Shell > , mut walk : F ) -> CargoResult < ( ) >
194
+ where
195
+ F : FnMut ( & Path ) -> CargoResult < ( ) > ,
196
+ {
197
+ let mut stash: HashSet < PathBuf > = HashSet :: new ( ) ;
198
+
199
+ match self {
200
+ ConfigResolver :: Heirarchical { cwd, home } => {
201
+ for current in paths:: ancestors ( cwd) {
202
+ if let Some ( path) =
203
+ get_file_path ( & current. join ( ".cargo" ) , "config" , true , shell) ?
204
+ {
205
+ walk ( & path) ?;
206
+ stash. insert ( path) ;
207
+ }
208
+ }
209
+
210
+ // Once we're done, also be sure to walk the home directory even if it's not
211
+ // in our history to be sure we pick up that standard location for
212
+ // information.
213
+ if let Some ( home) = home {
214
+ if let Some ( path) = get_file_path ( home, "config" , true , shell) ? {
215
+ if !stash. contains ( & path) {
216
+ walk ( & path) ?;
217
+ }
218
+ }
219
+ }
220
+ }
221
+
222
+ ConfigResolver :: ConfigPath { path } => {
223
+ for dir in path {
224
+ if let Some ( path) = get_file_path ( & dir. join ( ".cargo" ) , "config" , true , shell) ? {
225
+ if !stash. contains ( dir) {
226
+ walk ( & path) ?;
227
+ stash. insert ( path) ;
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ Ok ( ( ) )
234
+ }
235
+ }
236
+
120
237
/// Configuration information for cargo. This is not specific to a build, it is information
121
238
/// relating to cargo itself.
122
239
#[ derive( Debug ) ]
123
240
pub struct Config {
124
241
/// The location of the user's 'home' directory. OS-dependent.
125
242
home_path : Filesystem ,
243
+ /// How to resolve paths of configuration files
244
+ resolver : ConfigResolver ,
126
245
/// Information about how to write messages to the shell
127
246
shell : RefCell < Shell > ,
128
247
/// A collection of configuration options
@@ -210,6 +329,7 @@ impl Config {
210
329
} ;
211
330
212
331
Config {
332
+ resolver : ConfigResolver :: from_env ( & cwd, Some ( & homedir) , & env) ,
213
333
home_path : Filesystem :: new ( homedir) ,
214
334
shell : RefCell :: new ( shell) ,
215
335
cwd,
@@ -418,10 +538,14 @@ impl Config {
418
538
}
419
539
}
420
540
421
- /// Reloads on-disk configuration values, starting at the given path and
422
- /// walking up its ancestors.
423
541
pub fn reload_rooted_at < P : AsRef < Path > > ( & mut self , path : P ) -> CargoResult < ( ) > {
424
- let values = self . load_values_from ( path. as_ref ( ) ) ?;
542
+ let path = path. as_ref ( ) ;
543
+ // We treat the path as advisory if the user has overridden the config search path
544
+ let values = self . load_values_from ( & ConfigResolver :: from_env (
545
+ path,
546
+ homedir ( path) . as_ref ( ) . map ( PathBuf :: as_path) ,
547
+ & self . env ,
548
+ ) ) ?;
425
549
self . values . replace ( values) ;
426
550
self . merge_cli_args ( ) ?;
427
551
Ok ( ( ) )
@@ -774,22 +898,26 @@ impl Config {
774
898
775
899
/// Loads configuration from the filesystem.
776
900
pub fn load_values ( & self ) -> CargoResult < HashMap < String , ConfigValue > > {
777
- self . load_values_from ( & self . cwd )
901
+ self . load_values_from ( & self . resolver )
778
902
}
779
903
780
- fn load_values_from ( & self , path : & Path ) -> CargoResult < HashMap < String , ConfigValue > > {
904
+ fn load_values_from (
905
+ & self ,
906
+ resolver : & ConfigResolver ,
907
+ ) -> CargoResult < HashMap < String , ConfigValue > > {
781
908
// This definition path is ignored, this is just a temporary container
782
909
// representing the entire file.
783
910
let mut cfg = CV :: Table ( HashMap :: new ( ) , Definition :: Path ( PathBuf :: from ( "." ) ) ) ;
784
- let home = self . home_path . clone ( ) . into_path_unlocked ( ) ;
785
911
786
- self . walk_tree ( path, & home, |path| {
787
- let value = self . load_file ( path) ?;
788
- cfg. merge ( value, false )
789
- . chain_err ( || format ! ( "failed to merge configuration at `{}`" , path. display( ) ) ) ?;
790
- Ok ( ( ) )
791
- } )
792
- . chain_err ( || "could not load Cargo configuration" ) ?;
912
+ resolver
913
+ . resolve ( & self . shell , |path| {
914
+ let value = self . load_file ( path) ?;
915
+ cfg. merge ( value, false ) . chain_err ( || {
916
+ format ! ( "failed to merge configuration at `{}`" , path. display( ) )
917
+ } ) ?;
918
+ Ok ( ( ) )
919
+ } )
920
+ . chain_err ( || "could not load Cargo configuration" ) ?;
793
921
794
922
match cfg {
795
923
CV :: Table ( map, _) => Ok ( map) ,
@@ -935,76 +1063,6 @@ impl Config {
935
1063
Ok ( ( ) )
936
1064
}
937
1065
938
- /// The purpose of this function is to aid in the transition to using
939
- /// .toml extensions on Cargo's config files, which were historically not used.
940
- /// Both 'config.toml' and 'credentials.toml' should be valid with or without extension.
941
- /// When both exist, we want to prefer the one without an extension for
942
- /// backwards compatibility, but warn the user appropriately.
943
- fn get_file_path (
944
- & self ,
945
- dir : & Path ,
946
- filename_without_extension : & str ,
947
- warn : bool ,
948
- ) -> CargoResult < Option < PathBuf > > {
949
- let possible = dir. join ( filename_without_extension) ;
950
- let possible_with_extension = dir. join ( format ! ( "{}.toml" , filename_without_extension) ) ;
951
-
952
- if possible. exists ( ) {
953
- if warn && possible_with_extension. exists ( ) {
954
- // We don't want to print a warning if the version
955
- // without the extension is just a symlink to the version
956
- // WITH an extension, which people may want to do to
957
- // support multiple Cargo versions at once and not
958
- // get a warning.
959
- let skip_warning = if let Ok ( target_path) = fs:: read_link ( & possible) {
960
- target_path == possible_with_extension
961
- } else {
962
- false
963
- } ;
964
-
965
- if !skip_warning {
966
- self . shell ( ) . warn ( format ! (
967
- "Both `{}` and `{}` exist. Using `{}`" ,
968
- possible. display( ) ,
969
- possible_with_extension. display( ) ,
970
- possible. display( )
971
- ) ) ?;
972
- }
973
- }
974
-
975
- Ok ( Some ( possible) )
976
- } else if possible_with_extension. exists ( ) {
977
- Ok ( Some ( possible_with_extension) )
978
- } else {
979
- Ok ( None )
980
- }
981
- }
982
-
983
- fn walk_tree < F > ( & self , pwd : & Path , home : & Path , mut walk : F ) -> CargoResult < ( ) >
984
- where
985
- F : FnMut ( & Path ) -> CargoResult < ( ) > ,
986
- {
987
- let mut stash: HashSet < PathBuf > = HashSet :: new ( ) ;
988
-
989
- for current in paths:: ancestors ( pwd) {
990
- if let Some ( path) = self . get_file_path ( & current. join ( ".cargo" ) , "config" , true ) ? {
991
- walk ( & path) ?;
992
- stash. insert ( path) ;
993
- }
994
- }
995
-
996
- // Once we're done, also be sure to walk the home directory even if it's not
997
- // in our history to be sure we pick up that standard location for
998
- // information.
999
- if let Some ( path) = self . get_file_path ( home, "config" , true ) ? {
1000
- if !stash. contains ( & path) {
1001
- walk ( & path) ?;
1002
- }
1003
- }
1004
-
1005
- Ok ( ( ) )
1006
- }
1007
-
1008
1066
/// Gets the index for a registry.
1009
1067
pub fn get_registry_index ( & self , registry : & str ) -> CargoResult < Url > {
1010
1068
validate_package_name ( registry, "registry name" , "" ) ?;
@@ -1044,7 +1102,7 @@ impl Config {
1044
1102
/// Loads credentials config from the credentials file, if present.
1045
1103
pub fn load_credentials ( & mut self ) -> CargoResult < ( ) > {
1046
1104
let home_path = self . home_path . clone ( ) . into_path_unlocked ( ) ;
1047
- let credentials = match self . get_file_path ( & home_path, "credentials" , true ) ? {
1105
+ let credentials = match get_file_path ( & home_path, "credentials" , true , & self . shell ) ? {
1048
1106
Some ( credentials) => credentials,
1049
1107
None => return Ok ( ( ) ) ,
1050
1108
} ;
@@ -1560,7 +1618,7 @@ pub fn save_credentials(cfg: &Config, token: String, registry: Option<String>) -
1560
1618
// use the legacy 'credentials'. There's no need to print the warning
1561
1619
// here, because it would already be printed at load time.
1562
1620
let home_path = cfg. home_path . clone ( ) . into_path_unlocked ( ) ;
1563
- let filename = match cfg . get_file_path ( & home_path, "credentials" , false ) ? {
1621
+ let filename = match get_file_path ( & home_path, "credentials" , false , & cfg . shell ) ? {
1564
1622
Some ( path) => match path. file_name ( ) {
1565
1623
Some ( filename) => Path :: new ( filename) . to_owned ( ) ,
1566
1624
None => Path :: new ( "credentials" ) . to_owned ( ) ,
0 commit comments