2017-11-15 01:56:32 +01:00
|
|
|
use std::io;
|
2017-12-09 02:46:08 +01:00
|
|
|
use std::io::Write;
|
2018-11-11 18:00:01 +01:00
|
|
|
use std::sync::Mutex;
|
2017-11-15 01:56:32 +01:00
|
|
|
|
2022-05-12 16:41:47 +02:00
|
|
|
use argmax::Command;
|
|
|
|
|
2020-04-03 21:18:54 +02:00
|
|
|
use crate::error::print_error;
|
2019-09-13 22:26:27 +02:00
|
|
|
use crate::exit_codes::ExitCode;
|
|
|
|
|
2022-02-28 08:39:52 +01:00
|
|
|
struct Outputs {
|
|
|
|
stdout: Vec<u8>,
|
|
|
|
stderr: Vec<u8>,
|
|
|
|
}
|
2022-03-07 07:41:03 +01:00
|
|
|
struct OutputBuffer<'a> {
|
|
|
|
output_permission: &'a Mutex<()>,
|
2022-02-28 08:39:52 +01:00
|
|
|
outputs: Vec<Outputs>,
|
|
|
|
}
|
|
|
|
|
2022-03-07 07:41:03 +01:00
|
|
|
impl<'a> OutputBuffer<'a> {
|
|
|
|
fn new(output_permission: &'a Mutex<()>) -> Self {
|
2022-02-28 08:39:52 +01:00
|
|
|
Self {
|
2022-03-07 07:41:03 +01:00
|
|
|
output_permission,
|
2022-02-28 08:39:52 +01:00
|
|
|
outputs: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push(&mut self, stdout: Vec<u8>, stderr: Vec<u8>) {
|
|
|
|
self.outputs.push(Outputs { stdout, stderr });
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write(self) {
|
|
|
|
// avoid taking the lock if there is nothing to do
|
|
|
|
if self.outputs.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// While this lock is active, this thread will be the only thread allowed
|
|
|
|
// to write its outputs.
|
2022-03-07 07:41:03 +01:00
|
|
|
let _lock = self.output_permission.lock().unwrap();
|
2022-02-28 08:39:52 +01:00
|
|
|
|
|
|
|
let stdout = io::stdout();
|
|
|
|
let stderr = io::stderr();
|
|
|
|
|
|
|
|
let mut stdout = stdout.lock();
|
|
|
|
let mut stderr = stderr.lock();
|
|
|
|
|
|
|
|
for output in self.outputs.iter() {
|
|
|
|
let _ = stdout.write_all(&output.stdout);
|
|
|
|
let _ = stderr.write_all(&output.stderr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-15 01:56:32 +01:00
|
|
|
/// Executes a command.
|
2022-05-12 16:41:47 +02:00
|
|
|
pub fn execute_commands<I: Iterator<Item = io::Result<Command>>>(
|
2022-02-28 08:39:52 +01:00
|
|
|
cmds: I,
|
2021-08-09 09:02:30 +02:00
|
|
|
out_perm: &Mutex<()>,
|
|
|
|
enable_output_buffering: bool,
|
|
|
|
) -> ExitCode {
|
2022-03-07 07:41:03 +01:00
|
|
|
let mut output_buffer = OutputBuffer::new(out_perm);
|
2022-05-12 16:41:47 +02:00
|
|
|
for result in cmds {
|
|
|
|
let mut cmd = match result {
|
|
|
|
Ok(cmd) => cmd,
|
|
|
|
Err(e) => return handle_cmd_error(None, e),
|
|
|
|
};
|
|
|
|
|
2022-02-28 08:39:52 +01:00
|
|
|
// Spawn the supplied command.
|
|
|
|
let output = if enable_output_buffering {
|
|
|
|
cmd.output()
|
|
|
|
} else {
|
|
|
|
// If running on only one thread, don't buffer output
|
|
|
|
// Allows for viewing and interacting with intermediate command output
|
|
|
|
cmd.spawn().and_then(|c| c.wait_with_output())
|
|
|
|
};
|
|
|
|
|
|
|
|
// Then wait for the command to exit, if it was spawned.
|
|
|
|
match output {
|
|
|
|
Ok(output) => {
|
|
|
|
if enable_output_buffering {
|
2022-03-07 07:41:03 +01:00
|
|
|
output_buffer.push(output.stdout, output.stderr);
|
2022-02-28 08:39:52 +01:00
|
|
|
}
|
|
|
|
if output.status.code() != Some(0) {
|
2022-03-07 07:41:03 +01:00
|
|
|
output_buffer.write();
|
2022-02-28 08:39:52 +01:00
|
|
|
return ExitCode::GeneralError;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(why) => {
|
2022-03-07 07:41:03 +01:00
|
|
|
output_buffer.write();
|
2022-05-12 16:41:47 +02:00
|
|
|
return handle_cmd_error(Some(&cmd), why);
|
2019-09-13 22:26:27 +02:00
|
|
|
}
|
2017-11-15 01:56:32 +01:00
|
|
|
}
|
2022-02-28 08:39:52 +01:00
|
|
|
}
|
2022-03-07 07:41:03 +01:00
|
|
|
output_buffer.write();
|
2022-02-28 08:39:52 +01:00
|
|
|
ExitCode::Success
|
|
|
|
}
|
|
|
|
|
2022-05-12 16:41:47 +02:00
|
|
|
pub fn handle_cmd_error(cmd: Option<&Command>, err: io::Error) -> ExitCode {
|
|
|
|
match (cmd, err) {
|
|
|
|
(Some(cmd), err) if err.kind() == io::ErrorKind::NotFound => {
|
2022-09-11 20:39:04 +02:00
|
|
|
print_error(format!(
|
|
|
|
"Command not found: {}",
|
|
|
|
cmd.get_program().to_string_lossy()
|
|
|
|
));
|
2022-05-12 16:41:47 +02:00
|
|
|
ExitCode::GeneralError
|
|
|
|
}
|
|
|
|
(_, err) => {
|
|
|
|
print_error(format!("Problem while executing command: {}", err));
|
|
|
|
ExitCode::GeneralError
|
|
|
|
}
|
2020-06-23 17:29:04 +02:00
|
|
|
}
|
2017-11-15 01:56:32 +01:00
|
|
|
}
|