1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
use std::fmt;
use eyre::{eyre, OptionExt, Result};
use regex::Captures;
use super::command_line::CommandLine;
use super::pattern::r#match;
use super::ItemSource;
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct InferenceRule {
pub source: ItemSource,
pub products: Vec<String>,
pub prerequisites: Vec<String>,
pub commands: Vec<CommandLine>,
}
impl InferenceRule {
/// s1 is the product, s2 is the prereq
pub fn new_suffix(
source: ItemSource,
s1: String,
s2: String,
commands: Vec<CommandLine>,
) -> Self {
Self {
source,
products: vec![format!("%{}", s1)],
prerequisites: vec![format!("%{}", s2)],
commands,
}
}
pub fn first_match<'s, 't: 's>(&'s self, target_name: &'t str) -> Result<Option<Captures<'t>>> {
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<bool> {
self.first_match(target_name).map(|x| x.is_some())
}
pub fn prereqs<'s>(
&'s self,
target_name: &'s str,
) -> Result<impl Iterator<Item = String> + '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)
.ok_or_eyre("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(
ItemSource::Builtin,
".o".to_owned(),
".c".to_owned(),
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 {
source: ItemSource::Builtin,
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(())
}
}
|