Skip to content

Commit e81ec20

Browse files
CreepySkeletontopecongiro
authored andcommitted
Add --config command line option (#3767)
1 parent 15a28f7 commit e81ec20

File tree

4 files changed

+80
-6
lines changed

4 files changed

+80
-6
lines changed

config_proc_macro/src/item_enum.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,18 @@ fn impl_from_str(ident: &syn::Ident, variants: &Variants) -> TokenStream {
105105
}
106106
}
107107
});
108+
let mut err_msg = String::from("Bad variant, expected one of:");
109+
for v in variants.iter().filter(|v| is_unit(v)) {
110+
err_msg.push_str(&format!(" `{}`", v.ident));
111+
}
112+
108113
quote! {
109114
impl ::std::str::FromStr for #ident {
110115
type Err = &'static str;
111116

112117
fn from_str(s: &str) -> Result<Self, Self::Err> {
113118
#if_patterns
114-
return Err("Bad variant");
119+
return Err(#err_msg);
115120
}
116121
}
117122
}

src/bin/main.rs

+35
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use io::Error as IoError;
44

55
use rustfmt_nightly as rustfmt;
66

7+
use std::collections::HashMap;
78
use std::env;
89
use std::fs::File;
910
use std::io::{self, stdout, Read, Write};
@@ -132,6 +133,12 @@ fn make_opts() -> Options {
132133
"Prints the names of mismatched files that were formatted. Prints the names of \
133134
files that would be formated when used with `--check` mode. ",
134135
);
136+
opts.optmulti(
137+
"",
138+
"config",
139+
"Set options from command line. These settings take priority over .rustfmt.toml",
140+
"[key1=val1,key2=val2...]",
141+
);
135142

136143
if is_nightly {
137144
opts.optflag(
@@ -478,6 +485,7 @@ struct GetOptsOptions {
478485
quiet: bool,
479486
verbose: bool,
480487
config_path: Option<PathBuf>,
488+
inline_config: HashMap<String, String>,
481489
emit_mode: EmitMode,
482490
backup: bool,
483491
check: bool,
@@ -537,6 +545,29 @@ impl GetOptsOptions {
537545

538546
options.config_path = matches.opt_str("config-path").map(PathBuf::from);
539547

548+
options.inline_config = matches
549+
.opt_strs("config")
550+
.iter()
551+
.flat_map(|config| config.split(","))
552+
.map(
553+
|key_val| match key_val.char_indices().find(|(_, ch)| *ch == '=') {
554+
Some((middle, _)) => {
555+
let (key, val) = (&key_val[..middle], &key_val[middle + 1..]);
556+
if !Config::is_valid_key_val(key, val) {
557+
Err(format_err!("invalid key=val pair: `{}`", key_val))
558+
} else {
559+
Ok((key.to_string(), val.to_string()))
560+
}
561+
}
562+
563+
None => Err(format_err!(
564+
"--config expects comma-separated list of key=val pairs, found `{}`",
565+
key_val
566+
)),
567+
},
568+
)
569+
.collect::<Result<HashMap<_, _>, _>>()?;
570+
540571
options.check = matches.opt_present("check");
541572
if let Some(ref emit_str) = matches.opt_str("emit") {
542573
if options.check {
@@ -624,6 +655,10 @@ impl CliOptions for GetOptsOptions {
624655
if self.print_misformatted_file_names {
625656
config.set().print_misformatted_file_names(true);
626657
}
658+
659+
for (key, val) in self.inline_config {
660+
config.override_value(&key, &val);
661+
}
627662
}
628663

629664
fn config_path(&self) -> Option<&Path> {

src/config/config_type.rs

+10
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,16 @@ macro_rules! create_config {
178178
}
179179
}
180180

181+
#[allow(unreachable_pub)]
182+
pub fn is_valid_key_val(key: &str, val: &str) -> bool {
183+
match key {
184+
$(
185+
stringify!($i) => val.parse::<$ty>().is_ok(),
186+
)+
187+
_ => false,
188+
}
189+
}
190+
181191
#[allow(unreachable_pub)]
182192
pub fn used_options(&self) -> PartialConfig {
183193
PartialConfig {

tests/rustfmt/main.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,16 @@ fn rustfmt(args: &[&str]) -> (String, String) {
3030
}
3131

3232
macro_rules! assert_that {
33-
($args:expr, $check:ident $check_args:tt) => {
33+
($args:expr, $($check:ident $check_args:tt)&&+) => {
3434
let (stdout, stderr) = rustfmt($args);
35-
if !stdout.$check$check_args && !stderr.$check$check_args {
35+
if $(!stdout.$check$check_args && !stderr.$check$check_args)||* {
3636
panic!(
3737
"Output not expected for rustfmt {:?}\n\
38-
expected: {}{}\n\
38+
expected: {}\n\
3939
actual stdout:\n{}\n\
4040
actual stderr:\n{}",
4141
$args,
42-
stringify!($check),
43-
stringify!($check_args),
42+
stringify!($( $check$check_args )&&*),
4443
stdout,
4544
stderr
4645
);
@@ -76,3 +75,28 @@ fn print_config() {
7675
);
7776
remove_file("minimal-config").unwrap();
7877
}
78+
79+
#[ignore]
80+
#[test]
81+
fn inline_config() {
82+
// single invocation
83+
assert_that!(
84+
&[
85+
"--print-config",
86+
"current",
87+
".",
88+
"--config=color=Never,edition=2018"
89+
],
90+
contains("color = \"Never\"") && contains("edition = \"2018\"")
91+
);
92+
93+
// multiple overriding invocations
94+
assert_that!(
95+
&["--print-config", "current", ".",
96+
"--config", "color=never,edition=2018",
97+
"--config", "color=always,format_strings=true"],
98+
contains("color = \"Always\"") &&
99+
contains("edition = \"2018\"") &&
100+
contains("format_strings = true")
101+
);
102+
}

0 commit comments

Comments
 (0)