xref: /NovaShell/src/env.rs (revision 5b85994156defaf7a9d43e4b747af603d8d1ffc4)
1 use std::{
2     collections::HashMap,
3     fmt,
4     fs::File,
5     io::{Read, Write},
6     ops::{Deref, DerefMut},
7     path::Path,
8 };
9 
10 pub const ROOT_PATH: &str = "/";
11 pub const ENV_FILE_PATH: &str = "/etc/profile";
12 
13 #[derive(Clone, Debug)]
14 pub struct EnvEntry {
15     /// 环境变量的名称
16     name: String,
17     /// 环境变量值的原始字符串,多个值之间使用':'分隔
18     origin: String,
19     /// 值分割后的集合
20     collection: Vec<String>,
21 }
22 
23 impl EnvEntry {
24     pub fn new(env: String) -> Option<EnvEntry> {
25         let split_result = env.split('=').collect::<Vec<&str>>();
26         if split_result.len() != 2 || split_result.contains(&"") {
27             return None;
28         }
29 
30         let name = split_result.get(0).unwrap().to_string();
31         let origin = split_result.get(1).unwrap().to_string();
32 
33         let collection = origin
34             .split(':')
35             .filter_map(|str| {
36                 let path = String::from(str);
37                 if Path::new(&path).is_dir() {
38                     Some(path)
39                 } else {
40                     None
41                 }
42             })
43             .collect::<Vec<String>>();
44 
45         Some(EnvEntry {
46             name,
47             origin,
48             collection,
49         })
50     }
51 
52     #[allow(dead_code)]
53     pub fn name(&self) -> &String {
54         &self.name
55     }
56 
57     pub fn origin(&self) -> &String {
58         &self.origin
59     }
60 
61     #[allow(dead_code)]
62     pub fn collection(&self) -> &Vec<String> {
63         &self.collection
64     }
65 }
66 
67 impl fmt::Display for EnvEntry {
68     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69         write!(f, "{}={}", self.name, self.origin)
70     }
71 }
72 
73 pub struct Env(HashMap<String, EnvEntry>);
74 
75 static mut ENV: Option<Env> = None;
76 
77 impl Deref for Env {
78     type Target = HashMap<String, EnvEntry>;
79 
80     fn deref(&self) -> &Self::Target {
81         &self.0
82     }
83 }
84 
85 impl DerefMut for Env {
86     fn deref_mut(&mut self) -> &mut Self::Target {
87         &mut self.0
88     }
89 }
90 
91 impl Env {
92     /// 初始化环境变量结构体
93     pub fn init() {
94         // unsafe { ENV = Some(std::sync::Mutex::new(Env(HashMap::new()))) };
95         unsafe { ENV = Some(Env(HashMap::new())) };
96         Self::read_env();
97     }
98 
99     /// 获取Env引用
100     pub fn env() -> &'static mut Env {
101         unsafe { ENV.as_mut().unwrap() }
102     }
103 
104     /// 初始化环境变量文件
105     pub fn init_envfile() {
106         let mut file = File::create(ENV_FILE_PATH).unwrap();
107         file.write_all("PATH=/bin:/usr/bin:/usr/local/bin\n".as_bytes())
108             .unwrap();
109         file.write_all("PWD=/\n".as_bytes()).unwrap();
110     }
111 
112     /// 读取环境变量文件
113     /// 如果文件不存在则创建
114     pub fn read_env() {
115         let env = unsafe { ENV.as_mut().unwrap() };
116 
117         if !Path::new(ENV_FILE_PATH).exists() {
118             Env::init_envfile();
119         }
120         let mut file = File::open(ENV_FILE_PATH).unwrap();
121         let mut buf: Vec<u8> = Vec::new();
122         file.read_to_end(&mut buf).unwrap();
123 
124         for str in String::from_utf8(buf).unwrap().split('\n') {
125             if let Some(entry) = EnvEntry::new(str.to_string()) {
126                 env.insert(entry.name.clone(), entry);
127             }
128         }
129     }
130 
131     pub fn get(key: &String) -> Option<&EnvEntry> {
132         let env = unsafe { ENV.as_ref().unwrap() };
133         env.0.get(key)
134     }
135 
136     pub fn insert(key: String, value: String) {
137         if let Some(entry) = EnvEntry::new(value) {
138             Self::env().insert(key, entry);
139         }
140     }
141 
142     /// 获取PATH环境变量的值(已分割)
143     pub fn path() -> Vec<String> {
144         let env = Self::env();
145         env.get("PATH").unwrap().collection.clone()
146         // paths
147         //     .split(':')
148         //     .filter_map(|str| {
149         //         let path = String::from(str);
150         //         if Path::new(&path).is_dir() {
151         //             Some(path)
152         //         } else {
153         //             None
154         //         }
155         //     })
156         //     .collect::<Vec<String>>()
157     }
158 
159     pub fn current_dir() -> String {
160         std::env::current_dir()
161             .expect("Error getting current directory")
162             .to_str()
163             .unwrap()
164             .to_string()
165     }
166 
167     /// 从环境变量搜索路径,返回第一个匹配的绝对路径
168     pub fn search_path_from_env(path: &String) -> Option<String> {
169         let mut absolute_path = String::new();
170         if !path.contains('/') {
171             let mut dir_collection = Env::path();
172             dir_collection.insert(0, Self::current_dir());
173             for dir in dir_collection {
174                 let possible_path = format!("{}/{}", dir, path);
175                 if Path::new(&possible_path).is_file() {
176                     absolute_path = possible_path;
177                     break;
178                 }
179             }
180             if absolute_path.is_empty() {
181                 return None;
182             } else {
183                 return Some(absolute_path);
184             }
185         } else if Path::new(path).exists() {
186             return Some(path.clone());
187         } else {
188             return None;
189         }
190     }
191 
192     /// 返回所有环境变量的集合
193     pub fn get_all() -> Vec<(String, String)> {
194         let mut vec = Vec::new();
195         for (name, entry) in Self::env().iter() {
196             vec.push((name.clone(), entry.origin.clone()));
197         }
198         vec
199     }
200 }
201