Merge pull request #3468 from topecongiro/refactor-create_config

Move some code out of create_config
This commit is contained in:
Seiichi Uchida 2019-03-25 07:24:57 +09:00 committed by GitHub
commit a5cc780c98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 136 additions and 137 deletions

View File

@ -93,19 +93,6 @@ pub struct PartialConfig {
$(pub $i: Option<$ty>),+
}
impl PartialConfig {
pub fn to_toml(&self) -> Result<String, String> {
// Non-user-facing options can't be specified in TOML
let mut cloned = self.clone();
cloned.file_lines = None;
cloned.verbose = None;
cloned.width_heuristics = None;
::toml::to_string(&cloned)
.map_err(|e| format!("Could not output config: {}", e))
}
}
// Macro hygiene won't allow us to make `set_$i()` methods on Config
// for each item, so this struct is used to give the API to set values:
// `config.set().option(false)`. It's pretty ugly. Consider replacing
@ -139,23 +126,6 @@ pub fn $i(&self) -> bool {
}
impl Config {
pub(crate) fn version_meets_requirement(&self) -> bool {
if self.was_set().required_version() {
let version = env!("CARGO_PKG_VERSION");
let required_version = self.required_version();
if version != required_version {
println!(
"Error: rustfmt version ({}) doesn't match the required version ({})",
version,
required_version,
);
return false;
}
}
true
}
$(
pub fn $i(&self) -> $ty {
self.$i.0.set(true);
@ -213,37 +183,6 @@ pub(crate) fn is_valid_name(name: &str) -> bool {
}
}
pub(crate) fn from_toml(toml: &str, dir: &Path) -> Result<Config, String> {
let parsed: ::toml::Value =
toml.parse().map_err(|e| format!("Could not parse TOML: {}", e))?;
let mut err: String = String::new();
{
let table = parsed
.as_table()
.ok_or(String::from("Parsed config was not table"))?;
for key in table.keys() {
if !Config::is_valid_name(key) {
let msg = &format!("Warning: Unknown configuration option `{}`\n", key);
err.push_str(msg)
}
}
}
match parsed.try_into() {
Ok(parsed_config) => {
if !err.is_empty() {
eprint!("{}", err);
}
Ok(Config::default().fill_from_parsed_config(parsed_config, dir))
}
Err(e) => {
err.push_str("Error: Decoding config file failed:\n");
err.push_str(format!("{}\n", e).as_str());
err.push_str("Please check your config file.");
Err(err)
}
}
}
pub fn used_options(&self) -> PartialConfig {
PartialConfig {
$(
@ -287,82 +226,6 @@ pub fn override_value(&mut self, key: &str, val: &str)
}
}
/// Constructs 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`.
///
/// Returns a `Config` if the config could be read and parsed from
/// the file, otherwise errors.
pub(super) 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, file_path.parent().unwrap())
.map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
/// Resolves 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(super) 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(&current) {
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() {
break;
}
}
// If nothing was found, check in the home directory.
if let Some(home_dir) = dirs::home_dir() {
if let Some(path) = get_toml_path(&home_dir)? {
return Ok(Some(path));
}
}
// If none was found ther either, check in the user's configuration directory.
if let Some(mut config_dir) = dirs::config_dir() {
config_dir.push("rustfmt");
if let Some(path) = get_toml_path(&config_dir)? {
return Ok(Some(path));
}
}
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 is_hidden_option(name: &str) -> bool {
const HIDE_OPTIONS: [&str; 4] =
["verbose", "verbose_diff", "file_lines", "width_heuristics"];

View File

@ -150,6 +150,142 @@
make_backup: bool, false, false, "Backup changed files";
}
impl PartialConfig {
pub fn to_toml(&self) -> Result<String, String> {
// Non-user-facing options can't be specified in TOML
let mut cloned = self.clone();
cloned.file_lines = None;
cloned.verbose = None;
cloned.width_heuristics = None;
::toml::to_string(&cloned).map_err(|e| format!("Could not output config: {}", e))
}
}
impl Config {
pub(crate) fn version_meets_requirement(&self) -> bool {
if self.was_set().required_version() {
let version = env!("CARGO_PKG_VERSION");
let required_version = self.required_version();
if version != required_version {
println!(
"Error: rustfmt version ({}) doesn't match the required version ({})",
version, required_version,
);
return false;
}
}
true
}
/// Constructs 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`.
///
/// Returns a `Config` if the config could be read and parsed from
/// the file, otherwise errors.
pub(super) 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, file_path.parent().unwrap())
.map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
/// Resolves 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(super) 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(&current) {
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() {
break;
}
}
// If nothing was found, check in the home directory.
if let Some(home_dir) = dirs::home_dir() {
if let Some(path) = get_toml_path(&home_dir)? {
return Ok(Some(path));
}
}
// If none was found ther either, check in the user's configuration directory.
if let Some(mut config_dir) = dirs::config_dir() {
config_dir.push("rustfmt");
if let Some(path) = get_toml_path(&config_dir)? {
return Ok(Some(path));
}
}
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(crate) fn from_toml(toml: &str, dir: &Path) -> Result<Config, String> {
let parsed: ::toml::Value = toml
.parse()
.map_err(|e| format!("Could not parse TOML: {}", e))?;
let mut err: String = String::new();
{
let table = parsed
.as_table()
.ok_or(String::from("Parsed config was not table"))?;
for key in table.keys() {
if !Config::is_valid_name(key) {
let msg = &format!("Warning: Unknown configuration option `{}`\n", key);
err.push_str(msg)
}
}
}
match parsed.try_into() {
Ok(parsed_config) => {
if !err.is_empty() {
eprint!("{}", err);
}
Ok(Config::default().fill_from_parsed_config(parsed_config, dir))
}
Err(e) => {
err.push_str("Error: Decoding config file failed:\n");
err.push_str(format!("{}\n", e).as_str());
err.push_str("Please check your config file.");
Err(err)
}
}
}
}
/// Loads a config by checking the client-supplied options and if appropriate, the
/// file system (including searching the file system for overrides).
pub fn load_config<O: CliOptions>(