#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
use std::{
process::ExitStatus,
str,
time::Duration,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CommandOutput {
status: ExitStatus,
stdout: Vec<u8>,
stderr: Vec<u8>,
stdout_truncated: bool,
stderr_truncated: bool,
elapsed: Duration,
stdout_text: Option<String>,
stderr_text: Option<String>,
}
impl CommandOutput {
#[inline]
pub(crate) fn new(
status: ExitStatus,
stdout: Vec<u8>,
stderr: Vec<u8>,
stdout_truncated: bool,
stderr_truncated: bool,
elapsed: Duration,
lossy_output: bool,
) -> Self {
let stdout_text = if lossy_output {
Some(String::from_utf8_lossy(&stdout).into_owned())
} else {
None
};
let stderr_text = if lossy_output {
Some(String::from_utf8_lossy(&stderr).into_owned())
} else {
None
};
Self {
status,
stdout,
stderr,
stdout_truncated,
stderr_truncated,
elapsed,
stdout_text,
stderr_text,
}
}
#[inline]
pub fn exit_code(&self) -> Option<i32> {
self.status.code()
}
#[inline]
pub const fn exit_status(&self) -> &ExitStatus {
&self.status
}
#[cfg(unix)]
#[inline]
pub fn termination_signal(&self) -> Option<i32> {
self.status.signal()
}
#[inline]
pub fn stdout(&self) -> Result<&str, str::Utf8Error> {
match &self.stdout_text {
Some(text) => Ok(text.as_str()),
None => str::from_utf8(&self.stdout),
}
}
#[inline]
pub fn stderr(&self) -> Result<&str, str::Utf8Error> {
match &self.stderr_text {
Some(text) => Ok(text.as_str()),
None => str::from_utf8(&self.stderr),
}
}
#[inline]
pub const fn elapsed(&self) -> Duration {
self.elapsed
}
#[inline]
pub fn stdout_bytes(&self) -> &[u8] {
&self.stdout
}
#[inline]
pub fn stderr_bytes(&self) -> &[u8] {
&self.stderr
}
#[inline]
pub const fn stdout_truncated(&self) -> bool {
self.stdout_truncated
}
#[inline]
pub const fn stderr_truncated(&self) -> bool {
self.stderr_truncated
}
}