Skip to content

Commit b5fe661

Browse files
committed
Support builtin commands: pwd, cd, lcd
1 parent 22f6ce6 commit b5fe661

File tree

3 files changed

+85
-78
lines changed

3 files changed

+85
-78
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ documentation = "https://docs.rs/cmd_lib"
88
keywords = ["shell", "scripts", "commandline", "subprocess", "pipeline"]
99
categories = ["command-line-interface", "command-line-utilities"]
1010
readme = "README.md"
11-
version = "0.7.5"
11+
version = "0.7.7"
1212
authors = ["rust-shell-script <rust-shell-script@gmail.com>"]
1313
edition = "2018"
1414

README.md

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,36 @@ Process::new("ls")
5757
.wait::<CmdResult>()?;
5858
```
5959

60-
## Run commands with different environment settings
60+
## Builtin commands
61+
### pwd
62+
pwd: print current working directory
63+
64+
### cd
65+
cd: set procecess current directory
66+
6167
```rust
62-
Env::new()
63-
.cd("/src/rust-shell-script/")
64-
.exec("du -ah")
65-
.pipe("sort -hr")
66-
.pipe("head -n 5")
67-
.wait::<CmdResult>()?;
68+
run_cmd! {
69+
cd /tmp
70+
ls | wc -l
71+
};
72+
run_cmd!("pwd");
73+
```
6874

69-
let res = Env::new().cd("/home").exec("ls").wait::<FunResult>()?;
75+
output will be "/tmp"
76+
77+
### lcd
78+
lcd: set group commands current directory
79+
80+
```rust
81+
run_cmd! {
82+
lcd /tmp
83+
ls | wc -l
84+
};
85+
run_cmd!("pwd");
7086
```
7187

88+
output will be the old current directory
89+
7290
## Easy Reporting
7391
```rust
7492
info!("Running command xxx ...");
@@ -90,9 +108,12 @@ FATAL: Command exit unexpectedly: disk is full
90108
use cmd_lib::{info, warn, output, run_cmd, run_fun, CmdResult, FunResult};
91109

92110
fn foo() -> CmdResult {
93-
let f = "/var/tmp/nofile";
94-
run_cmd!{
95-
use f;
111+
let dir = "/var/tmp";
112+
let f = "nofile";
113+
114+
run_cmd! {
115+
use dir, f;
116+
cd ${dir};
96117
sleep 3;
97118
ls ${f};
98119
}
@@ -130,14 +151,13 @@ INFO: Running "echo hello, rust" ...
130151
hello, rust
131152
INFO: Running "du -ah . | sort -hr | head -n 5" ...
132153
INFO: Top 5 directories:
133-
362M .
134-
360M ./target
135-
216M ./target/debug
136-
131M ./target/debug/incremental
137-
117M ./target/package
154+
24K .
155+
16K ./lib.rs
156+
4.0K ./main.rs
157+
INFO: Set process current_dir: "/var/tmp"
138158
INFO: Running "sleep 3" ...
139-
INFO: Running "ls "/var/tmp/nofile"" ...
140-
ls: cannot access '/var/tmp/nofile': No such file or directory
159+
INFO: Running "ls nofile" ...
160+
ls: cannot access 'nofile': No such file or directory
141161
WARN: Failed to run foo()
142162
INFO: Running "date +%Y" ...
143163
INFO: You are in year 2019

src/lib.rs

Lines changed: 46 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -204,43 +204,6 @@ macro_rules! run_cmd {
204204
}};
205205
}
206206

