Show More
@@ -65,9 +65,9 b' impl Config {' | |||||
65 | /// Load system and user configuration from various files. |
|
65 | /// Load system and user configuration from various files. | |
66 | /// |
|
66 | /// | |
67 | /// This is also affected by some environment variables. |
|
67 | /// This is also affected by some environment variables. | |
68 | /// |
|
68 | pub fn load( | |
69 | /// TODO: add a parameter for `--config` CLI arguments |
|
69 | cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>, | |
70 |
|
|
70 | ) -> Result<Self, ConfigError> { | |
71 | let mut config = Self { layers: Vec::new() }; |
|
71 | let mut config = Self { layers: Vec::new() }; | |
72 | let opt_rc_path = env::var_os("HGRCPATH"); |
|
72 | let opt_rc_path = env::var_os("HGRCPATH"); | |
73 | // HGRCPATH replaces system config |
|
73 | // HGRCPATH replaces system config | |
@@ -92,6 +92,9 b' impl Config {' | |||||
92 | } |
|
92 | } | |
93 | } |
|
93 | } | |
94 | } |
|
94 | } | |
|
95 | if let Some(layer) = ConfigLayer::parse_cli_args(cli_config_args)? { | |||
|
96 | config.layers.push(layer) | |||
|
97 | } | |||
95 | Ok(config) |
|
98 | Ok(config) | |
96 | } |
|
99 | } | |
97 |
|
100 |
@@ -51,6 +51,49 b' impl ConfigLayer {' | |||||
51 | } |
|
51 | } | |
52 | } |
|
52 | } | |
53 |
|
53 | |||
|
54 | /// Parse `--config` CLI arguments and return a layer if thereβs any | |||
|
55 | pub(crate) fn parse_cli_args( | |||
|
56 | cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>, | |||
|
57 | ) -> Result<Option<Self>, ConfigError> { | |||
|
58 | fn parse_one(arg: &[u8]) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> { | |||
|
59 | use crate::utils::SliceExt; | |||
|
60 | ||||
|
61 | let (section_and_item, value) = split_2(arg, b'=')?; | |||
|
62 | let (section, item) = split_2(section_and_item.trim(), b'.')?; | |||
|
63 | Some(( | |||
|
64 | section.to_owned(), | |||
|
65 | item.to_owned(), | |||
|
66 | value.trim().to_owned(), | |||
|
67 | )) | |||
|
68 | } | |||
|
69 | ||||
|
70 | fn split_2(bytes: &[u8], separator: u8) -> Option<(&[u8], &[u8])> { | |||
|
71 | let mut iter = bytes.splitn(2, |&byte| byte == separator); | |||
|
72 | let a = iter.next()?; | |||
|
73 | let b = iter.next()?; | |||
|
74 | Some((a, b)) | |||
|
75 | } | |||
|
76 | ||||
|
77 | let mut layer = Self::new(ConfigOrigin::CommandLine); | |||
|
78 | for arg in cli_config_args { | |||
|
79 | let arg = arg.as_ref(); | |||
|
80 | if let Some((section, item, value)) = parse_one(arg) { | |||
|
81 | layer.add(section, item, value, None); | |||
|
82 | } else { | |||
|
83 | Err(HgError::abort(format!( | |||
|
84 | "malformed --config option: \"{}\" \ | |||
|
85 | (use --config section.name=value)", | |||
|
86 | String::from_utf8_lossy(arg), | |||
|
87 | )))? | |||
|
88 | } | |||
|
89 | } | |||
|
90 | if layer.sections.is_empty() { | |||
|
91 | Ok(None) | |||
|
92 | } else { | |||
|
93 | Ok(Some(layer)) | |||
|
94 | } | |||
|
95 | } | |||
|
96 | ||||
54 | /// Returns whether this layer comes from `--config` CLI arguments |
|
97 | /// Returns whether this layer comes from `--config` CLI arguments | |
55 | pub(crate) fn is_from_command_line(&self) -> bool { |
|
98 | pub(crate) fn is_from_command_line(&self) -> bool { | |
56 | if let ConfigOrigin::CommandLine = self.origin { |
|
99 | if let ConfigOrigin::CommandLine = self.origin { |
@@ -20,6 +20,17 b" fn add_global_args<'a, 'b>(app: App<'a, " | |||||
20 | .value_name("REPO") |
|
20 | .value_name("REPO") | |
21 | .takes_value(true), |
|
21 | .takes_value(true), | |
22 | ) |
|
22 | ) | |
|
23 | .arg( | |||
|
24 | Arg::with_name("config") | |||
|
25 | .help("set/override config option (use 'section.name=value')") | |||
|
26 | .long("--config") | |||
|
27 | .value_name("CONFIG") | |||
|
28 | .takes_value(true) | |||
|
29 | // Ok: `--config section.key1=val --config section.key2=val2` | |||
|
30 | .multiple(true) | |||
|
31 | // Not ok: `--config section.key1=val section.key2=val2` | |||
|
32 | .number_of_values(1), | |||
|
33 | ) | |||
23 | } |
|
34 | } | |
24 |
|
35 | |||
25 | fn main() { |
|
36 | fn main() { | |
@@ -47,12 +58,22 b' fn main() {' | |||||
47 |
|
58 | |||
48 | // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s. |
|
59 | // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s. | |
49 | // `hg log -R ./foo` |
|
60 | // `hg log -R ./foo` | |
50 | let global_arg = |
|
61 | let value_of_global_arg = | |
51 | |name| args.value_of_os(name).or_else(|| matches.value_of_os(name)); |
|
62 | |name| args.value_of_os(name).or_else(|| matches.value_of_os(name)); | |
|
63 | // For arguments where multiple occurences are allowed, return a | |||
|
64 | // possibly-iterator of all values. | |||
|
65 | let values_of_global_arg = |name: &str| { | |||
|
66 | let a = matches.values_of_os(name).into_iter().flatten(); | |||
|
67 | let b = args.values_of_os(name).into_iter().flatten(); | |||
|
68 | a.chain(b) | |||
|
69 | }; | |||
52 |
|
70 | |||
53 | let repo_path = global_arg("repository").map(Path::new); |
|
71 | let repo_path = value_of_global_arg("repository").map(Path::new); | |
54 | let result = (|| -> Result<(), CommandError> { |
|
72 | let result = (|| -> Result<(), CommandError> { | |
55 | let config = hg::config::Config::load()?; |
|
73 | let config_args = values_of_global_arg("config") | |
|
74 | // `get_bytes_from_path` works for OsStr the same as for Path | |||
|
75 | .map(hg::utils::files::get_bytes_from_path); | |||
|
76 | let config = hg::config::Config::load(config_args)?; | |||
56 | run(&ui, &config, repo_path, args) |
|
77 | run(&ui, &config, repo_path, args) | |
57 | })(); |
|
78 | })(); | |
58 |
|
79 |
General Comments 0
You need to be logged in to leave comments.
Login now