1
2include!(concat!(env!("OUT_DIR"), "/config.rs"));
3
4use std::env::vars;
5use regex::Regex;
6
7use crate::types::Search;
8use crate::types::Environment;
9use crate::types::Instance;
10use crate::types::EnvsMap;
11
12pub struct Parameters {
13 regexp: Regex,
14 search: Search,
15 env_name: Environment,
16 instance: Instance,
17 no_header: bool,
18 }
20
21impl Parameters {
22 pub fn new(regexp: String, search: String, env_name: Environment, instance: Instance, no_header: bool) -> Self {
23 #[cfg(debug_assertions)]
24 println!("-> Parameters::new({}, {}, e={:?}, i={:?}, nh={})", regexp, search, env_name, instance, no_header);
25
26 Self {
27 regexp: Regex::new(®exp).expect("Invalid regexp"),
28 search: search,
29 env_name: env_name,
30 instance: instance,
31 no_header: no_header,
32 }
33 }
34
35 pub fn process(&self, input: &String) -> String {
36 if cfg!(debug_assertions) {
37 println!("-> Parameters::process()");
38 println!("-> input: '{}'", input); println!();
39 }
40
41 let mut output: String = String::from(input);
42
43 let mut env_vars: EnvsMap = EnvsMap::new();
45 for (ename, evalue) in vars() {
46 if self.regexp.is_match(&ename) {
47 env_vars.insert(ename, evalue);
48 }
49 }
50
51 for (ename, evalue) in env_vars.iter().rev() {
52 #[cfg(debug_assertions)]
53 println!("-> var '{}': '{}'", ename, evalue);
54
55 let mut enamec = String::from(ename);
57
58 if let Some(_instance) = &self.instance {
60 #[cfg(debug_assertions)]
61 println!(" -> instance is some: '{}'", _instance);
62
63 let sub_instance = &enamec[(enamec.len() - _instance.len())..];
64
65 #[cfg(debug_assertions)]
66 println!(" -> sub instance: '{}'", sub_instance);
67
68 if _instance == sub_instance {
69 let _end = enamec.len() - _instance.len() - 1;
70 enamec = String::from(&enamec[0.._end]);
71
72 #[cfg(debug_assertions)]
73 println!(" -> new enamec: '{}'", enamec);
74 }
75 }
76
77 if let Some(_env_name) = &self.env_name {
79 #[cfg(debug_assertions)]
80 println!(" -> env is some: '{}'", _env_name);
81
82 let sub_env = &enamec[(enamec.len() - _env_name.len())..];
83
84 #[cfg(debug_assertions)]
85 println!(" -> sub env: '{}'", sub_env);
86
87 if _env_name == sub_env {
88 let _end = enamec.len() - _env_name.len() - 1;
89 enamec = String::from(&enamec[0.._end]);
90
91 #[cfg(debug_assertions)]
92 println!(" -> new enamec: '{}'", enamec);
93 }
94 }
95
96 let mut tpl_var: String = String::from(&self.search);
97 tpl_var.push_str(&enamec);
98 tpl_var.push_str(&self.search);
99
100 #[cfg(debug_assertions)]
101 println!(" -> template variable: '{}'", tpl_var);
102
103 output = output.replace(&tpl_var, &evalue);
104
105 if cfg!(debug_assertions) {
106 println!(" -> output: '{}'", output);
107 println!();
108 }
109 }
110
111 if cfg!(debug_assertions) {
112 println!();
113 println!("-> end output: '{}'", output);
114 }
115
116 if self.no_header {
117 output
119 } else {
120 format!("# Rendered by {} v{} @ {}\n\n{}", APP_NAME, APP_VERSION, chrono::Local::now().format("%Y-%m-%d %H:%M:%S %Z"), output)
122 }
123 }
124}
125
126#[cfg(test)]
127mod tests_sub_string {
128 #[test]
129 fn basic_test() {
130 assert!(true);
131 }
132
133 #[test]
134 fn test_substring1() {
135 let s1 = String::from("abcefg");
136 assert_eq!("ab", &s1[0..2]);
137 }
138
139 #[test]
140 fn test_substring2() {
141 let s1 = String::from("abcefg");
142 assert_eq!("ab", &s1[..2]);
143 }
144
145 #[test]
146 fn test_substring3() {
147 let s1 = String::from("abcefg");
148 assert_eq!("cefg", &s1[2..]);
149 }
150
151 #[test]
152 fn test_substring4() {
153 let s2 = String::from("cefg");
154 let s1 = String::from("abcefg");
155 assert_eq!("cefg", &s1[(s1.len() - s2.len())..]);
156 }
157}
158
159#[cfg(test)]
160mod tests_parameters {
161 use super::Parameters;
162 use crate::types::Search;
163 use crate::types::Environment;
164 use crate::types::Instance;
165
166 #[test]
167 fn test_parameters_single() {
168 let regexp: String = "^SYMF_".into();
169 let search: String = "@".into();
170 let input: String = "DB_USER=_@SYMF_DB_USER@#".into();
171
172 let p1 = Parameters::new(regexp, search, None, None, true);
173 assert_eq!("DB_USER=_user1#", p1.process(&input));
174 }
175
176 type SS = &'static str;
177 type BasicDto = (SS, SS, SS, SS);
178
179 #[test]
180 fn test_parameters_basic() {
181 let _data: Vec<BasicDto> = vec![
182 ("^SYMF_", "@", "DB_USER=@SYMF_DB_USER@", "DB_USER=user1"),
184 ("^SYMF_", "@", "DB_USER=_@SYMF_DB_USER@#", "DB_USER=_user1#"),
185 ("^SYMF_", "@", "DB_USER=/@SYMF_DB_USER@/", "DB_USER=/user1/"),
186
187 ("^SYMF_", "@", "DB_PASS=@SYMF_DB_PASS@", "DB_PASS=password1"),
188 ("^SYMF_", "@", "DB_PASS=_B_@SYMF_DB_PASS@_E_", "DB_PASS=_B_password1_E_"),
189 ("^SYMF_", "@", "DB_PASS=/@SYMF_DB_PASS@/@SYMF_DB_PASS@/", "DB_PASS=/password1/password1/"),
190
191 ("^SYMF_", "@", "DB_PASS1=@SYMF_DB_PASS@/DB_PASS2=@SYMF_DB_PASS_PRODUCTION@", "DB_PASS1=password1/DB_PASS2=password2"),
193
194 ("^SYMF_", "@", "DB_PASS1=@SYMF_DB_PASS@/DB_PASS2=@SYMF_DB_PASS_PRODUCTION@/DB_PASS3=@SYMF_DB_PASS_PRODUCTION_INSTANCE1@", "DB_PASS1=password1/DB_PASS2=password2/DB_PASS3=password3"),
196
197 ("^SYMF_", "@", "DB_PASS=/@SYMF_XYZ@/", "DB_PASS=/@SYMF_XYZ@/"),
199 ("^TEST_", "@", "DB_PASS=/@SYMF_DB_USER@/", "DB_PASS=/@SYMF_DB_USER@/"),
200 ];
201
202 for _t in _data {
203 let regexp: String = _t.0.into();
204 let search: Search = _t.1.into();
205 let input: String = _t.2.into();
206
207 let p1 = Parameters::new(regexp, search, None, None, true);
208 assert_eq!(_t.3, p1.process(&input));
209 }
210 }
211
212 type EnvDto = (SS, SS, SS, SS, SS);
213
214 #[test]
215 fn test_parameters_environment() {
216 let _data: Vec<EnvDto> = vec![
217 ("^SYMF_", "@", "PRODUCTION", "DB_PASS=@SYMF_DB_PASS@", "DB_PASS=password2"),
219
220 ("^SYMF_", "@", "ABC", "DB_PASS=@SYMF_DB_PASS_PRODUCTION@", "DB_PASS=password2"),
222
223 ("^SYMF_", "@", "ABC", "DB_PASS=@SYMF_DB_PASS@", "DB_PASS=password1"),
225
226 ("^SYMF_", "@", "ABC", "DB_PASS=@SYMF_DB_PASS_XYZ@", "DB_PASS=@SYMF_DB_PASS_XYZ@"),
228
229 ("^SYMF_", "@", "PRODUCTION", "DB_NAME=@SYMF_DB_NAME@", "DB_NAME=password5b"),
231 ("^SYMF_", "@", "ABC", "DB_NAME=@SYMF_DB_NAME@", "DB_NAME=@SYMF_DB_NAME@"),
232 ];
233
234 for _t in _data {
235 let regexp: String = _t.0.into();
236 let search: Search = _t.1.into();
237 let env_name: Environment = Some(_t.2.into());
238 let input: String = _t.3.into();
239
240 let p1 = Parameters::new(regexp, search, env_name, None, true);
241 assert_eq!(_t.4, p1.process(&input));
242 }
243 }
244
245 type InstanceDto = (SS, SS, SS, SS, SS, SS);
246
247 #[test]
248 fn test_parameters_instance() {
249 let _data: Vec<InstanceDto> = vec![
250 ("^SYMF_", "@", "PRODUCTION", "INSTANCE1", "DB_PASS=@SYMF_DB_PASS@", "DB_PASS=password3"),
252 ("^SYMF_", "@", "PRODUCTION", "INSTANCE2", "DB_PASS=@SYMF_DB_PASS@", "DB_PASS=password4"),
253
254 ("^SYMF_", "@", "PRODUCTION", "ABC", "DB_PASS=@SYMF_DB_PASS_PRODUCTION_INSTANCE1@", "DB_PASS=password3"),
256
257 ("^SYMF_", "@", "PRODUCTION", "ABC", "DB_PASS=@SYMF_DB_PASS@", "DB_PASS=password2"),
259
260 ("^SYMF_", "@", "PRODUCTION", "ABC", "DB_PASS=@SYMF_DB_PASS_PRODUCTION@", "DB_PASS=@SYMF_DB_PASS_PRODUCTION@"),
262 ];
263
264 for _t in _data {
265 let regexp: String = _t.0.into();
266 let search: Search = _t.1.into();
267 let env_name: Environment = Some(_t.2.into());
268 let instance: Instance = Some(_t.3.into());
269 let input: String = _t.4.into();
270
271 let p1 = Parameters::new(regexp, search, env_name, instance, true);
272 assert_eq!(_t.5, p1.process(&input));
273 }
274 }
275}