From 1d5d7a269fbff61a70b36c85e004351b6d761403 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 18 Feb 2020 09:30:27 -0800 Subject: [PATCH] Support `--config path_to_config.toml` cli syntax. --- src/cargo/util/config/mod.rs | 43 +++++++++++++++++++++---------- src/doc/src/reference/unstable.md | 5 ++-- tests/testsuite/config_include.rs | 28 +++++++++++++++++++- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/cargo/util/config/mod.rs b/src/cargo/util/config/mod.rs index 9b5eeef7194..e780410cff6 100644 --- a/src/cargo/util/config/mod.rs +++ b/src/cargo/util/config/mod.rs @@ -864,20 +864,35 @@ impl Config { }; let mut loaded_args = CV::Table(HashMap::new(), Definition::Cli); for arg in cli_args { - // TODO: This should probably use a more narrow parser, reject - // comments, blank lines, [headers], etc. - let toml_v: toml::Value = toml::de::from_str(arg) - .chain_err(|| format!("failed to parse --config argument `{}`", arg))?; - let toml_table = toml_v.as_table().unwrap(); - if toml_table.len() != 1 { - bail!( - "--config argument `{}` expected exactly one key=value pair, got {} keys", - arg, - toml_table.len() - ); - } - let tmp_table = CV::from_toml(Definition::Cli, toml_v) - .chain_err(|| format!("failed to convert --config argument `{}`", arg))?; + let arg_as_path = self.cwd.join(arg); + let tmp_table = if !arg.is_empty() && arg_as_path.exists() { + // --config path_to_file + let str_path = arg_as_path + .to_str() + .ok_or_else(|| { + anyhow::format_err!("config path {:?} is not utf-8", arg_as_path) + })? + .to_string(); + let mut map = HashMap::new(); + let value = CV::String(str_path, Definition::Cli); + map.insert("include".to_string(), value); + CV::Table(map, Definition::Cli) + } else { + // TODO: This should probably use a more narrow parser, reject + // comments, blank lines, [headers], etc. + let toml_v: toml::Value = toml::de::from_str(arg) + .chain_err(|| format!("failed to parse --config argument `{}`", arg))?; + let toml_table = toml_v.as_table().unwrap(); + if toml_table.len() != 1 { + bail!( + "--config argument `{}` expected exactly one key=value pair, got {} keys", + arg, + toml_table.len() + ); + } + CV::from_toml(Definition::Cli, toml_v) + .chain_err(|| format!("failed to convert --config argument `{}`", arg))? + }; let mut seen = HashSet::new(); let tmp_table = self .load_includes(tmp_table, &mut seen) diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 4654e0c02e7..bb0f8d8b889 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -465,10 +465,11 @@ The config values are first loaded from the include path, and then the config file's own values are merged on top of it. This can be paired with [config-cli](#config-cli) to specify a file to load -from the command-line: +from the command-line. Pass a path to a config file as the argument to +`--config`: ```console -cargo +nightly -Zunstable-options -Zconfig-include --config 'include="somefile.toml"' build +cargo +nightly -Zunstable-options -Zconfig-include --config somefile.toml build ``` CLI paths are relative to the current working directory. diff --git a/tests/testsuite/config_include.rs b/tests/testsuite/config_include.rs index 259cb41a1cc..f1c6b63f4d8 100644 --- a/tests/testsuite/config_include.rs +++ b/tests/testsuite/config_include.rs @@ -3,7 +3,8 @@ use super::config::{ assert_error, assert_match, read_output, write_config, write_config_at, ConfigBuilder, }; -use cargo_test_support::NO_SUCH_FILE_ERR_MSG; +use cargo_test_support::{paths, NO_SUCH_FILE_ERR_MSG}; +use std::fs; #[cargo_test] fn gated() { @@ -208,3 +209,28 @@ Caused by: expected array, but found string", ); } + +#[cargo_test] +fn cli_path() { + // --config path_to_file + fs::write(paths::root().join("myconfig.toml"), "key = 123").unwrap(); + let config = ConfigBuilder::new() + .cwd(paths::root()) + .unstable_flag("config-include") + .config_arg("myconfig.toml") + .build(); + assert_eq!(config.get::("key").unwrap(), 123); + + let config = ConfigBuilder::new() + .unstable_flag("config-include") + .config_arg("missing.toml") + .build_err(); + assert_error( + config.unwrap_err(), + "\ +failed to parse --config argument `missing.toml` + +Caused by: + expected an equals, found eof at line 1 column 13", + ); +}