1extern crate regex;
6
7use regex::Regex;
8
9pub fn expand_env<T: AsRef<str>>(p: T) -> String {
11 let mut p = String::from(p.as_ref());
13 p = p.replace("~", "${HOME}");
14 let start = '{';
15 let end = '}';
16 let re = Regex::new(r"\$(\w+|\{[^}]*\})").unwrap();
17 let mut global_start_pos = 0;
18
19 #[warn(unused_variables, unused_mut)]
20 let mut result = String::new();
21
22 for cap in re.find_iter(&p) {
23 let mut name = cap.as_str();
24 name = &name[1..name.chars().count()];
25 let name_len = name.chars().count();
26 if name.chars().nth(0).unwrap() == start && name.chars().nth(name_len - 1).unwrap() == end {
27 name = &name[1..name_len - 1];
28 }
29
30 let local_start_pos = cap.start();
31 if global_start_pos < local_start_pos {
32 let inner: String = p
33 .chars()
34 .skip(global_start_pos)
35 .take(local_start_pos - global_start_pos)
36 .collect();
37 result.push_str(inner.as_str());
38 }
39
40 for (ref key, ref value) in std::env::vars().into_iter() {
41 if key == name {
42 result.push_str(value);
43 break;
44 }
45 }
46 global_start_pos = cap.end();
47 }
48
49 let end_pos = p.chars().count();
50 if global_start_pos < end_pos {
51 let inner: String = p
52 .chars()
53 .skip(global_start_pos)
54 .take(end_pos - global_start_pos)
55 .collect();
56 result.push_str(inner.as_str());
57 }
58 println!("result: {}", result);
59
60 return result;
61}
62
63#[cfg(test)]
64mod tests {
65 use super::expand_env;
66
67 #[test]
68 fn test_expand_env() {
69 let s = expand_env("${PWD}/a/$HOME/c.txt");
70 let pwd = std::env::current_dir().unwrap();
71 let home = std::env::home_dir().unwrap();
72 let s2 = format!(
73 "{}/a/{}/c.txt",
74 pwd.to_str().unwrap(),
75 home.to_str().unwrap()
76 );
77 assert_eq!(s, s2);
78 }
79}