From e81ec20af061d3a58216d4f23c20da87358d0d8a Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Thu, 5 Sep 2019 05:15:19 +0300 Subject: [PATCH] Add --config command line option (#3767) --- config_proc_macro/src/item_enum.rs | 7 +++++- src/bin/main.rs | 35 ++++++++++++++++++++++++++++++ src/config/config_type.rs | 10 +++++++++ tests/rustfmt/main.rs | 34 ++++++++++++++++++++++++----- 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/config_proc_macro/src/item_enum.rs b/config_proc_macro/src/item_enum.rs index d59c87d77bf..dcee77a8549 100644 --- a/config_proc_macro/src/item_enum.rs +++ b/config_proc_macro/src/item_enum.rs @@ -105,13 +105,18 @@ fn impl_from_str(ident: &syn::Ident, variants: &Variants) -> TokenStream { } } }); + let mut err_msg = String::from("Bad variant, expected one of:"); + for v in variants.iter().filter(|v| is_unit(v)) { + err_msg.push_str(&format!(" `{}`", v.ident)); + } + quote! { impl ::std::str::FromStr for #ident { type Err = &'static str; fn from_str(s: &str) -> Result { #if_patterns - return Err("Bad variant"); + return Err(#err_msg); } } } diff --git a/src/bin/main.rs b/src/bin/main.rs index bb12169329a..7290c2f30d5 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -4,6 +4,7 @@ use rustfmt_nightly as rustfmt; +use std::collections::HashMap; use std::env; use std::fs::File; use std::io::{self, stdout, Read, Write}; @@ -132,6 +133,12 @@ fn make_opts() -> Options { "Prints the names of mismatched files that were formatted. Prints the names of \ files that would be formated when used with `--check` mode. ", ); + opts.optmulti( + "", + "config", + "Set options from command line. These settings take priority over .rustfmt.toml", + "[key1=val1,key2=val2...]", + ); if is_nightly { opts.optflag( @@ -478,6 +485,7 @@ struct GetOptsOptions { quiet: bool, verbose: bool, config_path: Option, + inline_config: HashMap, emit_mode: EmitMode, backup: bool, check: bool, @@ -537,6 +545,29 @@ pub fn from_matches(matches: &Matches) -> Result { options.config_path = matches.opt_str("config-path").map(PathBuf::from); + options.inline_config = matches + .opt_strs("config") + .iter() + .flat_map(|config| config.split(",")) + .map( + |key_val| match key_val.char_indices().find(|(_, ch)| *ch == '=') { + Some((middle, _)) => { + let (key, val) = (&key_val[..middle], &key_val[middle + 1..]); + if !Config::is_valid_key_val(key, val) { + Err(format_err!("invalid key=val pair: `{}`", key_val)) + } else { + Ok((key.to_string(), val.to_string())) + } + } + + None => Err(format_err!( + "--config expects comma-separated list of key=val pairs, found `{}`", + key_val + )), + }, + ) + .collect::, _>>()?; + options.check = matches.opt_present("check"); if let Some(ref emit_str) = matches.opt_str("emit") { if options.check { @@ -624,6 +655,10 @@ fn apply_to(self, config: &mut Config) { if self.print_misformatted_file_names { config.set().print_misformatted_file_names(true); } + + for (key, val) in self.inline_config { + config.override_value(&key, &val); + } } fn config_path(&self) -> Option<&Path> { diff --git a/src/config/config_type.rs b/src/config/config_type.rs index 7b91f54877d..7f7e8905fba 100644 --- a/src/config/config_type.rs +++ b/src/config/config_type.rs @@ -178,6 +178,16 @@ pub(crate) fn is_valid_name(name: &str) -> bool { } } + #[allow(unreachable_pub)] + pub fn is_valid_key_val(key: &str, val: &str) -> bool { + match key { + $( + stringify!($i) => val.parse::<$ty>().is_ok(), + )+ + _ => false, + } + } + #[allow(unreachable_pub)] pub fn used_options(&self) -> PartialConfig { PartialConfig { diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index 18ef9b60963..ccf2db120b3 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -30,17 +30,16 @@ fn rustfmt(args: &[&str]) -> (String, String) { } macro_rules! assert_that { - ($args:expr, $check:ident $check_args:tt) => { + ($args:expr, $($check:ident $check_args:tt)&&+) => { let (stdout, stderr) = rustfmt($args); - if !stdout.$check$check_args && !stderr.$check$check_args { + if $(!stdout.$check$check_args && !stderr.$check$check_args)||* { panic!( "Output not expected for rustfmt {:?}\n\ - expected: {}{}\n\ + expected: {}\n\ actual stdout:\n{}\n\ actual stderr:\n{}", $args, - stringify!($check), - stringify!($check_args), + stringify!($( $check$check_args )&&*), stdout, stderr ); @@ -76,3 +75,28 @@ fn print_config() { ); remove_file("minimal-config").unwrap(); } + +#[ignore] +#[test] +fn inline_config() { + // single invocation + assert_that!( + &[ + "--print-config", + "current", + ".", + "--config=color=Never,edition=2018" + ], + contains("color = \"Never\"") && contains("edition = \"2018\"") + ); + + // multiple overriding invocations + assert_that!( + &["--print-config", "current", ".", + "--config", "color=never,edition=2018", + "--config", "color=always,format_strings=true"], + contains("color = \"Always\"") && + contains("edition = \"2018\"") && + contains("format_strings = true") + ); +} -- 2.44.0