1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # Rust shell - shell script written in rust.
//!
//! This is not an officially supported Google product
//!
//! Rust shell is a helper library for std::process::Command to write shell
//! script like tasks in rust. The library only works with unix-like operation
//! systems.
//!
//! ## Run command
//!
//! `run!` macro creates a ShellCommand instance which you can run by `run()`
//! method.
//!
//! ```
//! #[macro_use] extern crate shell;
//!
//! # fn main() {
//! // Run command by cmd! macro
//! cmd!("echo Hello rust shell!").run().unwrap();
//!
//! // Contain white space or non-alphabetical characters
//! cmd!("echo \"%$#\"").run().unwrap();
//!
//! // Pass an argument
//! let name = "shell";
//! cmd!("echo Hello rust {}!", name).run().unwrap();
//!
//! // Extract environment variable
//! cmd!("echo HOME is $HOME").run().unwrap();
//! # }
//! ```
//! ## ShellResult
//!
//! The return value of `ShellCommand#run()` is `ShellResult` which is `Ok(_)`
//! only when the command successfully runs and its execution code is 0, so you
//! can use `?` operator to check if the command successfully exits or not.
//!
//! ```
//! #[macro_use] extern crate shell;
//! use shell::ShellResult;
//!
//! # fn main() {
//! #   shell_function().unwrap();
//! # }
//! fn shell_function() -> ShellResult {
//!   cmd!("echo Command A").run()?;
//!   cmd!("echo Command B").run()?;
//!   shell::ok()
//! }
//! ```
//!
//! ## Output string
//!
//! ShellCommand has a shorthand to obtain stdout as UTF8 string.
//!
//! ```
//! #[macro_use] extern crate shell;
//!
//! # fn main() {
//! assert_eq!(cmd!("echo OK").stdout_utf8().unwrap(), "OK\n");
//! # }
//! ```
//!
//! ## Spawn
//!
//! ShellCommand has `spawn()` method which runs the command asynchronously and
//! returns `ShellChild`.
//!
//! ```
//! #[macro_use] extern crate shell;
//! extern crate libc;
//! use shell::ShellResultExt;
//!
//! # fn main() {
//! // Wait
//! let child = cmd!("sleep 2").spawn().unwrap();
//! child.wait().unwrap();
//!
//! // Signal
//! let child = cmd!("sleep 2").spawn().unwrap();
//! child.signal(libc::SIGINT);
//! let result = child.wait();
//! assert!(result.is_err(), "Should be error as it exits with a signal");
//! assert!(result.status().is_ok(), "Still able to obtain status");
//! # }
//! ```
//!
//! ## Thread
//!
//! If you would like to run a sequence of commands asynchronously,
//! `shell::spawn` creates a thread as well as `std::thread::spawn` but it
//! returns `ShellHandle` wrapping `std::thread::JoinHandle`.
//!
//! `ShellHandle#signal()` is used to send a signal to processes running on the
//! thread.  It also stops launching a new process by `ShellComamnd::run()` on
//! that thread.
//!
//! ```
//! #[macro_use] extern crate shell;
//! extern crate libc;
//! use shell::ShellResult;
//! use shell::ShellResultExt;
//!
//! # fn main() {
//! let handle = shell::spawn(|| -> ShellResult {
//!   cmd!("sleep 3").run()
//! });
//! handle.signal(libc::SIGINT);
//! let result = handle.join().unwrap();
//! assert!(result.is_err(), "Should be error as it exits with a signal");
//! assert!(result.status().is_ok(), "Still able to obtain status");
//! # }
//! ```
//!
//! ## Signal handling
//!
//! `trap_signal_and_wait_children()` starts watching SIGINT and SIGTERM, and
//! waits all child processes before exiting the process when receiving these
//! signals. The function needs to be called before launching any new thread.
//!
//! ```
//! extern crate shell;
//! shell::trap_signal_and_wait_children().unwrap();
//! ```
//!
//! ## Access underlaying objects
//!
//! `ShellComamnd` wraps `std::process::Command` and `ShellChild` wraps
//! `std::process::Child`. Both underlaying objects are accessible via public
//! fields.
//!
//! ```
//! #[macro_use] extern crate shell;
//! use std::process::Stdio;
//! use std::io::Read;
//!
//! # fn main() {
//! // Access std::process::Command.
//! let mut shell_command = cmd!("echo OK");
//! {
//!   let mut command = &mut shell_command.command;
//!   command.stdout(Stdio::piped());
//! }
//!
//! // Access std::process::Child.
//! let shell_child = shell_command.spawn().unwrap();
//! {
//!   let mut lock = shell_child.0.write().unwrap();
//!   let mut child = &mut lock.as_mut().unwrap().child;
//!   let mut str = String::new();
//!   child.stdout.as_mut().unwrap().read_to_string(&mut str);
//! }
//! shell_child.wait().unwrap();
//! # }
//! ```
//!
//! ## License
//! Apatch 2 License

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate log;
#[macro_use] extern crate nom;
extern crate errno;
extern crate libc;
extern crate regex;
extern crate env_logger;

#[macro_use] mod command;
mod shell_child;
mod shell_command;
mod process_manager;
mod local_shell;
mod result;

pub use command::new_command;
pub use local_shell::ShellHandle;
pub use local_shell::spawn;
pub use process_manager::trap_signal_and_wait_children;
pub use result::ShellError;
pub use result::ShellResult;
pub use result::ShellResultExt;
pub use result::ok;
pub use shell_child::ShellChild;
pub use shell_child::ShellChildArc;
pub use shell_child::ShellChildCore;
pub use shell_command::ShellCommand;