Skip to content

Commit 7bb802a

Browse files
authored
实现简单的命令行解析器 (#49)
1 parent b0dea7c commit 7bb802a

File tree

8 files changed

+937
-600
lines changed

8 files changed

+937
-600
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ num_enum_derive = "0.7.1"
1717
path-clean = "1.0.1"
1818
crossterm = "0.27.0"
1919
colored = "2.1.0"
20+
which = "6.0.3"
21+
concat-idents = "1.1.5"

src/env.rs

Lines changed: 11 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,24 @@
11
use std::{
2-
collections::HashMap,
3-
fmt,
42
fs::File,
53
io::{Read, Write},
6-
ops::{Deref, DerefMut},
74
path::Path,
85
};
96

107
pub const ROOT_PATH: &str = "/";
11-
pub const ENV_FILE_PATH: &str = "/etc/profile";
128

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-
}
9+
pub struct EnvManager;
8410

85-
impl DerefMut for Env {
86-
fn deref_mut(&mut self) -> &mut Self::Target {
87-
&mut self.0
88-
}
89-
}
11+
impl EnvManager {
12+
pub const ENV_FILE_PATH: &str = "/etc/profile";
9013

91-
impl Env {
92-
/// 初始化环境变量结构体
14+
/// 初始化环境变量相关信息
9315
pub fn init() {
94-
// unsafe { ENV = Some(std::sync::Mutex::new(Env(HashMap::new()))) };
95-
unsafe { ENV = Some(Env(HashMap::new())) };
9616
Self::read_env();
9717
}
9818

99-
/// 获取Env引用
100-
pub fn env() -> &'static mut Env {
101-
unsafe { ENV.as_mut().unwrap() }
102-
}
103-
10419
/// 初始化环境变量文件
10520
pub fn init_envfile() {
106-
let mut file = File::create(ENV_FILE_PATH).unwrap();
21+
let mut file = File::create(Self::ENV_FILE_PATH).unwrap();
10722
file.write_all("PATH=/bin:/usr/bin:/usr/local/bin\n".as_bytes())
10823
.unwrap();
10924
file.write_all("PWD=/\n".as_bytes()).unwrap();
@@ -112,89 +27,26 @@ impl Env {
11227
/// 读取环境变量文件
11328
/// 如果文件不存在则创建
11429
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();
30+
if !Path::new(Self::ENV_FILE_PATH).exists() {
31+
Self::init_envfile();
11932
}
120-
let mut file = File::open(ENV_FILE_PATH).unwrap();
33+
34+
let mut file = File::open(Self::ENV_FILE_PATH).unwrap();
12135
let mut buf: Vec<u8> = Vec::new();
12236
file.read_to_end(&mut buf).unwrap();
12337

12438
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);
39+
if let Some(index) = str.find('=') {
40+
std::env::set_var(&str[..index], &str[index + 1..]);
12741
}
12842
}
12943
}
13044

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-
15945
pub fn current_dir() -> String {
16046
std::env::current_dir()
16147
.expect("Error getting current directory")
16248
.to_str()
16349
.unwrap()
16450
.to_string()
16551
}
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-
}
20052
}

src/main.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ mod keycode;
1111

1212
mod env;
1313

14-
use env::Env;
14+
mod parser;
15+
16+
use env::EnvManager;
1517
use shell::Shell;
1618

1719
fn main() {
18-
Env::init();
20+
EnvManager::init();
1921
let mut shell = Shell::new();
2022
shell.exec();
2123
return;

0 commit comments

Comments
 (0)