2022-12-17 12:02:15 -05:00
|
|
|
use crate::event::EventMessage;
|
2022-12-18 03:12:35 -05:00
|
|
|
use crate::CommandOptions;
|
2022-12-16 23:44:35 -05:00
|
|
|
use anyhow::bail;
|
|
|
|
use anyhow::Context;
|
|
|
|
use anyhow::Result;
|
2022-12-17 12:02:15 -05:00
|
|
|
use crossbeam::channel::Receiver;
|
|
|
|
use crossbeam::channel::Sender;
|
2022-12-18 03:12:35 -05:00
|
|
|
use parking_lot::RwLock;
|
|
|
|
use std::sync::Arc;
|
2022-12-15 23:19:17 -05:00
|
|
|
use std::{
|
|
|
|
io::Write,
|
|
|
|
process::{Command, Stdio},
|
|
|
|
};
|
|
|
|
|
2022-12-18 03:12:35 -05:00
|
|
|
pub type CommandRequest = (Arc<RwLock<CommandOptions>>, Arc<String>);
|
2022-12-15 23:19:17 -05:00
|
|
|
use crate::App;
|
|
|
|
|
2022-12-18 11:16:43 -05:00
|
|
|
#[derive(Debug)]
|
2022-12-18 03:12:35 -05:00
|
|
|
pub enum CommandCompleted {
|
|
|
|
Success(CommandResult),
|
|
|
|
Failure(Vec<u8>),
|
2022-12-17 12:02:15 -05:00
|
|
|
}
|
|
|
|
|
2022-12-18 11:16:43 -05:00
|
|
|
#[derive(Debug)]
|
2022-12-16 21:28:40 -05:00
|
|
|
pub struct CommandResult {
|
2022-12-15 23:19:17 -05:00
|
|
|
pub status_success: bool,
|
2022-12-16 21:28:40 -05:00
|
|
|
pub stdout: Vec<u8>,
|
|
|
|
pub stderr: Vec<u8>,
|
2022-12-15 23:19:17 -05:00
|
|
|
}
|
|
|
|
|
2022-12-16 21:28:40 -05:00
|
|
|
impl Default for CommandResult {
|
2022-12-15 23:19:17 -05:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
status_success: true,
|
2022-12-16 21:28:40 -05:00
|
|
|
stdout: vec![],
|
|
|
|
stderr: vec![],
|
2022-12-15 23:19:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-18 03:12:35 -05:00
|
|
|
pub fn command_event_loop(
|
|
|
|
command_request_receiver: Receiver<CommandRequest>,
|
|
|
|
event_sender: Sender<EventMessage>,
|
|
|
|
) -> Result<()> {
|
|
|
|
loop {
|
|
|
|
match command_request_receiver.recv() {
|
|
|
|
Ok(command_request) => {
|
|
|
|
event_sender.send(EventMessage::CommandCompleted(
|
|
|
|
match run_inner(command_request) {
|
|
|
|
Ok(c) => {
|
|
|
|
// If there was no stdout and the command failed, don't touch stdout
|
|
|
|
if !c.status_success && c.stdout.is_empty() {
|
|
|
|
CommandCompleted::Failure(c.stderr)
|
|
|
|
} else {
|
|
|
|
CommandCompleted::Success(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => CommandCompleted::Failure(e.to_string().as_bytes().to_vec()),
|
|
|
|
},
|
|
|
|
))?;
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
event_sender.send(EventMessage::CommandLoopStopped)?;
|
|
|
|
bail!("Crossterm read error: {}", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// pub fn run(app: Arc<App>) {
|
|
|
|
// match run_inner(app) {
|
|
|
|
// Ok(c) => {
|
|
|
|
// // If there was no stdout and the command failed, don't touch stdout
|
|
|
|
// if !c.status_success && c.stdout.is_empty() {
|
|
|
|
// app.command_result.stderr = c.stderr;
|
|
|
|
// app.command_result.status_success = c.status_success;
|
|
|
|
// } else {
|
|
|
|
// app.command_result = c;
|
2022-12-17 12:02:15 -05:00
|
|
|
// }
|
|
|
|
// }
|
2022-12-18 03:12:35 -05:00
|
|
|
// Err(e) => {
|
|
|
|
// app.command_result.status_success = false;
|
|
|
|
// app.command_result.stderr = e.to_string().as_bytes().to_vec();
|
|
|
|
// }
|
2022-12-17 12:02:15 -05:00
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
2022-12-18 03:12:35 -05:00
|
|
|
fn run_inner(command_request: CommandRequest) -> Result<CommandResult> {
|
2022-12-18 11:16:43 -05:00
|
|
|
// Spawn the child
|
|
|
|
let mut child = {
|
|
|
|
let request = command_request.0.read();
|
2022-12-16 20:41:16 -05:00
|
|
|
|
2022-12-18 11:16:43 -05:00
|
|
|
let mut command = Command::new(&request.command);
|
|
|
|
command
|
|
|
|
.stdin(Stdio::piped())
|
|
|
|
.stdout(Stdio::piped())
|
|
|
|
.stderr(Stdio::piped())
|
|
|
|
.args(&request.hidden_options);
|
2022-12-17 11:25:15 -05:00
|
|
|
|
2022-12-18 11:16:43 -05:00
|
|
|
if request.wordsplit {
|
|
|
|
match shellwords::split(&request.cmdline) {
|
|
|
|
Ok(a) => {
|
|
|
|
command.args(a);
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
bail!("Argument error: {e:?}");
|
|
|
|
}
|
2022-12-17 11:25:15 -05:00
|
|
|
}
|
2022-12-18 11:16:43 -05:00
|
|
|
} else {
|
|
|
|
// TODO: Avoid cloning here
|
|
|
|
command.arg(&request.cmdline);
|
2022-12-17 11:25:15 -05:00
|
|
|
}
|
2022-12-18 11:16:43 -05:00
|
|
|
|
|
|
|
std::mem::drop(request);
|
|
|
|
|
|
|
|
command.spawn()
|
|
|
|
}?;
|
2022-12-15 23:19:17 -05:00
|
|
|
|
2022-12-16 23:44:35 -05:00
|
|
|
let mut stdin = child.stdin.take().context("Could not take stdin")?;
|
2022-12-18 03:12:35 -05:00
|
|
|
let text_orig_clone = command_request.1.clone();
|
2022-12-15 23:19:17 -05:00
|
|
|
std::thread::spawn(move || {
|
2022-12-17 00:10:17 -05:00
|
|
|
let _result = stdin.write_all(text_orig_clone.as_bytes());
|
2022-12-15 23:19:17 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
// Collect the output
|
2022-12-18 03:12:35 -05:00
|
|
|
let output = child.wait_with_output()?;
|
2022-12-15 23:19:17 -05:00
|
|
|
|
2022-12-16 23:44:35 -05:00
|
|
|
Ok(CommandResult {
|
2022-12-15 23:19:17 -05:00
|
|
|
status_success: output.status.success(),
|
2022-12-16 21:28:40 -05:00
|
|
|
stdout: output.stdout,
|
|
|
|
stderr: output.stderr,
|
2022-12-16 23:44:35 -05:00
|
|
|
})
|
2022-12-15 23:19:17 -05:00
|
|
|
}
|