|
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