Merge pull request #1613 from khadiwala/master
Expose methods to locate and load config
This commit is contained in:
commit
f6e8e9facc
@ -19,11 +19,11 @@ extern crate getopts;
|
||||
|
||||
use rustfmt::{run, Input, Summary};
|
||||
use rustfmt::file_lines::FileLines;
|
||||
use rustfmt::config::{Config, WriteMode};
|
||||
use rustfmt::config::{Config, WriteMode, get_toml_path};
|
||||
|
||||
use std::{env, error};
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, ErrorKind, Read, Write};
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
@ -95,78 +95,16 @@ impl CliOptions {
|
||||
}
|
||||
}
|
||||
|
||||
const CONFIG_FILE_NAMES: [&'static str; 2] = [".rustfmt.toml", "rustfmt.toml"];
|
||||
|
||||
/// Try to find a project file in the given directory and its parents. Returns the path of a the
|
||||
/// nearest project file if one exists, or `None` if no project file was found.
|
||||
fn lookup_project_file(dir: &Path) -> FmtResult<Option<PathBuf>> {
|
||||
let mut current = if dir.is_relative() {
|
||||
env::current_dir()?.join(dir)
|
||||
} else {
|
||||
dir.to_path_buf()
|
||||
};
|
||||
|
||||
current = fs::canonicalize(current)?;
|
||||
|
||||
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
|
||||
// `rustfmt.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() != ErrorKind::NotFound {
|
||||
return Err(FmtError::from(e));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// If the current directory has no parent, we're done searching.
|
||||
if !current.pop() {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn open_config_file(file_path: &Path) -> FmtResult<(Config, Option<PathBuf>)> {
|
||||
let mut file = File::open(&file_path)?;
|
||||
let mut toml = String::new();
|
||||
file.read_to_string(&mut toml)?;
|
||||
match Config::from_toml(&toml) {
|
||||
Ok(cfg) => Ok((cfg, Some(file_path.to_path_buf()))),
|
||||
Err(err) => Err(FmtError::from(err)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve the config for input in `dir`.
|
||||
///
|
||||
/// Returns the `Config` to use, and the path of the project file if there was
|
||||
/// one.
|
||||
fn resolve_config(dir: &Path) -> FmtResult<(Config, Option<PathBuf>)> {
|
||||
let path = lookup_project_file(dir)?;
|
||||
if path.is_none() {
|
||||
return Ok((Config::default(), None));
|
||||
}
|
||||
open_config_file(&path.unwrap())
|
||||
}
|
||||
|
||||
/// read the given config file path recursively if present else read the project file path
|
||||
fn match_cli_path_or_file(config_path: Option<PathBuf>,
|
||||
input_file: &Path)
|
||||
-> FmtResult<(Config, Option<PathBuf>)> {
|
||||
|
||||
if let Some(config_file) = config_path {
|
||||
let (toml, path) = open_config_file(config_file.as_ref())?;
|
||||
if path.is_some() {
|
||||
return Ok((toml, path));
|
||||
}
|
||||
let toml = Config::from_toml_path(config_file.as_ref())?;
|
||||
return Ok((toml, Some(config_file)));
|
||||
}
|
||||
resolve_config(input_file)
|
||||
Config::from_resolved_toml_path(input_file).map_err(|e| FmtError::from(e))
|
||||
}
|
||||
|
||||
fn make_opts() -> Options {
|
||||
@ -261,16 +199,13 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
|
||||
}
|
||||
|
||||
let mut config = Config::default();
|
||||
let mut path = None;
|
||||
// Load the config path file if provided
|
||||
if let Some(config_file) = config_path {
|
||||
let (cfg_tmp, path_tmp) = open_config_file(config_file.as_ref())?;
|
||||
config = cfg_tmp;
|
||||
path = path_tmp;
|
||||
if let Some(config_file) = config_path.as_ref() {
|
||||
config = Config::from_toml_path(config_file.as_ref())?;
|
||||
};
|
||||
|
||||
if options.verbose {
|
||||
if let Some(path) = path.as_ref() {
|
||||
if let Some(path) = config_path.as_ref() {
|
||||
println!("Using rustfmt config file {}", path.display());
|
||||
}
|
||||
}
|
||||
@ -285,8 +220,9 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
|
||||
error_summary.add_operational_error();
|
||||
} else {
|
||||
// Check the file directory if the config-path could not be read or not provided
|
||||
if path.is_none() {
|
||||
let (config_tmp, path_tmp) = resolve_config(file.parent().unwrap())?;
|
||||
if config_path.is_none() {
|
||||
let (config_tmp, path_tmp) =
|
||||
Config::from_resolved_toml_path(file.parent().unwrap())?;
|
||||
if options.verbose {
|
||||
if let Some(path) = path_tmp.as_ref() {
|
||||
println!("Using rustfmt config file {} for {}",
|
||||
@ -391,13 +327,7 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
|
||||
let config_path: Option<PathBuf> = match matches.opt_str("config-path").map(PathBuf::from) {
|
||||
Some(ref path) if !path.exists() => return config_path_not_found(path.to_str().unwrap()),
|
||||
Some(ref path) if path.is_dir() => {
|
||||
let mut config_file_path = None;
|
||||
for config_file_name in &CONFIG_FILE_NAMES {
|
||||
let temp_path = path.join(config_file_name);
|
||||
if temp_path.is_file() {
|
||||
config_file_path = Some(temp_path);
|
||||
}
|
||||
}
|
||||
let config_file_path = get_toml_path(path)?;
|
||||
if config_file_path.is_some() {
|
||||
config_file_path
|
||||
} else {
|
||||
|
@ -11,6 +11,11 @@
|
||||
extern crate toml;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::env;
|
||||
use std::io::{Error, ErrorKind, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use file_lines::FileLines;
|
||||
use lists::{SeparatorTactic, ListTactic};
|
||||
@ -347,6 +352,64 @@ macro_rules! create_config {
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `Config` from the toml file specified at `file_path`.
|
||||
///
|
||||
/// This method only looks at the provided path, for a method that
|
||||
/// searches parents for a `rustfmt.toml` see `from_resolved_toml_path`.
|
||||
///
|
||||
/// Return a `Config` if the config could be read and parsed from
|
||||
/// the file, Error otherwise.
|
||||
pub fn from_toml_path(file_path: &Path) -> Result<Config, Error> {
|
||||
let mut file = File::open(&file_path)?;
|
||||
let mut toml = String::new();
|
||||
file.read_to_string(&mut toml)?;
|
||||
Config::from_toml(&toml).map_err(|err| Error::new(ErrorKind::InvalidData, err))
|
||||
}
|
||||
|
||||
/// Resolve the config for input in `dir`.
|
||||
///
|
||||
/// Searches for `rustfmt.toml` beginning with `dir`, and
|
||||
/// recursively checking parents of `dir` if no config file is found.
|
||||
/// If no config file exists in `dir` or in any parent, a
|
||||
/// default `Config` will be returned (and the returned path will be empty).
|
||||
///
|
||||
/// Returns the `Config` to use, and the path of the project file if there was
|
||||
/// one.
|
||||
pub fn from_resolved_toml_path(dir: &Path) -> Result<(Config, Option<PathBuf>), Error> {
|
||||
|
||||
/// Try to find a project file in the given directory and its parents.
|
||||
/// Returns the path of a the nearest project file if one exists,
|
||||
/// or `None` if no project file was found.
|
||||
fn resolve_project_file(dir: &Path) -> Result<Option<PathBuf>, Error> {
|
||||
let mut current = if dir.is_relative() {
|
||||
env::current_dir()?.join(dir)
|
||||
} else {
|
||||
dir.to_path_buf()
|
||||
};
|
||||
|
||||
current = fs::canonicalize(current)?;
|
||||
|
||||
loop {
|
||||
match get_toml_path(¤t) {
|
||||
Ok(Some(path)) => return Ok(Some(path)),
|
||||
Err(e) => return Err(e),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
// If the current directory has no parent, we're done searching.
|
||||
if !current.pop() {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match resolve_project_file(dir)? {
|
||||
None => Ok((Config::default(), None)),
|
||||
Some(path) => Config::from_toml_path(&path).map(|config| (config, Some(path))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn print_docs() {
|
||||
use std::cmp;
|
||||
let max = 0;
|
||||
@ -389,6 +452,32 @@ macro_rules! create_config {
|
||||
)
|
||||
}
|
||||
|
||||
/// Check for the presence of known config file names (`rustfmt.toml, `.rustfmt.toml`) in `dir`
|
||||
///
|
||||
/// Return the path if a config file exists, empty if no file exists, and Error for IO errors
|
||||
pub fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
|
||||
const CONFIG_FILE_NAMES: [&'static str; 2] = [".rustfmt.toml", "rustfmt.toml"];
|
||||
for config_file_name in &CONFIG_FILE_NAMES {
|
||||
let config_file = dir.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
|
||||
// `rustfmt.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() != ErrorKind::NotFound {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
|
||||
create_config! {
|
||||
verbose: bool, false, "Use verbose output";
|
||||
disable_all_formatting: bool, false, "Don't reformat anything";
|
||||
|
Loading…
x
Reference in New Issue
Block a user