2
2
3
3
#![ deny( missing_docs_in_private_items) ]
4
4
5
- use std:: { fmt, fs, io} ;
5
+ use std:: { env , fmt, fs, io, path } ;
6
6
use std:: io:: Read ;
7
7
use syntax:: { ast, codemap} ;
8
- use syntax:: parse:: token;
9
8
use toml;
10
9
11
10
/// Get the configuration file from arguments.
12
- pub fn file ( args : & [ codemap:: Spanned < ast:: NestedMetaItemKind > ] ) -> Result < Option < token :: InternedString > , ( & ' static str , codemap:: Span ) > {
11
+ pub fn file_from_args ( args : & [ codemap:: Spanned < ast:: NestedMetaItemKind > ] ) -> Result < Option < path :: PathBuf > , ( & ' static str , codemap:: Span ) > {
13
12
for arg in args. iter ( ) . filter_map ( |a| a. meta_item ( ) ) {
14
13
match arg. node {
15
14
ast:: MetaItemKind :: Word ( ref name) |
@@ -21,7 +20,7 @@ pub fn file(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option
21
20
ast:: MetaItemKind :: NameValue ( ref name, ref value) => {
22
21
if name == & "conf_file" {
23
22
return if let ast:: LitKind :: Str ( ref file, _) = value. node {
24
- Ok ( Some ( file. clone ( ) ) )
23
+ Ok ( Some ( file. to_string ( ) . into ( ) ) )
25
24
} else {
26
25
Err ( ( "`conf_file` value must be a string" , value. span ) )
27
26
} ;
@@ -179,13 +178,51 @@ define_Conf! {
179
178
( "enum-variant-name-threshold" , enum_variant_name_threshold, 3 => u64 ) ,
180
179
}
181
180
182
- /// Read the `toml` configuration file. The function will ignore “File not found” errors iif
183
- /// `!must_exist`, in which case, it will return the default configuration.
181
+ /// Search for the configuration file.
182
+ pub fn lookup_conf_file ( ) -> io:: Result < Option < path:: PathBuf > > {
183
+ /// Possible filename to search for.
184
+ const CONFIG_FILE_NAMES : [ & ' static str ; 2 ] = [ ".clippy.toml" , "clippy.toml" ] ;
185
+
186
+ let mut current = try!( env:: current_dir ( ) ) ;
187
+
188
+ loop {
189
+ for config_file_name in & CONFIG_FILE_NAMES {
190
+ let config_file = current. join ( config_file_name) ;
191
+ match fs:: metadata ( & config_file) {
192
+ // Only return if it's a file to handle the unlikely situation of a directory named
193
+ // `clippy.toml`.
194
+ Ok ( ref md) if md. is_file ( ) => return Ok ( Some ( config_file) ) ,
195
+ // Return the error if it's something other than `NotFound`; otherwise we didn't
196
+ // find the project file yet, and continue searching.
197
+ Err ( e) => {
198
+ if e. kind ( ) != io:: ErrorKind :: NotFound {
199
+ return Err ( e) ;
200
+ }
201
+ }
202
+ _ => ( ) ,
203
+ }
204
+ }
205
+
206
+ // If the current directory has no parent, we're done searching.
207
+ if !current. pop ( ) {
208
+ return Ok ( None ) ;
209
+ }
210
+ }
211
+ }
212
+
213
+ /// Read the `toml` configuration file.
214
+ ///
184
215
/// In case of error, the function tries to continue as much as possible.
185
- pub fn read ( path : & str , must_exist : bool ) -> ( Conf , Vec < Error > ) {
216
+ pub fn read ( path : Option < & path :: Path > ) -> ( Conf , Vec < Error > ) {
186
217
let mut conf = Conf :: default ( ) ;
187
218
let mut errors = Vec :: new ( ) ;
188
219
220
+ let path = if let Some ( path) = path {
221
+ path
222
+ } else {
223
+ return ( conf, errors) ;
224
+ } ;
225
+
189
226
let file = match fs:: File :: open ( path) {
190
227
Ok ( mut file) => {
191
228
let mut buf = String :: new ( ) ;
@@ -197,9 +234,6 @@ pub fn read(path: &str, must_exist: bool) -> (Conf, Vec<Error>) {
197
234
198
235
buf
199
236
}
200
- Err ( ref err) if !must_exist && err. kind ( ) == io:: ErrorKind :: NotFound => {
201
- return ( conf, errors) ;
202
- }
203
237
Err ( err) => {
204
238
errors. push ( err. into ( ) ) ;
205
239
return ( conf, errors) ;
0 commit comments