risedev/config/
dollar_expander.rs1use std::collections::HashMap;
16
17use anyhow::{Result, anyhow};
18use regex::Regex;
19use yaml_rust::Yaml;
20
21pub struct DollarExpander {
23 re: Regex,
24 extra_info: HashMap<String, String>,
25}
26
27fn yaml_to_string(y: &Yaml) -> Result<String> {
28 match y {
29 Yaml::Integer(x) => Ok(format!("{}", x)),
30 Yaml::String(x) => Ok(x.clone()),
31 _ => Err(anyhow!("{:?} cannot be converted to string", y)),
32 }
33}
34
35impl DollarExpander {
36 pub fn new(extra_info: HashMap<String, String>) -> Self {
37 Self {
38 re: Regex::new(r"\$\{(.*?)\}").unwrap(),
39 extra_info,
40 }
41 }
42
43 pub fn visit(&mut self, y: Yaml) -> Result<Yaml> {
44 match y {
45 Yaml::Hash(y) => {
46 let mut ny = y.clone();
47 for (_, v) in &mut ny {
48 let result = if let Some(v) = v.as_str() {
49 let mut target = String::new();
50 let mut last_location = 0;
51 for cap in self.re.captures_iter(v) {
52 let cap = cap.get(1).unwrap();
53 let name = cap.as_str();
54 let value = match y.get(&Yaml::String(name.to_owned())) {
55 Some(item) => yaml_to_string(item)?,
56 _ => {
57 if let Some(item) = self.extra_info.get(name) {
58 item.clone()
59 } else {
60 return Err(anyhow!("{} not found in {:?}", name, y));
61 }
62 }
63 };
64 target += &v[last_location..(cap.start() - 2)]; target += &value;
66 last_location = cap.end() + 1; }
68 target += &v[last_location..v.len()];
69 Yaml::String(target)
70 } else {
71 self.visit(v.clone())?
72 };
73 *v = result;
74 }
75 Ok(Yaml::Hash(ny))
76 }
77 Yaml::Array(mut yv) => {
78 for y in &mut yv {
79 *y = self.visit(y.clone())?;
80 }
81 Ok(Yaml::Array(yv))
82 }
83 other => Ok(other),
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use yaml_rust::YamlLoader;
91
92 use super::*;
93
94 #[test]
95 fn test_expand_dollar() {
96 let yaml = YamlLoader::load_from_str(
97 "
98a:
99 b:
100 c:
101 d: \"${x}${y},${test:key}\"
102 x: 2333
103 y: 2334
104 ",
105 )
106 .unwrap()
107 .remove(0);
108 let yaml_result = YamlLoader::load_from_str(
109 "
110 a:
111 b:
112 c:
113 d: \"23332334,value\"
114 x: 2333
115 y: 2334
116 ",
117 )
118 .unwrap()
119 .remove(0);
120 let mut visitor = DollarExpander::new(
121 vec![("test:key".to_owned(), "value".to_owned())]
122 .into_iter()
123 .collect(),
124 );
125
126 assert_eq!(visitor.visit(yaml).unwrap(), yaml_result);
127 }
128}