207-
/// Envrionment settings
208-
pub struct Env {
209-
current_dir: String,
210-
variables: HashMap<String, String>,
211-
}
212-
213-
impl Env {
214-
pub fn new() -> Self {
215-
Self {
216-
current_dir: ".".to_string(),
217-
variables: HashMap::new(),
218-
}
219-
}
220-
221-
pub fn cd(&mut self, dir: &str) -> &Self {
222-
self.current_dir = dir.to_string();
223-
self
224-
}
225-
226-
pub fn pwd(&self) -> &str {
227-
&self.current_dir
228-
}
229-
230-
pub fn set(&mut self, key: String, val: String) -> &Self {
231-
self.variables.insert(key, val);
232-
self
233-
}
234-
235-
pub fn get(&mut self, key: &str) -> Option<&String> {
236-
self.variables.get(key)
237-
}
238-
239-
pub fn exec(&self, cmd: &str) -> Process {
240-
Process::new_with_env(self, cmd)
241-
}
242-
}
243-
244207
#[doc(hidden)]
245208
pub trait ProcessResult {
246209
fn get_result(process: &mut Process) -> Self;
@@ -257,30 +220,22 @@ pub trait ProcessResult {
257220
/// .wait::<CmdResult>()?
258221
/// ```
259222
///
260-
pub struct Process<'a> {
261-
env: Option<&'a Env>,
223+
pub struct Process {
262224
cur_dir: Option<String>,
263225
full_cmd: Vec<Vec<String>>,
264226
}
265227

266-
impl<'a> Process<'a> {
228+
impl Process {
267229
pub fn new<S: Borrow<str>>(pipe_cmd: S) -> Self {
268230
let args = parse_args(pipe_cmd.borrow());
269231
let argv = parse_argv(args);
270232

271233
Self {
272-
env: None,
273234
cur_dir: None,
274235
full_cmd: vec![argv],
275236
}
276237
}
277238

278-
fn new_with_env(env: &'a Env, cmd: &str) -> Self {
279-
let mut p = Process::new(cmd);
280-
p.env = Some(env);
281-
p
282-
}
283-
284239
pub fn current_dir<S: Borrow<str>>(&mut self, dir: S) -> &mut Self {
285240
self.cur_dir = Some(dir.borrow().to_string());
286241
self
@@ -335,18 +290,14 @@ fn format_full_cmd(full_cmd: &Vec<Vec<String>>) -> String {
335290
fn run_full_cmd(process: &mut Process, pipe_last: bool) -> Result<(Child, String)> {
336291
let mut full_cmd_str = format_full_cmd(&process.full_cmd);
337292
let first_cmd = &process.full_cmd[0];
338-
let cur_dir = if let Some(dir) = &process.cur_dir {
293+
let mut cmd = Command::new(&first_cmd[0]);
294+
if let Some(dir) = &process.cur_dir {
339295
full_cmd_str += &format!(" (cd: {})", dir);
340-
dir
341-
} else if let Some(env) = process.env {
342-
full_cmd_str += &format!(" (cd: {})", env.current_dir);
343-
&env.current_dir
344-
} else {
345-
"."
346-
};
296+
cmd.current_dir(dir);
297+
}
347298
info!("Running \"{}\" ...", full_cmd_str);
348-
let mut last_proc = Command::new(&first_cmd[0])
349-
.current_dir(cur_dir)
299+
300+
let mut last_proc = cmd
350301
.args(&first_cmd[1..])
351302
.stdout(if pipe_last || process.full_cmd.len() > 1 {
352303
Stdio::piped()
@@ -370,11 +321,39 @@ fn run_full_cmd(process: &mut Process, pipe_last: bool) -> Result<(Child, String
370321
Ok((last_proc, full_cmd_str))
371322
}
372323

373-
fn run_pipe_cmd(full_command: &str) -> CmdResult {
324+
fn run_pipe_cmd(full_command: &str, cd_opt: &mut Option<String>) -> CmdResult {
374325
let pipe_args = parse_pipes(full_command.trim());
375326
let pipe_argv = parse_argv(pipe_args);
376327

328+
let mut pipe_iter = pipe_argv[0].split_whitespace();
329+
let cmd = pipe_iter.next().unwrap();
330+
if cmd == "cd" || cmd == "lcd" {
331+
let dir = pipe_iter.next().unwrap().trim_matches('"');
332+
if pipe_iter.next() != None {
333+
let err = Error::new(ErrorKind::Other,
334+
format!("{} format wrong: {}", cmd, full_command));
335+
return Err(err);
336+
} else {
337+
if cmd == "cd" {
338+
info!("Set env current_dir: \"{}\"", dir);
339+
return std::env::set_current_dir(dir);
340+
} else {
341+
info!("Set local current_dir: \"{}\"", dir);
342+
*cd_opt = Some(dir.into());
343+
return Ok(());
344+
}
345+
}
346+
} else if cmd == "pwd" {
347+
let pwd = std::env::current_dir()?;
348+
info!("Running \"pwd\" ...");
349+
println!("{}", pwd.display());
350+
return Ok(());
351+
}
352+
377353
let mut last_proc = Process::new(pipe_argv[0].clone());
354+
if let Some(dir) = cd_opt {
355+
last_proc.current_dir(dir.clone());
356+
}
378357
for pipe_cmd in pipe_argv.iter().skip(1) {
379358
last_proc.pipe(pipe_cmd.clone());
380359
}
@@ -386,6 +365,13 @@ fn run_pipe_fun(full_command: &str) -> FunResult {
386365
let pipe_args = parse_pipes(full_command.trim());
387366
let pipe_argv = parse_argv(pipe_args);
388367

368+
let mut pipe_iter = pipe_argv[0].split_whitespace();
369+
let cmd = pipe_iter.next().unwrap();
370+
if cmd == "pwd" {
371+
let pwd = std::env::current_dir()?;
372+
return Ok(format!("{}", pwd.display()));
373+
}
374+
389375
let mut last_proc = Process::new(pipe_argv[0].clone());
390376
for pipe_cmd in pipe_argv.iter().skip(1) {
391377
last_proc.pipe(pipe_cmd.clone());
@@ -403,8 +389,9 @@ pub fn run_fun(cmds: &str) -> FunResult {
403389
pub fn run_cmd(cmds: &str) -> CmdResult {
404390
let cmd_args = parse_cmds(cmds);
405391
let cmd_argv = parse_argv(cmd_args);
392+
let mut cd_opt: Option<String> = None;
406393
for cmd in cmd_argv {
407-
if let Err(e) = run_pipe_cmd(&cmd) {
394+
if let Err(e) = run_pipe_cmd(&cmd, &mut cd_opt) {
408395
return Err(e);
409396
}
410397
}

0 commit comments

Comments
 (0)