119625d8cSopenharmony_ci// Internal 219625d8cSopenharmony_ciuse crate::builder::StyledStr; 319625d8cSopenharmony_ciuse crate::builder::{Arg, ArgGroup, ArgPredicate, Command, PossibleValue}; 419625d8cSopenharmony_ciuse crate::error::{Error, Result as ClapResult}; 519625d8cSopenharmony_ciuse crate::output::Usage; 619625d8cSopenharmony_ciuse crate::parser::{ArgMatcher, ParseState}; 719625d8cSopenharmony_ciuse crate::util::ChildGraph; 819625d8cSopenharmony_ciuse crate::util::FlatMap; 919625d8cSopenharmony_ciuse crate::util::FlatSet; 1019625d8cSopenharmony_ciuse crate::util::Id; 1119625d8cSopenharmony_ciuse crate::INTERNAL_ERROR_MSG; 1219625d8cSopenharmony_ci 1319625d8cSopenharmony_cipub(crate) struct Validator<'cmd> { 1419625d8cSopenharmony_ci cmd: &'cmd Command, 1519625d8cSopenharmony_ci required: ChildGraph<Id>, 1619625d8cSopenharmony_ci} 1719625d8cSopenharmony_ci 1819625d8cSopenharmony_ciimpl<'cmd> Validator<'cmd> { 1919625d8cSopenharmony_ci pub(crate) fn new(cmd: &'cmd Command) -> Self { 2019625d8cSopenharmony_ci let required = cmd.required_graph(); 2119625d8cSopenharmony_ci Validator { cmd, required } 2219625d8cSopenharmony_ci } 2319625d8cSopenharmony_ci 2419625d8cSopenharmony_ci pub(crate) fn validate( 2519625d8cSopenharmony_ci &mut self, 2619625d8cSopenharmony_ci parse_state: ParseState, 2719625d8cSopenharmony_ci matcher: &mut ArgMatcher, 2819625d8cSopenharmony_ci ) -> ClapResult<()> { 2919625d8cSopenharmony_ci debug!("Validator::validate"); 3019625d8cSopenharmony_ci let conflicts = Conflicts::with_args(self.cmd, matcher); 3119625d8cSopenharmony_ci let has_subcmd = matcher.subcommand_name().is_some(); 3219625d8cSopenharmony_ci 3319625d8cSopenharmony_ci if let ParseState::Opt(a) = parse_state { 3419625d8cSopenharmony_ci debug!("Validator::validate: needs_val_of={:?}", a); 3519625d8cSopenharmony_ci 3619625d8cSopenharmony_ci let o = &self.cmd[&a]; 3719625d8cSopenharmony_ci let should_err = if let Some(v) = matcher.args.get(o.get_id()) { 3819625d8cSopenharmony_ci v.all_val_groups_empty() && o.get_min_vals() != 0 3919625d8cSopenharmony_ci } else { 4019625d8cSopenharmony_ci true 4119625d8cSopenharmony_ci }; 4219625d8cSopenharmony_ci if should_err { 4319625d8cSopenharmony_ci return Err(Error::empty_value( 4419625d8cSopenharmony_ci self.cmd, 4519625d8cSopenharmony_ci &get_possible_values_cli(o) 4619625d8cSopenharmony_ci .iter() 4719625d8cSopenharmony_ci .filter(|pv| !pv.is_hide_set()) 4819625d8cSopenharmony_ci .map(|n| n.get_name().to_owned()) 4919625d8cSopenharmony_ci .collect::<Vec<_>>(), 5019625d8cSopenharmony_ci o.to_string(), 5119625d8cSopenharmony_ci )); 5219625d8cSopenharmony_ci } 5319625d8cSopenharmony_ci } 5419625d8cSopenharmony_ci 5519625d8cSopenharmony_ci if !has_subcmd && self.cmd.is_arg_required_else_help_set() { 5619625d8cSopenharmony_ci let num_user_values = matcher 5719625d8cSopenharmony_ci .args() 5819625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 5919625d8cSopenharmony_ci .count(); 6019625d8cSopenharmony_ci if num_user_values == 0 { 6119625d8cSopenharmony_ci let message = self.cmd.write_help_err(false); 6219625d8cSopenharmony_ci return Err(Error::display_help_error(self.cmd, message)); 6319625d8cSopenharmony_ci } 6419625d8cSopenharmony_ci } 6519625d8cSopenharmony_ci if !has_subcmd && self.cmd.is_subcommand_required_set() { 6619625d8cSopenharmony_ci let bn = self 6719625d8cSopenharmony_ci .cmd 6819625d8cSopenharmony_ci .get_bin_name() 6919625d8cSopenharmony_ci .unwrap_or_else(|| self.cmd.get_name()); 7019625d8cSopenharmony_ci return Err(Error::missing_subcommand( 7119625d8cSopenharmony_ci self.cmd, 7219625d8cSopenharmony_ci bn.to_string(), 7319625d8cSopenharmony_ci self.cmd 7419625d8cSopenharmony_ci .all_subcommand_names() 7519625d8cSopenharmony_ci .map(|s| s.to_owned()) 7619625d8cSopenharmony_ci .collect::<Vec<_>>(), 7719625d8cSopenharmony_ci Usage::new(self.cmd) 7819625d8cSopenharmony_ci .required(&self.required) 7919625d8cSopenharmony_ci .create_usage_with_title(&[]), 8019625d8cSopenharmony_ci )); 8119625d8cSopenharmony_ci } 8219625d8cSopenharmony_ci 8319625d8cSopenharmony_ci ok!(self.validate_conflicts(matcher, &conflicts)); 8419625d8cSopenharmony_ci if !(self.cmd.is_subcommand_negates_reqs_set() && has_subcmd) { 8519625d8cSopenharmony_ci ok!(self.validate_required(matcher, &conflicts)); 8619625d8cSopenharmony_ci } 8719625d8cSopenharmony_ci 8819625d8cSopenharmony_ci Ok(()) 8919625d8cSopenharmony_ci } 9019625d8cSopenharmony_ci 9119625d8cSopenharmony_ci fn validate_conflicts( 9219625d8cSopenharmony_ci &mut self, 9319625d8cSopenharmony_ci matcher: &ArgMatcher, 9419625d8cSopenharmony_ci conflicts: &Conflicts, 9519625d8cSopenharmony_ci ) -> ClapResult<()> { 9619625d8cSopenharmony_ci debug!("Validator::validate_conflicts"); 9719625d8cSopenharmony_ci 9819625d8cSopenharmony_ci ok!(self.validate_exclusive(matcher)); 9919625d8cSopenharmony_ci 10019625d8cSopenharmony_ci for (arg_id, _) in matcher 10119625d8cSopenharmony_ci .args() 10219625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 10319625d8cSopenharmony_ci .filter(|(arg_id, _)| self.cmd.find(arg_id).is_some()) 10419625d8cSopenharmony_ci { 10519625d8cSopenharmony_ci debug!("Validator::validate_conflicts::iter: id={:?}", arg_id); 10619625d8cSopenharmony_ci let conflicts = conflicts.gather_conflicts(self.cmd, arg_id); 10719625d8cSopenharmony_ci ok!(self.build_conflict_err(arg_id, &conflicts, matcher)); 10819625d8cSopenharmony_ci } 10919625d8cSopenharmony_ci 11019625d8cSopenharmony_ci Ok(()) 11119625d8cSopenharmony_ci } 11219625d8cSopenharmony_ci 11319625d8cSopenharmony_ci fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> { 11419625d8cSopenharmony_ci debug!("Validator::validate_exclusive"); 11519625d8cSopenharmony_ci let args_count = matcher 11619625d8cSopenharmony_ci .args() 11719625d8cSopenharmony_ci .filter(|(arg_id, matched)| { 11819625d8cSopenharmony_ci matched.check_explicit(&crate::builder::ArgPredicate::IsPresent) 11919625d8cSopenharmony_ci // Avoid including our own groups by checking none of them. If a group is present, the 12019625d8cSopenharmony_ci // args for the group will be. 12119625d8cSopenharmony_ci && self.cmd.find(arg_id).is_some() 12219625d8cSopenharmony_ci }) 12319625d8cSopenharmony_ci .count(); 12419625d8cSopenharmony_ci if args_count <= 1 { 12519625d8cSopenharmony_ci // Nothing present to conflict with 12619625d8cSopenharmony_ci return Ok(()); 12719625d8cSopenharmony_ci } 12819625d8cSopenharmony_ci 12919625d8cSopenharmony_ci matcher 13019625d8cSopenharmony_ci .args() 13119625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&crate::builder::ArgPredicate::IsPresent)) 13219625d8cSopenharmony_ci .filter_map(|(id, _)| { 13319625d8cSopenharmony_ci debug!("Validator::validate_exclusive:iter:{:?}", id); 13419625d8cSopenharmony_ci self.cmd 13519625d8cSopenharmony_ci .find(id) 13619625d8cSopenharmony_ci // Find `arg`s which are exclusive but also appear with other args. 13719625d8cSopenharmony_ci .filter(|&arg| arg.is_exclusive_set() && args_count > 1) 13819625d8cSopenharmony_ci }) 13919625d8cSopenharmony_ci // Throw an error for the first conflict found. 14019625d8cSopenharmony_ci .try_for_each(|arg| { 14119625d8cSopenharmony_ci Err(Error::argument_conflict( 14219625d8cSopenharmony_ci self.cmd, 14319625d8cSopenharmony_ci arg.to_string(), 14419625d8cSopenharmony_ci Vec::new(), 14519625d8cSopenharmony_ci Usage::new(self.cmd) 14619625d8cSopenharmony_ci .required(&self.required) 14719625d8cSopenharmony_ci .create_usage_with_title(&[]), 14819625d8cSopenharmony_ci )) 14919625d8cSopenharmony_ci }) 15019625d8cSopenharmony_ci } 15119625d8cSopenharmony_ci 15219625d8cSopenharmony_ci fn build_conflict_err( 15319625d8cSopenharmony_ci &self, 15419625d8cSopenharmony_ci name: &Id, 15519625d8cSopenharmony_ci conflict_ids: &[Id], 15619625d8cSopenharmony_ci matcher: &ArgMatcher, 15719625d8cSopenharmony_ci ) -> ClapResult<()> { 15819625d8cSopenharmony_ci if conflict_ids.is_empty() { 15919625d8cSopenharmony_ci return Ok(()); 16019625d8cSopenharmony_ci } 16119625d8cSopenharmony_ci 16219625d8cSopenharmony_ci debug!("Validator::build_conflict_err: name={:?}", name); 16319625d8cSopenharmony_ci let mut seen = FlatSet::new(); 16419625d8cSopenharmony_ci let conflicts = conflict_ids 16519625d8cSopenharmony_ci .iter() 16619625d8cSopenharmony_ci .flat_map(|c_id| { 16719625d8cSopenharmony_ci if self.cmd.find_group(c_id).is_some() { 16819625d8cSopenharmony_ci self.cmd.unroll_args_in_group(c_id) 16919625d8cSopenharmony_ci } else { 17019625d8cSopenharmony_ci vec![c_id.clone()] 17119625d8cSopenharmony_ci } 17219625d8cSopenharmony_ci }) 17319625d8cSopenharmony_ci .filter_map(|c_id| { 17419625d8cSopenharmony_ci seen.insert(c_id.clone()).then(|| { 17519625d8cSopenharmony_ci let c_arg = self.cmd.find(&c_id).expect(INTERNAL_ERROR_MSG); 17619625d8cSopenharmony_ci c_arg.to_string() 17719625d8cSopenharmony_ci }) 17819625d8cSopenharmony_ci }) 17919625d8cSopenharmony_ci .collect(); 18019625d8cSopenharmony_ci 18119625d8cSopenharmony_ci let former_arg = self.cmd.find(name).expect(INTERNAL_ERROR_MSG); 18219625d8cSopenharmony_ci let usg = self.build_conflict_err_usage(matcher, conflict_ids); 18319625d8cSopenharmony_ci Err(Error::argument_conflict( 18419625d8cSopenharmony_ci self.cmd, 18519625d8cSopenharmony_ci former_arg.to_string(), 18619625d8cSopenharmony_ci conflicts, 18719625d8cSopenharmony_ci usg, 18819625d8cSopenharmony_ci )) 18919625d8cSopenharmony_ci } 19019625d8cSopenharmony_ci 19119625d8cSopenharmony_ci fn build_conflict_err_usage( 19219625d8cSopenharmony_ci &self, 19319625d8cSopenharmony_ci matcher: &ArgMatcher, 19419625d8cSopenharmony_ci conflicting_keys: &[Id], 19519625d8cSopenharmony_ci ) -> Option<StyledStr> { 19619625d8cSopenharmony_ci let used_filtered: Vec<Id> = matcher 19719625d8cSopenharmony_ci .args() 19819625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 19919625d8cSopenharmony_ci .map(|(n, _)| n) 20019625d8cSopenharmony_ci .filter(|n| { 20119625d8cSopenharmony_ci // Filter out the args we don't want to specify. 20219625d8cSopenharmony_ci self.cmd.find(n).map_or(false, |a| !a.is_hide_set()) 20319625d8cSopenharmony_ci }) 20419625d8cSopenharmony_ci .filter(|key| !conflicting_keys.contains(key)) 20519625d8cSopenharmony_ci .cloned() 20619625d8cSopenharmony_ci .collect(); 20719625d8cSopenharmony_ci let required: Vec<Id> = used_filtered 20819625d8cSopenharmony_ci .iter() 20919625d8cSopenharmony_ci .filter_map(|key| self.cmd.find(key)) 21019625d8cSopenharmony_ci .flat_map(|arg| arg.requires.iter().map(|item| &item.1)) 21119625d8cSopenharmony_ci .filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key)) 21219625d8cSopenharmony_ci .chain(used_filtered.iter()) 21319625d8cSopenharmony_ci .cloned() 21419625d8cSopenharmony_ci .collect(); 21519625d8cSopenharmony_ci Usage::new(self.cmd) 21619625d8cSopenharmony_ci .required(&self.required) 21719625d8cSopenharmony_ci .create_usage_with_title(&required) 21819625d8cSopenharmony_ci } 21919625d8cSopenharmony_ci 22019625d8cSopenharmony_ci fn gather_requires(&mut self, matcher: &ArgMatcher) { 22119625d8cSopenharmony_ci debug!("Validator::gather_requires"); 22219625d8cSopenharmony_ci for (name, matched) in matcher 22319625d8cSopenharmony_ci .args() 22419625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 22519625d8cSopenharmony_ci { 22619625d8cSopenharmony_ci debug!("Validator::gather_requires:iter:{:?}", name); 22719625d8cSopenharmony_ci if let Some(arg) = self.cmd.find(name) { 22819625d8cSopenharmony_ci let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> { 22919625d8cSopenharmony_ci let required = matched.check_explicit(val); 23019625d8cSopenharmony_ci required.then(|| req_arg.clone()) 23119625d8cSopenharmony_ci }; 23219625d8cSopenharmony_ci 23319625d8cSopenharmony_ci for req in self.cmd.unroll_arg_requires(is_relevant, arg.get_id()) { 23419625d8cSopenharmony_ci self.required.insert(req); 23519625d8cSopenharmony_ci } 23619625d8cSopenharmony_ci } else if let Some(g) = self.cmd.find_group(name) { 23719625d8cSopenharmony_ci debug!("Validator::gather_requires:iter:{:?}:group", name); 23819625d8cSopenharmony_ci for r in &g.requires { 23919625d8cSopenharmony_ci self.required.insert(r.clone()); 24019625d8cSopenharmony_ci } 24119625d8cSopenharmony_ci } 24219625d8cSopenharmony_ci } 24319625d8cSopenharmony_ci } 24419625d8cSopenharmony_ci 24519625d8cSopenharmony_ci fn validate_required(&mut self, matcher: &ArgMatcher, conflicts: &Conflicts) -> ClapResult<()> { 24619625d8cSopenharmony_ci debug!("Validator::validate_required: required={:?}", self.required); 24719625d8cSopenharmony_ci self.gather_requires(matcher); 24819625d8cSopenharmony_ci 24919625d8cSopenharmony_ci let mut missing_required = Vec::new(); 25019625d8cSopenharmony_ci let mut highest_index = 0; 25119625d8cSopenharmony_ci 25219625d8cSopenharmony_ci let is_exclusive_present = matcher 25319625d8cSopenharmony_ci .args() 25419625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 25519625d8cSopenharmony_ci .any(|(id, _)| { 25619625d8cSopenharmony_ci self.cmd 25719625d8cSopenharmony_ci .find(id) 25819625d8cSopenharmony_ci .map(|arg| arg.is_exclusive_set()) 25919625d8cSopenharmony_ci .unwrap_or_default() 26019625d8cSopenharmony_ci }); 26119625d8cSopenharmony_ci debug!( 26219625d8cSopenharmony_ci "Validator::validate_required: is_exclusive_present={}", 26319625d8cSopenharmony_ci is_exclusive_present 26419625d8cSopenharmony_ci ); 26519625d8cSopenharmony_ci 26619625d8cSopenharmony_ci for arg_or_group in self 26719625d8cSopenharmony_ci .required 26819625d8cSopenharmony_ci .iter() 26919625d8cSopenharmony_ci .filter(|r| !matcher.check_explicit(r, &ArgPredicate::IsPresent)) 27019625d8cSopenharmony_ci { 27119625d8cSopenharmony_ci debug!("Validator::validate_required:iter:aog={:?}", arg_or_group); 27219625d8cSopenharmony_ci if let Some(arg) = self.cmd.find(arg_or_group) { 27319625d8cSopenharmony_ci debug!("Validator::validate_required:iter: This is an arg"); 27419625d8cSopenharmony_ci if !is_exclusive_present && !self.is_missing_required_ok(arg, conflicts) { 27519625d8cSopenharmony_ci debug!( 27619625d8cSopenharmony_ci "Validator::validate_required:iter: Missing {:?}", 27719625d8cSopenharmony_ci arg.get_id() 27819625d8cSopenharmony_ci ); 27919625d8cSopenharmony_ci missing_required.push(arg.get_id().clone()); 28019625d8cSopenharmony_ci if !arg.is_last_set() { 28119625d8cSopenharmony_ci highest_index = highest_index.max(arg.get_index().unwrap_or(0)); 28219625d8cSopenharmony_ci } 28319625d8cSopenharmony_ci } 28419625d8cSopenharmony_ci } else if let Some(group) = self.cmd.find_group(arg_or_group) { 28519625d8cSopenharmony_ci debug!("Validator::validate_required:iter: This is a group"); 28619625d8cSopenharmony_ci if !self 28719625d8cSopenharmony_ci .cmd 28819625d8cSopenharmony_ci .unroll_args_in_group(&group.id) 28919625d8cSopenharmony_ci .iter() 29019625d8cSopenharmony_ci .any(|a| matcher.check_explicit(a, &ArgPredicate::IsPresent)) 29119625d8cSopenharmony_ci { 29219625d8cSopenharmony_ci debug!( 29319625d8cSopenharmony_ci "Validator::validate_required:iter: Missing {:?}", 29419625d8cSopenharmony_ci group.get_id() 29519625d8cSopenharmony_ci ); 29619625d8cSopenharmony_ci missing_required.push(group.get_id().clone()); 29719625d8cSopenharmony_ci } 29819625d8cSopenharmony_ci } 29919625d8cSopenharmony_ci } 30019625d8cSopenharmony_ci 30119625d8cSopenharmony_ci // Validate the conditionally required args 30219625d8cSopenharmony_ci for a in self 30319625d8cSopenharmony_ci .cmd 30419625d8cSopenharmony_ci .get_arguments() 30519625d8cSopenharmony_ci .filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent)) 30619625d8cSopenharmony_ci { 30719625d8cSopenharmony_ci let mut required = false; 30819625d8cSopenharmony_ci 30919625d8cSopenharmony_ci for (other, val) in &a.r_ifs { 31019625d8cSopenharmony_ci if matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) { 31119625d8cSopenharmony_ci debug!( 31219625d8cSopenharmony_ci "Validator::validate_required:iter: Missing {:?}", 31319625d8cSopenharmony_ci a.get_id() 31419625d8cSopenharmony_ci ); 31519625d8cSopenharmony_ci required = true; 31619625d8cSopenharmony_ci } 31719625d8cSopenharmony_ci } 31819625d8cSopenharmony_ci 31919625d8cSopenharmony_ci let match_all = a.r_ifs_all.iter().all(|(other, val)| { 32019625d8cSopenharmony_ci matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) 32119625d8cSopenharmony_ci }); 32219625d8cSopenharmony_ci if match_all && !a.r_ifs_all.is_empty() { 32319625d8cSopenharmony_ci debug!( 32419625d8cSopenharmony_ci "Validator::validate_required:iter: Missing {:?}", 32519625d8cSopenharmony_ci a.get_id() 32619625d8cSopenharmony_ci ); 32719625d8cSopenharmony_ci required = true; 32819625d8cSopenharmony_ci } 32919625d8cSopenharmony_ci 33019625d8cSopenharmony_ci if (!a.r_unless.is_empty() || !a.r_unless_all.is_empty()) 33119625d8cSopenharmony_ci && self.fails_arg_required_unless(a, matcher) 33219625d8cSopenharmony_ci { 33319625d8cSopenharmony_ci debug!( 33419625d8cSopenharmony_ci "Validator::validate_required:iter: Missing {:?}", 33519625d8cSopenharmony_ci a.get_id() 33619625d8cSopenharmony_ci ); 33719625d8cSopenharmony_ci required = true; 33819625d8cSopenharmony_ci } 33919625d8cSopenharmony_ci 34019625d8cSopenharmony_ci if required { 34119625d8cSopenharmony_ci missing_required.push(a.get_id().clone()); 34219625d8cSopenharmony_ci if !a.is_last_set() { 34319625d8cSopenharmony_ci highest_index = highest_index.max(a.get_index().unwrap_or(0)); 34419625d8cSopenharmony_ci } 34519625d8cSopenharmony_ci } 34619625d8cSopenharmony_ci } 34719625d8cSopenharmony_ci 34819625d8cSopenharmony_ci // For display purposes, include all of the preceding positional arguments 34919625d8cSopenharmony_ci if !self.cmd.is_allow_missing_positional_set() { 35019625d8cSopenharmony_ci for pos in self 35119625d8cSopenharmony_ci .cmd 35219625d8cSopenharmony_ci .get_positionals() 35319625d8cSopenharmony_ci .filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent)) 35419625d8cSopenharmony_ci { 35519625d8cSopenharmony_ci if pos.get_index() < Some(highest_index) { 35619625d8cSopenharmony_ci debug!( 35719625d8cSopenharmony_ci "Validator::validate_required:iter: Missing {:?}", 35819625d8cSopenharmony_ci pos.get_id() 35919625d8cSopenharmony_ci ); 36019625d8cSopenharmony_ci missing_required.push(pos.get_id().clone()); 36119625d8cSopenharmony_ci } 36219625d8cSopenharmony_ci } 36319625d8cSopenharmony_ci } 36419625d8cSopenharmony_ci 36519625d8cSopenharmony_ci if !missing_required.is_empty() { 36619625d8cSopenharmony_ci ok!(self.missing_required_error(matcher, missing_required)); 36719625d8cSopenharmony_ci } 36819625d8cSopenharmony_ci 36919625d8cSopenharmony_ci Ok(()) 37019625d8cSopenharmony_ci } 37119625d8cSopenharmony_ci 37219625d8cSopenharmony_ci fn is_missing_required_ok(&self, a: &Arg, conflicts: &Conflicts) -> bool { 37319625d8cSopenharmony_ci debug!("Validator::is_missing_required_ok: {}", a.get_id()); 37419625d8cSopenharmony_ci if !conflicts.gather_conflicts(self.cmd, a.get_id()).is_empty() { 37519625d8cSopenharmony_ci debug!("Validator::is_missing_required_ok: true (self)"); 37619625d8cSopenharmony_ci return true; 37719625d8cSopenharmony_ci } 37819625d8cSopenharmony_ci for group_id in self.cmd.groups_for_arg(a.get_id()) { 37919625d8cSopenharmony_ci if !conflicts.gather_conflicts(self.cmd, &group_id).is_empty() { 38019625d8cSopenharmony_ci debug!("Validator::is_missing_required_ok: true ({})", group_id); 38119625d8cSopenharmony_ci return true; 38219625d8cSopenharmony_ci } 38319625d8cSopenharmony_ci } 38419625d8cSopenharmony_ci false 38519625d8cSopenharmony_ci } 38619625d8cSopenharmony_ci 38719625d8cSopenharmony_ci // Failing a required unless means, the arg's "unless" wasn't present, and neither were they 38819625d8cSopenharmony_ci fn fails_arg_required_unless(&self, a: &Arg, matcher: &ArgMatcher) -> bool { 38919625d8cSopenharmony_ci debug!("Validator::fails_arg_required_unless: a={:?}", a.get_id()); 39019625d8cSopenharmony_ci let exists = |id| matcher.check_explicit(id, &ArgPredicate::IsPresent); 39119625d8cSopenharmony_ci 39219625d8cSopenharmony_ci (a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists)) 39319625d8cSopenharmony_ci && !a.r_unless.iter().any(exists) 39419625d8cSopenharmony_ci } 39519625d8cSopenharmony_ci 39619625d8cSopenharmony_ci // `req_args`: an arg to include in the error even if not used 39719625d8cSopenharmony_ci fn missing_required_error( 39819625d8cSopenharmony_ci &self, 39919625d8cSopenharmony_ci matcher: &ArgMatcher, 40019625d8cSopenharmony_ci raw_req_args: Vec<Id>, 40119625d8cSopenharmony_ci ) -> ClapResult<()> { 40219625d8cSopenharmony_ci debug!("Validator::missing_required_error; incl={:?}", raw_req_args); 40319625d8cSopenharmony_ci debug!( 40419625d8cSopenharmony_ci "Validator::missing_required_error: reqs={:?}", 40519625d8cSopenharmony_ci self.required 40619625d8cSopenharmony_ci ); 40719625d8cSopenharmony_ci 40819625d8cSopenharmony_ci let usg = Usage::new(self.cmd).required(&self.required); 40919625d8cSopenharmony_ci 41019625d8cSopenharmony_ci let req_args = { 41119625d8cSopenharmony_ci #[cfg(feature = "usage")] 41219625d8cSopenharmony_ci { 41319625d8cSopenharmony_ci usg.get_required_usage_from(&raw_req_args, Some(matcher), true) 41419625d8cSopenharmony_ci .into_iter() 41519625d8cSopenharmony_ci .map(|s| s.to_string()) 41619625d8cSopenharmony_ci .collect::<Vec<_>>() 41719625d8cSopenharmony_ci } 41819625d8cSopenharmony_ci 41919625d8cSopenharmony_ci #[cfg(not(feature = "usage"))] 42019625d8cSopenharmony_ci { 42119625d8cSopenharmony_ci raw_req_args 42219625d8cSopenharmony_ci .iter() 42319625d8cSopenharmony_ci .map(|id| { 42419625d8cSopenharmony_ci if let Some(arg) = self.cmd.find(id) { 42519625d8cSopenharmony_ci arg.to_string() 42619625d8cSopenharmony_ci } else if let Some(_group) = self.cmd.find_group(id) { 42719625d8cSopenharmony_ci self.cmd.format_group(id).to_string() 42819625d8cSopenharmony_ci } else { 42919625d8cSopenharmony_ci debug_assert!(false, "id={:?} is unknown", id); 43019625d8cSopenharmony_ci "".to_owned() 43119625d8cSopenharmony_ci } 43219625d8cSopenharmony_ci }) 43319625d8cSopenharmony_ci .collect::<Vec<_>>() 43419625d8cSopenharmony_ci } 43519625d8cSopenharmony_ci }; 43619625d8cSopenharmony_ci 43719625d8cSopenharmony_ci debug!( 43819625d8cSopenharmony_ci "Validator::missing_required_error: req_args={:#?}", 43919625d8cSopenharmony_ci req_args 44019625d8cSopenharmony_ci ); 44119625d8cSopenharmony_ci 44219625d8cSopenharmony_ci let used: Vec<Id> = matcher 44319625d8cSopenharmony_ci .args() 44419625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 44519625d8cSopenharmony_ci .map(|(n, _)| n) 44619625d8cSopenharmony_ci .filter(|n| { 44719625d8cSopenharmony_ci // Filter out the args we don't want to specify. 44819625d8cSopenharmony_ci self.cmd.find(n).map_or(false, |a| !a.is_hide_set()) 44919625d8cSopenharmony_ci }) 45019625d8cSopenharmony_ci .cloned() 45119625d8cSopenharmony_ci .chain(raw_req_args) 45219625d8cSopenharmony_ci .collect(); 45319625d8cSopenharmony_ci 45419625d8cSopenharmony_ci Err(Error::missing_required_argument( 45519625d8cSopenharmony_ci self.cmd, 45619625d8cSopenharmony_ci req_args, 45719625d8cSopenharmony_ci usg.create_usage_with_title(&used), 45819625d8cSopenharmony_ci )) 45919625d8cSopenharmony_ci } 46019625d8cSopenharmony_ci} 46119625d8cSopenharmony_ci 46219625d8cSopenharmony_ci#[derive(Default, Clone, Debug)] 46319625d8cSopenharmony_cistruct Conflicts { 46419625d8cSopenharmony_ci potential: FlatMap<Id, Vec<Id>>, 46519625d8cSopenharmony_ci} 46619625d8cSopenharmony_ci 46719625d8cSopenharmony_ciimpl Conflicts { 46819625d8cSopenharmony_ci fn with_args(cmd: &Command, matcher: &ArgMatcher) -> Self { 46919625d8cSopenharmony_ci let mut potential = FlatMap::new(); 47019625d8cSopenharmony_ci potential.extend_unchecked( 47119625d8cSopenharmony_ci matcher 47219625d8cSopenharmony_ci .args() 47319625d8cSopenharmony_ci .filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent)) 47419625d8cSopenharmony_ci .map(|(id, _)| { 47519625d8cSopenharmony_ci let conf = gather_direct_conflicts(cmd, id); 47619625d8cSopenharmony_ci (id.clone(), conf) 47719625d8cSopenharmony_ci }), 47819625d8cSopenharmony_ci ); 47919625d8cSopenharmony_ci Self { potential } 48019625d8cSopenharmony_ci } 48119625d8cSopenharmony_ci 48219625d8cSopenharmony_ci fn gather_conflicts(&self, cmd: &Command, arg_id: &Id) -> Vec<Id> { 48319625d8cSopenharmony_ci debug!("Conflicts::gather_conflicts: arg={:?}", arg_id); 48419625d8cSopenharmony_ci let mut conflicts = Vec::new(); 48519625d8cSopenharmony_ci 48619625d8cSopenharmony_ci let arg_id_conflicts_storage; 48719625d8cSopenharmony_ci let arg_id_conflicts = if let Some(arg_id_conflicts) = self.get_direct_conflicts(arg_id) { 48819625d8cSopenharmony_ci arg_id_conflicts 48919625d8cSopenharmony_ci } else { 49019625d8cSopenharmony_ci // `is_missing_required_ok` is a case where we check not-present args for conflicts 49119625d8cSopenharmony_ci arg_id_conflicts_storage = gather_direct_conflicts(cmd, arg_id); 49219625d8cSopenharmony_ci &arg_id_conflicts_storage 49319625d8cSopenharmony_ci }; 49419625d8cSopenharmony_ci for (other_arg_id, other_arg_id_conflicts) in self.potential.iter() { 49519625d8cSopenharmony_ci if arg_id == other_arg_id { 49619625d8cSopenharmony_ci continue; 49719625d8cSopenharmony_ci } 49819625d8cSopenharmony_ci 49919625d8cSopenharmony_ci if arg_id_conflicts.contains(other_arg_id) { 50019625d8cSopenharmony_ci conflicts.push(other_arg_id.clone()); 50119625d8cSopenharmony_ci } 50219625d8cSopenharmony_ci if other_arg_id_conflicts.contains(arg_id) { 50319625d8cSopenharmony_ci conflicts.push(other_arg_id.clone()); 50419625d8cSopenharmony_ci } 50519625d8cSopenharmony_ci } 50619625d8cSopenharmony_ci 50719625d8cSopenharmony_ci debug!("Conflicts::gather_conflicts: conflicts={:?}", conflicts); 50819625d8cSopenharmony_ci conflicts 50919625d8cSopenharmony_ci } 51019625d8cSopenharmony_ci 51119625d8cSopenharmony_ci fn get_direct_conflicts(&self, arg_id: &Id) -> Option<&[Id]> { 51219625d8cSopenharmony_ci self.potential.get(arg_id).map(Vec::as_slice) 51319625d8cSopenharmony_ci } 51419625d8cSopenharmony_ci} 51519625d8cSopenharmony_ci 51619625d8cSopenharmony_cifn gather_direct_conflicts(cmd: &Command, id: &Id) -> Vec<Id> { 51719625d8cSopenharmony_ci let conf = if let Some(arg) = cmd.find(id) { 51819625d8cSopenharmony_ci gather_arg_direct_conflicts(cmd, arg) 51919625d8cSopenharmony_ci } else if let Some(group) = cmd.find_group(id) { 52019625d8cSopenharmony_ci gather_group_direct_conflicts(group) 52119625d8cSopenharmony_ci } else { 52219625d8cSopenharmony_ci debug_assert!(false, "id={id:?} is unknown"); 52319625d8cSopenharmony_ci Vec::new() 52419625d8cSopenharmony_ci }; 52519625d8cSopenharmony_ci debug!("Conflicts::gather_direct_conflicts id={id:?}, conflicts={conf:?}",); 52619625d8cSopenharmony_ci conf 52719625d8cSopenharmony_ci} 52819625d8cSopenharmony_ci 52919625d8cSopenharmony_cifn gather_arg_direct_conflicts(cmd: &Command, arg: &Arg) -> Vec<Id> { 53019625d8cSopenharmony_ci let mut conf = arg.blacklist.clone(); 53119625d8cSopenharmony_ci for group_id in cmd.groups_for_arg(arg.get_id()) { 53219625d8cSopenharmony_ci let group = cmd.find_group(&group_id).expect(INTERNAL_ERROR_MSG); 53319625d8cSopenharmony_ci conf.extend(group.conflicts.iter().cloned()); 53419625d8cSopenharmony_ci if !group.multiple { 53519625d8cSopenharmony_ci for member_id in &group.args { 53619625d8cSopenharmony_ci if member_id != arg.get_id() { 53719625d8cSopenharmony_ci conf.push(member_id.clone()); 53819625d8cSopenharmony_ci } 53919625d8cSopenharmony_ci } 54019625d8cSopenharmony_ci } 54119625d8cSopenharmony_ci } 54219625d8cSopenharmony_ci 54319625d8cSopenharmony_ci // Overrides are implicitly conflicts 54419625d8cSopenharmony_ci conf.extend(arg.overrides.iter().cloned()); 54519625d8cSopenharmony_ci 54619625d8cSopenharmony_ci conf 54719625d8cSopenharmony_ci} 54819625d8cSopenharmony_ci 54919625d8cSopenharmony_cifn gather_group_direct_conflicts(group: &ArgGroup) -> Vec<Id> { 55019625d8cSopenharmony_ci group.conflicts.clone() 55119625d8cSopenharmony_ci} 55219625d8cSopenharmony_ci 55319625d8cSopenharmony_cipub(crate) fn get_possible_values_cli(a: &Arg) -> Vec<PossibleValue> { 55419625d8cSopenharmony_ci if !a.is_takes_value_set() { 55519625d8cSopenharmony_ci vec![] 55619625d8cSopenharmony_ci } else { 55719625d8cSopenharmony_ci a.get_value_parser() 55819625d8cSopenharmony_ci .possible_values() 55919625d8cSopenharmony_ci .map(|pvs| pvs.collect()) 56019625d8cSopenharmony_ci .unwrap_or_default() 56119625d8cSopenharmony_ci } 56219625d8cSopenharmony_ci} 563