proplate_core/template/
op.rs1use std::{collections::HashMap, fs, path::Path};
2
3use proplate_errors::{ProplateError, ProplateErrorKind, ProplateResult};
4use serde::{Deserialize, Serialize};
5
6use super::interpolation::Interpolate;
7use crate::fs as pfs;
8
9#[derive(Serialize, Deserialize, Debug, Clone)]
10pub enum StringCompareOp {
11 Eq,
12 NotEqual,
13}
14
15#[derive(Serialize, Deserialize, Debug, Clone)]
16pub struct Condition {
17 pub lhs: String,
18 pub op: StringCompareOp,
19 pub rhs: String,
20}
21
22#[derive(Serialize, Deserialize, Debug)]
23pub enum Operation {
24 Copy { file: String, dest: String },
26 CopyDir { path: String, dest: String },
27 Remove { files: Vec<String> },
28}
29
30#[derive(Serialize, Deserialize, Debug)]
31pub struct AdditionalOperation {
32 #[serde(default = "Vec::new")]
33 pub conditions: Vec<Condition>,
34 pub operations: Vec<Operation>,
36}
37
38impl Condition {
39 fn eval(&self) -> bool {
40 match self.op {
41 StringCompareOp::Eq => self.lhs == self.rhs,
42 StringCompareOp::NotEqual => self.lhs != self.rhs,
43 }
44 }
45
46 pub fn eval_in_ctx(&self, ctx: &HashMap<String, String>) -> bool {
47 let mut c = self.clone();
48 c.lhs = c.lhs.interpolate(ctx);
49 c.rhs = c.rhs.interpolate(ctx);
50 c.eval()
51 }
52}
53
54pub trait Execute {
55 fn execute(&self, ctx: &HashMap<String, String>) -> ProplateResult<()>;
56}
57
58impl Execute for Operation {
59 fn execute(&self, _ctx: &HashMap<String, String>) -> ProplateResult<()> {
60 match self {
61 Operation::Copy { file, dest } => {
62 let src = Path::new(&file);
63 let dest = Path::new(&dest);
64 fs::copy(src, dest).map_err(|e| {
65 ProplateError::create(ProplateErrorKind::Fs {
66 concerned_paths: vec![src.display().to_string(), dest.display().to_string()],
67 operation: "copy".into(),
68 })
69 .with_ctx("op::execute::Copy")
70 .with_cause(&e.to_string())
71 })?;
72 Ok(())
73 }
74 Operation::CopyDir { path, dest } => {
75 let path = Path::new(path);
76 let dest = Path::new(dest);
77 pfs::copy_fdir(path, dest, None).map_err(|e| {
78 ProplateError::create(ProplateErrorKind::Fs {
79 concerned_paths: vec![path.display().to_string(), dest.display().to_string()],
80 operation: "copy_dir".into(),
81 })
82 .with_ctx("op::execute::CopyDir")
83 .with_cause(&e.to_string())
84 })?;
85 Ok(())
86 }
87 Operation::Remove { files } => {
88 for file in files {
89 let src = Path::new(&file);
90 pfs::remove_fdir(src).map_err(|e| {
91 ProplateError::create(ProplateErrorKind::Fs {
92 concerned_paths: vec![src.display().to_string()],
93 operation: "remove_fdir".into(),
94 })
95 .with_ctx("op::execute::Remove")
96 .with_cause(&e.to_string())
97 })?;
98 }
99 Ok(())
100 }
101 }
102 }
103}
104
105impl Execute for AdditionalOperation {
106 fn execute(&self, ctx: &HashMap<String, String>) -> ProplateResult<()> {
107 let conditions = &self.conditions;
109 let true_ = match conditions.is_empty() {
110 true => true,
111 false => conditions.iter().all(|c| c.eval_in_ctx(ctx)),
112 };
113
114 if true_ {
115 for operation in &self.operations {
116 operation.execute(ctx)?;
117 }
118 }
119
120 Ok(())
121 }
122}