-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GH 731 review #341
GH 731 review #341
Changes from all commits
cedb1b3
32dd2cb
690b099
0d7427b
22e607b
b9a6e85
08349e2
8aead2a
6167856
7286ee8
fce6fe1
4dd0932
413ffc5
18d0cc1
efd3fbb
cf6da59
34b8fea
5895879
62e99e3
8369ff9
5b02822
0603f70
2ec7e12
fe491ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,7 @@ macro_rules! values_m { | |
#[derive(Debug)] | ||
pub struct MultiConfig<'a> { | ||
arg_matches: ArgMatches<'a>, | ||
computed_value_names: HashSet<String>, | ||
} | ||
|
||
impl<'a> MultiConfig<'a> { | ||
|
@@ -63,9 +64,20 @@ impl<'a> MultiConfig<'a> { | |
) -> Result<MultiConfig<'a>, ConfiguratorError> { | ||
let initial: Box<dyn VirtualCommandLine> = | ||
Box::new(CommandLineVcl::new(vec![String::new()])); | ||
let merged: Box<dyn VirtualCommandLine> = vcls | ||
let mut computed_value_names = HashSet::new(); | ||
vcls.iter().for_each(|vcl| { | ||
vcl.vcl_args().iter().for_each(|vcl_arg| { | ||
match vcl.is_computed() { | ||
true => computed_value_names.insert(vcl_arg.name().to_string()), | ||
false => computed_value_names.remove(&vcl_arg.name().to_string()), | ||
}; | ||
}) | ||
}); | ||
// TODO pull this out to function to use in determine_user_specific_data | ||
let merged = vcls | ||
.into_iter() | ||
.fold(initial, |so_far, vcl| merge(so_far, vcl)); | ||
|
||
let arg_matches = match schema | ||
.clone() | ||
.get_matches_from_safe(merged.args().into_iter()) | ||
|
@@ -78,7 +90,10 @@ impl<'a> MultiConfig<'a> { | |
_ => return Err(Self::make_configurator_error(e)), | ||
}, | ||
}; | ||
Ok(MultiConfig { arg_matches }) | ||
Ok(MultiConfig { | ||
arg_matches, | ||
computed_value_names, | ||
}) | ||
} | ||
|
||
fn check_for_invalid_value_err( | ||
|
@@ -139,6 +154,10 @@ impl<'a> MultiConfig<'a> { | |
ConfiguratorError::required("<unknown>", &format!("Unfamiliar message: {}", e.message)) | ||
} | ||
|
||
pub fn is_user_specified(&self, value_name: &str) -> bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the old code, there's a macro that looks like this:
That seems incompatible with this code. Do the two pass the same tests? Further observation: The macro above does not seem to be used anywhere in the codebase anymore. (Check to make sure I'm right about this.) If it's not, there's no need to keep it around, and once it's deleted its meaning can be redefined as desired. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
!self.computed_value_names.contains(value_name) | ||
} | ||
|
||
pub fn occurrences_of(&self, parameter: &str) -> u64 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point, I think we can remove There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm afraid it is not possible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Next thing is |
||
self.arg_matches.occurrences_of(parameter) | ||
} | ||
|
@@ -150,6 +169,7 @@ impl<'a> MultiConfig<'a> { | |
|
||
pub trait VclArg: Debug { | ||
fn name(&self) -> &str; | ||
fn value_opt(&self) -> Option<&str>; | ||
fn to_args(&self) -> Vec<String>; | ||
fn dup(&self) -> Box<dyn VclArg>; | ||
} | ||
|
@@ -175,7 +195,9 @@ impl VclArg for NameValueVclArg { | |
fn name(&self) -> &str { | ||
&self.name | ||
} | ||
|
||
fn value_opt(&self) -> Option<&str> { | ||
Some(self.value.as_str()) | ||
} | ||
fn to_args(&self) -> Vec<String> { | ||
vec![self.name.clone(), self.value.clone()] | ||
} | ||
|
@@ -203,7 +225,9 @@ impl VclArg for NameOnlyVclArg { | |
fn name(&self) -> &str { | ||
&self.name | ||
} | ||
|
||
fn value_opt(&self) -> Option<&str> { | ||
None | ||
} | ||
fn to_args(&self) -> Vec<String> { | ||
vec![self.name.clone()] | ||
} | ||
|
@@ -224,6 +248,9 @@ impl NameOnlyVclArg { | |
pub trait VirtualCommandLine { | ||
fn vcl_args(&self) -> Vec<&dyn VclArg>; | ||
fn args(&self) -> Vec<String>; | ||
fn is_computed(&self) -> bool { | ||
false | ||
} | ||
} | ||
|
||
impl Debug for dyn VirtualCommandLine { | ||
|
@@ -263,6 +290,24 @@ pub fn merge( | |
}) | ||
} | ||
|
||
pub struct ComputedVcl { | ||
vcl_args: Vec<Box<dyn VclArg>>, | ||
} | ||
|
||
impl VirtualCommandLine for ComputedVcl { | ||
fn vcl_args(&self) -> Vec<&dyn VclArg> { | ||
vcl_args_to_vcl_args(&self.vcl_args) | ||
czarte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
fn args(&self) -> Vec<String> { | ||
vcl_args_to_args(&self.vcl_args) | ||
} | ||
|
||
fn is_computed(&self) -> bool { | ||
true | ||
} | ||
} | ||
|
||
pub struct CommandLineVcl { | ||
vcl_args: Vec<Box<dyn VclArg>>, | ||
} | ||
|
@@ -283,6 +328,33 @@ impl From<Vec<Box<dyn VclArg>>> for CommandLineVcl { | |
} | ||
} | ||
|
||
impl ComputedVcl { | ||
czarte marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pub fn new(mut args: Vec<String>) -> ComputedVcl { | ||
args.remove(0); // remove command | ||
let mut vcl_args = vec![]; | ||
while let Some(vcl_arg) = Self::next_vcl_arg(&mut args) { | ||
vcl_args.push(vcl_arg); | ||
} | ||
ComputedVcl { vcl_args } | ||
} | ||
|
||
fn next_vcl_arg(args: &mut Vec<String>) -> Option<Box<dyn VclArg>> { | ||
if args.is_empty() { | ||
return None; | ||
} | ||
let name = args.remove(0); | ||
if !name.starts_with("--") { | ||
panic!("Expected option beginning with '--', not {}", name) | ||
} | ||
if args.is_empty() || args[0].starts_with("--") { | ||
Some(Box::new(NameOnlyVclArg::new(&name))) | ||
} else { | ||
let value = args.remove(0); | ||
Some(Box::new(NameValueVclArg::new(&name, &value))) | ||
} | ||
} | ||
} | ||
|
||
impl CommandLineVcl { | ||
pub fn new(mut args: Vec<String>) -> CommandLineVcl { | ||
args.remove(0); // remove command | ||
|
@@ -334,7 +406,7 @@ impl EnvironmentVcl { | |
.collect(); | ||
let mut vcl_args: Vec<Box<dyn VclArg>> = vec![]; | ||
for (upper_name, value) in std::env::vars() { | ||
if (upper_name.len() < 5) || (&upper_name[0..5] != "MASQ_") { | ||
if (upper_name.len() < 5) || (&upper_name[0..5] != "MASQ_") || (value == *"") { | ||
continue; | ||
} | ||
let lower_name = str::replace(&upper_name[5..].to_lowercase(), "_", "-"); | ||
|
@@ -347,10 +419,19 @@ impl EnvironmentVcl { | |
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct ConfigFileVcl { | ||
vcl_args: Vec<Box<dyn VclArg>>, | ||
} | ||
|
||
impl Clone for ConfigFileVcl { | ||
fn clone(&self) -> Self { | ||
ConfigFileVcl { | ||
vcl_args: self.vcl_args.iter().map(|arg| arg.dup()).collect(), | ||
} | ||
} | ||
} | ||
|
||
impl VirtualCommandLine for ConfigFileVcl { | ||
fn vcl_args(&self) -> Vec<&dyn VclArg> { | ||
vcl_args_to_vcl_args(&self.vcl_args) | ||
|
@@ -491,8 +572,14 @@ fn append<T>(ts: Vec<T>, t: T) -> Vec<T> { | |
|
||
#[cfg(not(feature = "no_test_share"))] | ||
impl<'a> MultiConfig<'a> { | ||
pub fn new_test_only(arg_matches: ArgMatches<'a>) -> Self { | ||
Self { arg_matches } | ||
pub fn new_test_only( | ||
arg_matches: ArgMatches<'a>, | ||
computed_value_names: HashSet<String>, | ||
) -> Self { | ||
Self { | ||
arg_matches, | ||
computed_value_names, | ||
} | ||
} | ||
} | ||
|
||
|
@@ -504,6 +591,7 @@ pub mod tests { | |
use clap::Arg; | ||
use std::fs::File; | ||
use std::io::Write; | ||
use std::ops::Deref; | ||
|
||
#[test] | ||
fn config_file_vcl_error_displays_open_error() { | ||
|
@@ -949,6 +1037,40 @@ pub mod tests { | |
assert_eq!(subject.args(), command_line); | ||
} | ||
|
||
#[test] | ||
fn command_line_vcl_return_value_from_vcl_args_by_name() { | ||
let command_line: Vec<String> = vec![ | ||
"", | ||
"--first-value", | ||
"/nonexistent/directory", | ||
"--takes_no_value", | ||
"--other_takes_no_value", | ||
] | ||
.into_iter() | ||
.map(|s| s.to_string()) | ||
.collect(); | ||
|
||
let subject = CommandLineVcl::new(command_line.clone()); | ||
let existing_value = match subject | ||
.vcl_args | ||
.iter() | ||
.find(|vcl_arg_box| vcl_arg_box.deref().name() == "--first-value") | ||
{ | ||
Some(vcl_arg_box) => vcl_arg_box.deref().value_opt(), | ||
None => None, | ||
}; | ||
let non_existing_value = match subject | ||
.vcl_args | ||
.iter() | ||
.find(|vcl_arg_box| vcl_arg_box.deref().name() == "--takes_no_value") | ||
{ | ||
Some(vcl_arg_box) => vcl_arg_box.deref().value_opt(), | ||
None => None, | ||
}; | ||
assert_eq!(existing_value.unwrap(), "/nonexistent/directory"); | ||
assert_eq!(non_existing_value, None); | ||
} | ||
|
||
#[test] | ||
#[should_panic(expected = "Expected option beginning with '--', not value")] | ||
fn command_line_vcl_panics_when_given_value_without_name() { | ||
|
@@ -963,12 +1085,19 @@ pub mod tests { | |
#[test] | ||
fn environment_vcl_works() { | ||
let _guard = EnvironmentGuard::new(); | ||
let schema = App::new("test").arg( | ||
Arg::with_name("numeric-arg") | ||
.long("numeric-arg") | ||
.takes_value(true), | ||
); | ||
let schema = App::new("test") | ||
.arg( | ||
Arg::with_name("numeric-arg") | ||
.long("numeric-arg") | ||
.takes_value(true), | ||
) | ||
.arg( | ||
Arg::with_name("empty-arg") | ||
.long("empty-arg") | ||
.takes_value(true), | ||
); | ||
std::env::set_var("MASQ_NUMERIC_ARG", "47"); | ||
std::env::set_var("MASQ_EMPTY_ARG", ""); | ||
|
||
let subject = EnvironmentVcl::new(&schema); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you move this down so that it's next to where it's used? It'd be easier to read.