|
|
@ -1,11 +1,13 @@ |
|
|
|
use std::io::ErrorKind::NotFound;
|
|
|
|
use std::process::Command;
|
|
|
|
use crossbeam_channel::{select, Receiver};
|
|
|
|
use std::io::ErrorKind;
|
|
|
|
use std::process::{Command, ExitStatus};
|
|
|
|
use std::{io, thread};
|
|
|
|
|
|
|
|
use crate::builtins::{execute_builtin, is_builtin};
|
|
|
|
use crate::error::ShellError;
|
|
|
|
use crate::parse::parse_line;
|
|
|
|
|
|
|
|
pub fn interpret(line: String) -> Result<(), ShellError> {
|
|
|
|
pub fn interpret(line: String, ctrlc_recv: Receiver<()>) -> Result<(), ShellError> {
|
|
|
|
if line.is_empty() {
|
|
|
|
return Err(ShellError::EmptyLine);
|
|
|
|
}
|
|
|
@ -17,25 +19,33 @@ pub fn interpret(line: String) -> Result<(), ShellError> { |
|
|
|
let mut command = Command::new(keyword);
|
|
|
|
command.args(args);
|
|
|
|
|
|
|
|
execute(command)?;
|
|
|
|
execute(command, ctrlc_recv)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute(mut command: Command) -> Result<(), ShellError> {
|
|
|
|
fn execute(mut command: Command, ctrlc_recv: Receiver<()>) -> Result<(), ShellError> {
|
|
|
|
match command.spawn() {
|
|
|
|
Ok(mut child) => {
|
|
|
|
if let Err(err) = child.wait() {
|
|
|
|
return Err(ShellError::ExecuteFailure(err.to_string()));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
if err.kind() == NotFound {
|
|
|
|
return Err(ShellError::NotFound(command));
|
|
|
|
let (cmd_send, cmd_recv) = crossbeam_channel::unbounded::<io::Result<ExitStatus>>();
|
|
|
|
thread::spawn(move || cmd_send.send(child.wait()));
|
|
|
|
|
|
|
|
select! {
|
|
|
|
recv(ctrlc_recv) -> _ => Err(ShellError::Interrupt),
|
|
|
|
recv(cmd_recv) -> result => {
|
|
|
|
if let Err(err) = result.unwrap() {
|
|
|
|
Err(ShellError::ExecuteFailure(err.to_string()))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(ShellError::ExecuteFailure(err.to_string()))
|
|
|
|
}
|
|
|
|
Err(err) => match err.kind() {
|
|
|
|
ErrorKind::NotFound => Err(ShellError::NotFound(command)),
|
|
|
|
ErrorKind::Interrupted => Err(ShellError::Interrupt),
|
|
|
|
_ => Err(ShellError::ExecuteFailure(err.to_string())),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|