|
3 | 3 | // SPDX-License-Identifier: MPL-2.0 |
4 | 4 |
|
5 | 5 | use std::collections::BTreeMap; |
| 6 | +use std::path::PathBuf; |
6 | 7 |
|
7 | | -use fnmatch::Pattern; |
8 | | -use serde::Deserialize; |
| 8 | +use serde::{Deserialize, Deserializer}; |
9 | 9 |
|
10 | | -/// Filter matched paths to a specific kind |
11 | | -#[derive(Debug, Deserialize)] |
12 | | -#[serde(rename_all = "lowercase")] |
13 | | -pub enum PathKind { |
14 | | - Directory, |
15 | | - Symlink, |
16 | | -} |
17 | | - |
18 | | -/// Execution handlers for a trigger |
19 | | -#[derive(Debug, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord)] |
20 | | -#[serde(untagged)] |
21 | | -pub enum Handler { |
22 | | - Run { run: String, args: Vec<String> }, |
23 | | - Delete { delete: Vec<String> }, |
24 | | -} |
| 10 | +use crate::{FileKind, Inhibitor, OsEnv, Pattern}; |
25 | 11 |
|
26 | | -#[derive(Debug, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord)] |
27 | | -pub struct CompiledHandler(Handler); |
28 | | - |
29 | | -impl CompiledHandler { |
30 | | - pub fn handler(&self) -> &Handler { |
31 | | - &self.0 |
| 12 | +/// Deserializes the "inhibitors" field of a [`Trigger`]. |
| 13 | +pub fn deserialize_inhibitors<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<Inhibitor>, D::Error> { |
| 14 | + #[derive(Default, Deserialize)] |
| 15 | + struct Inhibitors { |
| 16 | + pub paths: Vec<PathBuf>, |
| 17 | + pub environment: Vec<OsEnv>, |
32 | 18 | } |
33 | | -} |
34 | 19 |
|
35 | | -impl Handler { |
36 | | - /// Substitute all paths using matched variables |
37 | | - pub fn compiled(&self, with_match: &fnmatch::Match) -> CompiledHandler { |
38 | | - match self { |
39 | | - Handler::Run { run, args } => { |
40 | | - let mut run = run.clone(); |
41 | | - for (key, value) in &with_match.groups { |
42 | | - run = run.replace(&format!("$({key})"), value); |
43 | | - } |
44 | | - let args = args |
45 | | - .iter() |
46 | | - .map(|a| { |
47 | | - let mut a = a.clone(); |
48 | | - for (key, value) in &with_match.groups { |
49 | | - a = a.replace(&format!("$({key})"), value); |
50 | | - } |
51 | | - a |
52 | | - }) |
53 | | - .collect(); |
54 | | - CompiledHandler(Handler::Run { run, args }) |
55 | | - } |
56 | | - Handler::Delete { delete } => CompiledHandler(Handler::Delete { delete: delete.clone() }), |
57 | | - } |
| 20 | + let de = Inhibitors::deserialize(deserializer)?; |
| 21 | + let mut inhibitors = vec![]; |
| 22 | + for path in de.paths { |
| 23 | + inhibitors.push(Inhibitor::Path(path)); |
| 24 | + } |
| 25 | + for env in de.environment { |
| 26 | + inhibitors.push(Inhibitor::Environment(env)); |
| 27 | + } |
| 28 | + Ok(inhibitors) |
| 29 | +} |
| 30 | + |
| 31 | +/// Deserializes the "paths" field of a [`Trigger`]. |
| 32 | +pub fn deserialize_patterns<'de, D: Deserializer<'de>>( |
| 33 | + deserializer: D, |
| 34 | +) -> Result<BTreeMap<Pattern, Vec<String>>, D::Error> { |
| 35 | + #[derive(Deserialize)] |
| 36 | + struct PathDefinition { |
| 37 | + pub handlers: Vec<String>, |
| 38 | + #[serde(rename = "type")] |
| 39 | + pub kind: Option<FileKind>, |
58 | 40 | } |
59 | | -} |
60 | | - |
61 | | -/// Inhibitors prevent handlers from running based on some constraints |
62 | | -#[derive(Debug, Deserialize)] |
63 | | -pub struct Inhibitors { |
64 | | - pub paths: Vec<String>, |
65 | | - pub environment: Vec<String>, |
66 | | -} |
67 | | - |
68 | | -/// Map handlers to a path pattern and kind filter |
69 | | -#[derive(Debug, Deserialize)] |
70 | | -pub struct PathDefinition { |
71 | | - pub handlers: Vec<String>, |
72 | | - #[serde(rename = "type")] |
73 | | - pub kind: Option<PathKind>, |
74 | | -} |
75 | | - |
76 | | -/// Serialization format of triggers |
77 | | -#[derive(Debug, Deserialize)] |
78 | | -pub struct Trigger { |
79 | | - /// Unique (global scope) identifier |
80 | | - pub name: String, |
81 | | - |
82 | | - /// User friendly description |
83 | | - pub description: String, |
84 | | - |
85 | | - /// Run before this trigger name |
86 | | - pub before: Option<String>, |
87 | | - |
88 | | - /// Run after this trigger name |
89 | | - pub after: Option<String>, |
90 | | - |
91 | | - /// Optional inhibitors |
92 | | - pub inhibitors: Option<Inhibitors>, |
93 | | - |
94 | | - /// Map glob / patterns to their configuration |
95 | | - pub paths: BTreeMap<Pattern, PathDefinition>, |
96 | | - |
97 | | - /// Named handlers within this trigger scope |
98 | | - pub handlers: BTreeMap<String, Handler>, |
99 | | -} |
100 | | - |
101 | | -#[cfg(test)] |
102 | | -mod tests { |
103 | | - use crate::format::Trigger; |
104 | | - |
105 | | - #[test] |
106 | | - fn test_trigger_file() { |
107 | | - let trigger: Trigger = serde_yaml::from_str(include_str!("../../../test/trigger.yml")).unwrap(); |
108 | 41 |
|
109 | | - let (pattern, _) = trigger.paths.iter().next().expect("Missing path entry"); |
110 | | - let result = pattern |
111 | | - .matches("/usr/lib/modules/6.6.7-267.current/kernel") |
112 | | - .expect("Couldn't match path"); |
113 | | - let version = result.groups.get("version").expect("Missing kernel version"); |
114 | | - assert_eq!(version, "6.6.7-267.current", "Wrong kernel version match"); |
115 | | - eprintln!("trigger: {trigger:?}"); |
116 | | - eprintln!("match: {result:?}"); |
| 42 | + let de = BTreeMap::<fnmatch::Pattern, PathDefinition>::deserialize(deserializer)?; |
| 43 | + let mut paths = BTreeMap::new(); |
| 44 | + for (pattern, path_definition) in de { |
| 45 | + paths.insert( |
| 46 | + Pattern { |
| 47 | + kind: path_definition.kind, |
| 48 | + pattern, |
| 49 | + }, |
| 50 | + path_definition.handlers, |
| 51 | + ); |
117 | 52 | } |
| 53 | + Ok(paths) |
118 | 54 | } |
0 commit comments