Search for clippy.toml recursively

This commit is contained in:
mcarton 2016-10-25 19:41:24 +02:00
parent 49c2c2c628
commit d52af53e04
No known key found for this signature in database
GPG Key ID: 5E427C794CBA45E8
2 changed files with 55 additions and 15 deletions

View File

@ -136,17 +136,23 @@ mod reexport {
#[cfg_attr(rustfmt, rustfmt_skip)]
pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
let conf = match utils::conf::file(reg.args()) {
let conf = match utils::conf::file_from_args(reg.args()) {
Ok(file_name) => {
// if the user specified a file, it must exist, otherwise default to `clippy.toml` but
// do not require the file to exist
let (file_name, must_exist) = if let Some(ref file_name) = file_name {
(&**file_name, true)
let file_name = if let Some(file_name) = file_name {
Some(file_name)
} else {
("clippy.toml", false)
match utils::conf::lookup_conf_file() {
Ok(path) => path,
Err(error) => {
reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", error)).emit();
None
}
}
};
let (conf, errors) = utils::conf::read(file_name, must_exist);
let (conf, errors) = utils::conf::read(file_name.as_ref().map(|p| p.as_ref()));
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {

View File

@ -2,14 +2,13 @@
#![deny(missing_docs_in_private_items)]
use std::{fmt, fs, io};
use std::{env, fmt, fs, io, path};
use std::io::Read;
use syntax::{ast, codemap};
use syntax::parse::token;
use toml;
/// Get the configuration file from arguments.
pub fn file(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> {
pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> {
for arg in args.iter().filter_map(|a| a.meta_item()) {
match arg.node {
ast::MetaItemKind::Word(ref name) |
@ -21,7 +20,7 @@ pub fn file(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option
ast::MetaItemKind::NameValue(ref name, ref value) => {
if name == &"conf_file" {
return if let ast::LitKind::Str(ref file, _) = value.node {
Ok(Some(file.clone()))
Ok(Some(file.to_string().into()))
} else {
Err(("`conf_file` value must be a string", value.span))
};
@ -179,13 +178,51 @@ define_Conf! {
("enum-variant-name-threshold", enum_variant_name_threshold, 3 => u64),
}
/// Read the `toml` configuration file. The function will ignore “File not found” errors iif
/// `!must_exist`, in which case, it will return the default configuration.
/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
/// Possible filename to search for.
const CONFIG_FILE_NAMES: [&'static str; 2] = [".clippy.toml", "clippy.toml"];
let mut current = try!(env::current_dir());
loop {
for config_file_name in &CONFIG_FILE_NAMES {
let config_file = current.join(config_file_name);
match fs::metadata(&config_file) {
// Only return if it's a file to handle the unlikely situation of a directory named
// `clippy.toml`.
Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
// Return the error if it's something other than `NotFound`; otherwise we didn't
// find the project file yet, and continue searching.
Err(e) => {
if e.kind() != io::ErrorKind::NotFound {
return Err(e);
}
}
_ => (),
}
}
// If the current directory has no parent, we're done searching.
if !current.pop() {
return Ok(None);
}
}
}
/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: &str, must_exist: bool) -> (Conf, Vec<Error>) {
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
let mut conf = Conf::default();
let mut errors = Vec::new();
let path = if let Some(path) = path {
path
} else {
return (conf, errors);
};
let file = match fs::File::open(path) {
Ok(mut file) => {
let mut buf = String::new();
@ -197,9 +234,6 @@ pub fn read(path: &str, must_exist: bool) -> (Conf, Vec<Error>) {
buf
}
Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => {
return (conf, errors);
}
Err(err) => {
errors.push(err.into());
return (conf, errors);