PageRenderTime 50ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/parse/linked_command/mod.rs

https://gitlab.com/zachdaniel/rush
Rust | 335 lines | 296 code | 38 blank | 1 comment | 64 complexity | a4433786e24c552552f7653e3b706c8f MD5 | raw file
  1. use std::process::{Command, Stdio, Child, ExitStatus, exit};
  2. use std::path::PathBuf;
  3. use std::fs::File;
  4. use std::error;
  5. use std::io::{Error, copy, ErrorKind};
  6. use std::fmt;
  7. use std::env;
  8. use std::ffi::OsString;
  9. use std::thread;
  10. use std::collections::HashMap;
  11. use std::error::Error as stdError;
  12. use BINDINGS;
  13. use ALIAS;
  14. #[derive(Debug)]
  15. pub struct LinkedCommand {
  16. pub command: Spawn,
  17. pub piped_to: Option<Box<LinkedCommand>>,
  18. pub and: Option<Box<LinkedCommand>>,
  19. pub file_out: Option<PathBuf>,
  20. pub file_in: Option<PathBuf>,
  21. }
  22. impl LinkedCommand {
  23. pub fn new(name: String) -> LinkedCommand {
  24. if let Some(builtin) = BuiltIn::find(name.clone()) {
  25. LinkedCommand {
  26. command: Spawn::BuiltIn(builtin),
  27. piped_to: None,
  28. and: None,
  29. file_out: None,
  30. file_in: None,
  31. }
  32. } else {
  33. LinkedCommand {
  34. command: Spawn::Com(Command::new(name)),
  35. piped_to: None,
  36. and: None,
  37. file_out: None,
  38. file_in: None,
  39. }
  40. }
  41. }
  42. fn piped_input(&mut self) {
  43. match self.command {
  44. Spawn::BuiltIn(_) => (),
  45. Spawn::Com(ref mut command) => {
  46. command.stdin(Stdio::piped());
  47. }
  48. }
  49. }
  50. fn execute(mut self) -> Result<Spawned, Error> {
  51. match self.command {
  52. Spawn::BuiltIn(mut builtin) => {
  53. if let Some(ref mut next) = self.piped_to {
  54. next.piped_input();
  55. }
  56. let output = try!(builtin.spawn());
  57. if let Some(next) = self.piped_to {
  58. let next_command = try!(next.execute());
  59. if let Spawned::Com(mut next_child) = next_command {
  60. let mut stdin = next_child.stdin.take().unwrap();
  61. thread::spawn(move || copy(&mut output.as_bytes(), &mut stdin));
  62. }
  63. } else if let Some(ref mut file_out) = self.file_out {
  64. let mut file = try!(File::create(file_out));
  65. thread::spawn(move || copy(&mut output.as_bytes(), &mut file));
  66. }
  67. Ok(Spawned::BuiltIn(builtin))
  68. }
  69. Spawn::Com(ref mut command) => {
  70. if let Some(ref mut next) = self.piped_to {
  71. next.piped_input();
  72. command.stdout(Stdio::piped());
  73. } else if let Some(_) = self.file_out {
  74. command.stdout(Stdio::piped());
  75. }
  76. if self.file_in.is_some() {
  77. command.stdin(Stdio::piped());
  78. }
  79. let mut child = try!(command.spawn());
  80. if let Some(ref file_in) = self.file_in {
  81. let mut file = try!(File::create(file_in));
  82. let mut stdin = child.stdin.take().unwrap();
  83. thread::spawn(move || copy(&mut file, &mut stdin));
  84. }
  85. if let Some(next) = self.piped_to {
  86. let mut next_command = try!(next.execute());
  87. if let Spawned::Com(ref mut next_child) = next_command {
  88. let stdout = child.stdout.take();
  89. let stdin = next_child.stdin.take();
  90. if stdout.is_some() {
  91. if stdin.is_some() {
  92. thread::spawn(move || {
  93. copy(&mut stdout.unwrap(), &mut stdin.unwrap())
  94. });
  95. } else {
  96. panic!();
  97. }
  98. } else {
  99. panic!();
  100. }
  101. }
  102. } else if let Some(ref mut file_out) = self.file_out {
  103. let mut file = try!(File::create(file_out));
  104. try!(copy(child.stdout.as_mut().unwrap(), &mut file));
  105. }
  106. if let Some(and) = self.and {
  107. try!(and.execute());
  108. }
  109. Ok(Spawned::Com(child))
  110. }
  111. }
  112. }
  113. pub fn spawn(self) -> Result<ExStatus, Error> {
  114. try!(self.execute()).wait()
  115. }
  116. pub fn arg(&mut self, arg: String) {
  117. self.command.arg(arg);
  118. }
  119. }
  120. #[derive(Debug)]
  121. pub struct BuiltIn {
  122. name: String,
  123. args: Vec<String>,
  124. output: String,
  125. exit_status: ExStatus,
  126. env: HashMap<String, String>,
  127. }
  128. #[derive(Debug)]
  129. pub enum Spawn {
  130. Com(Command),
  131. BuiltIn(BuiltIn),
  132. }
  133. pub enum Spawned {
  134. Com(Child),
  135. BuiltIn(BuiltIn),
  136. }
  137. impl Spawned {
  138. fn wait(self) -> Result<ExStatus, Error> {
  139. match self {
  140. Spawned::Com(mut child) => Ok(ExStatus::from(try!(child.wait()))),
  141. Spawned::BuiltIn(builtin) => Ok(builtin.exit_status),
  142. }
  143. }
  144. }
  145. #[derive(Debug)]
  146. pub struct ExStatus {
  147. code: Option<i32>,
  148. exit_status: Option<ExitStatus>,
  149. }
  150. impl From<ExitStatus> for ExStatus {
  151. fn from(exit_status: ExitStatus) -> ExStatus {
  152. ExStatus {
  153. code: None,
  154. exit_status: Some(exit_status),
  155. }
  156. }
  157. }
  158. impl ExStatus {
  159. fn new(code: i32) -> ExStatus {
  160. ExStatus {
  161. code: Some(code),
  162. exit_status: None,
  163. }
  164. }
  165. }
  166. impl Spawn {
  167. fn arg(&mut self, arg: String) {
  168. match *self {
  169. Spawn::Com(ref mut command) => {
  170. command.arg(arg);
  171. }
  172. Spawn::BuiltIn(ref mut builtin) => {
  173. builtin.arg(arg);
  174. }
  175. }
  176. }
  177. }
  178. impl BuiltIn {
  179. pub fn find(name: String) -> Option<BuiltIn> {
  180. if Self::is_built_in(name.clone()) {
  181. Some(BuiltIn {
  182. name: name,
  183. args: vec![],
  184. output: String::new(),
  185. exit_status: ExStatus::new(1),
  186. env: HashMap::new(),
  187. })
  188. } else {
  189. None
  190. }
  191. }
  192. fn is_built_in(name: String) -> bool {
  193. &name == "exit" || &name == "cd" || &name == "export" || &name == "alias"
  194. }
  195. fn spawn(&mut self) -> Result<String, Error> {
  196. if &self.name == "exit" {
  197. self.exit()
  198. } else if &self.name == "cd" {
  199. self.cd()
  200. } else if &self.name == "export" {
  201. self.export()
  202. } else if &self.name == "alias" {
  203. self.alias()
  204. } else {
  205. Err(Error::from(BuiltInError::NoSuchBuiltIn(self.name.clone())))
  206. }
  207. }
  208. fn arg(&mut self, arg: String) {
  209. self.args.push(arg);
  210. }
  211. // builtins
  212. fn exit(&self) -> Result<String, Error> {
  213. exit(0);
  214. }
  215. fn cd(&self) -> Result<String, Error> {
  216. let current = try!(env::current_dir());
  217. if self.args.is_empty() {
  218. Err(Error::from(BuiltInError::NoArgument(String::from("cd"))))
  219. } else {
  220. let path = PathBuf::from(self.args[0].clone());
  221. let dest = current.join(path);
  222. try!(env::set_current_dir(dest));
  223. let new_dir = try!(env::current_dir());
  224. match new_dir.into_os_string().into_string() {
  225. Ok(string) => Ok(string),
  226. Err(os_string) => Err(Error::from(BuiltInError::InvalidUnicode(os_string))),
  227. }
  228. }
  229. }
  230. fn alias(&self) -> Result<String, Error> {
  231. if self.args[0] == "list".to_string() {
  232. let mut response = String::new();
  233. for (name, value) in ALIAS.lock().unwrap().iter() {
  234. response.push_str(&format!("{:?}: {:?}\n", name, value));
  235. }
  236. println!("{}", response);
  237. Ok(response)
  238. } else if self.args.len() < 2 {
  239. Err(Error::from(BuiltInError::NoArgument(String::from("alias"))))
  240. } else {
  241. let mut alias = ALIAS.lock().unwrap();
  242. alias.insert(self.args[0].clone(), self.args[1].clone());
  243. println!("{}: {}", self.args[0].clone(), self.args[1].clone());
  244. Ok(self.args[1].clone())
  245. }
  246. }
  247. fn export(&mut self) -> Result<String, Error> {
  248. let arg = self.args.clone();
  249. let mut args = arg.iter();
  250. loop {
  251. if let Some(name) = args.next() {
  252. if name.ends_with("=") {
  253. let mut sane_name = name.clone();
  254. sane_name.pop();
  255. if let Some(val) = args.next() {
  256. env::set_var(sane_name, val);
  257. } else {
  258. env::set_var(sane_name, String::new());
  259. break;
  260. }
  261. } else {
  262. let val =
  263. BINDINGS.lock().unwrap().get(name).unwrap_or(&String::from("")).clone();
  264. env::set_var(name, val);
  265. }
  266. } else {
  267. break;
  268. }
  269. }
  270. Ok(String::new())
  271. }
  272. }
  273. #[derive(Debug)]
  274. pub enum BuiltInError {
  275. NoSuchBuiltIn(String),
  276. NoArgument(String),
  277. InvalidUnicode(OsString),
  278. }
  279. impl error::Error for BuiltInError {
  280. fn description(&self) -> &str {
  281. match *self {
  282. BuiltInError::NoSuchBuiltIn(_) => "Attempted to parse a builtin, but no such builtin",
  283. BuiltInError::NoArgument(_) => "Expected argument, but got none",
  284. BuiltInError::InvalidUnicode(_) => "Invalid Unicode",
  285. }
  286. }
  287. }
  288. impl fmt::Display for BuiltInError {
  289. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  290. write!(f, "{}", self.description())
  291. }
  292. }
  293. impl From<BuiltInError> for Error {
  294. fn from(err: BuiltInError) -> Error {
  295. Error::new(ErrorKind::Other, err)
  296. }
  297. }