Skip to content

Commit

Permalink
Add --config command line option (rust-lang#3767)
Browse files Browse the repository at this point in the history
  • Loading branch information
CreepySkeleton authored and topecongiro committed Sep 5, 2019
1 parent 15a28f7 commit e81ec20
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 6 deletions.
7 changes: 6 additions & 1 deletion config_proc_macro/src/item_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down
35 changes: 35 additions & 0 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use io::Error as IoError;

use rustfmt_nightly as rustfmt;

use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{self, stdout, Read, Write};
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -537,6 +545,29 @@ impl GetOptsOptions {

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 {
Expand Down Expand Up @@ -624,6 +655,10 @@ impl CliOptions for GetOptsOptions {
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> {
Expand Down
10 changes: 10 additions & 0 deletions src/config/config_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ macro_rules! create_config {
}
}

#[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 {
Expand Down
34 changes: 29 additions & 5 deletions tests/rustfmt/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
Expand Down Expand Up @@ -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")
);
}

0 comments on commit e81ec20

Please sign in to comment.