]> git.lizzy.rs Git - rust.git/commitdiff
Add --config command line option (#3767)
authorCreepySkeleton <creepy-skeleton@yandex.ru>
Thu, 5 Sep 2019 02:15:19 +0000 (05:15 +0300)
committerSeiichi Uchida <seuchida@gmail.com>
Thu, 5 Sep 2019 02:15:19 +0000 (11:15 +0900)
config_proc_macro/src/item_enum.rs
src/bin/main.rs
src/config/config_type.rs
tests/rustfmt/main.rs

index d59c87d77bf448f055d601d9d3c7d2aea9d73db3..dcee77a8549c5b9cf9beacd47663cb39d177c4ce 100644 (file)
@@ -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<Self, Self::Err> {
                 #if_patterns
-                return Err("Bad variant");
+                return Err(#err_msg);
             }
         }
     }
index bb12169329a1e079a1ad601ecfca9f9af674639b..7290c2f30d5a0d8edc211a6a6d69ef3a714895d2 100644 (file)
@@ -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<PathBuf>,
+    inline_config: HashMap<String, String>,
     emit_mode: EmitMode,
     backup: bool,
     check: bool,
@@ -537,6 +545,29 @@ pub fn from_matches(matches: &Matches) -> Result<GetOptsOptions, FailureError> {
 
         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::<Result<HashMap<_, _>, _>>()?;
+
         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> {
index 7b91f54877d3820cce6e1c058622b19afc8a9175..7f7e8905fba92a7025573bce0ee41887a9e2ebed 100644 (file)
@@ -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 {
index 18ef9b609634fa6be46be8ee8f75ff0b20ba9483..ccf2db120b3b65b11b820a33b69ac95c081f5124 100644 (file)
@@ -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")
+    );
+}