use std::fmt; use eyre::{eyre, Result}; use regex::Captures; use super::command_line::CommandLine; use super::pattern::r#match; #[derive(PartialEq, Eq, Clone, Debug)] pub struct InferenceRule { pub products: Vec, pub prerequisites: Vec, pub commands: Vec, } impl InferenceRule { /// s1 is the product, s2 is the prereq pub fn new_suffix(s1: String, s2: String, commands: Vec) -> Self { Self { products: vec![format!("%{}", s1)], prerequisites: vec![format!("%{}", s2)], commands, } } fn first_match<'s, 't: 's>(&'s self, target_name: &'t str) -> Result>> { self.products .iter() .map(|pattern| r#match(pattern, target_name)) .try_fold(None, |x, y| y.map(|y| x.or(y))) } pub fn matches(&self, target_name: &str) -> Result { self.first_match(target_name).map(|x| x.is_some()) } pub fn prereqs<'s>( &'s self, target_name: &'s str, ) -> Result + 's> { let capture = self .first_match(target_name)? .ok_or_else(|| eyre!("asked non-matching inference rule for prerequisites"))?; let percent_expansion = capture.get(1).expect("should've matched the %").as_str(); Ok(self .prerequisites .iter() .map(move |p| p.replace('%', percent_expansion))) } } impl fmt::Display for InferenceRule { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!( f, "{}: {}", self.products.join(" "), self.prerequisites.join(" ") )?; for command in &self.commands { writeln!(f, "\t{}", command)?; } Ok(()) } } #[cfg(test)] mod test { use super::*; type R = eyre::Result<()>; #[test] fn suffix_match() -> R { let rule = InferenceRule::new_suffix(".o".to_string(), ".c".to_string(), vec![]); assert!(rule.matches("foo.o")?); assert!(rule.matches("dir/foo.o")?); Ok(()) } #[cfg(feature = "full")] #[test] fn percent_match() -> R { // thanks, SPDX License List let rule = InferenceRule { products: vec!["licenseListPublisher-%.jar-valid".to_owned()], prerequisites: vec![ "licenseListPublisher-%.jar.asc".to_owned(), "licenseListPublisher-%.jar".to_owned(), "goneall.gpg".to_owned(), ], commands: vec![], }; assert!(rule.matches("licenseListPublisher-2.2.1.jar-valid")?); Ok(()) } }