mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 05:12:40 +03:00
pty: ExitStatus now understands signals and impl Display
Improves the fidelity of the information in ExitStatus and shows it in the wezterm exit_behavior output to clarify the status.
This commit is contained in:
parent
317bfeef41
commit
0f6ee20b28
@ -164,8 +164,9 @@ impl Pane for LocalPane {
|
|||||||
(ExitBehavior::Close, _, _) => *proc = ProcessState::Dead,
|
(ExitBehavior::Close, _, _) => *proc = ProcessState::Dead,
|
||||||
(ExitBehavior::CloseOnCleanExit, false, false) => {
|
(ExitBehavior::CloseOnCleanExit, false, false) => {
|
||||||
notify = Some(format!(
|
notify = Some(format!(
|
||||||
"\r\n⚠️ Process {} didn't exit cleanly.\r\n{}=\"CloseOnCleanExit\"\r\n",
|
"\r\n⚠️ Process {} didn't exit cleanly\r\n{}.\r\n{}=\"CloseOnCleanExit\"\r\n",
|
||||||
self.command_description,
|
self.command_description,
|
||||||
|
status,
|
||||||
EXIT_BEHAVIOR
|
EXIT_BEHAVIOR
|
||||||
));
|
));
|
||||||
*proc = ProcessState::DeadPendingClose { killed: false }
|
*proc = ProcessState::DeadPendingClose { killed: false }
|
||||||
@ -179,8 +180,10 @@ impl Pane for LocalPane {
|
|||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
notify = Some(format!(
|
notify = Some(format!(
|
||||||
"\r\n⚠️ Process {} didn't exit cleanly.\r\n{}=\"Hold\"\r\n",
|
"\r\n⚠️ Process {} didn't exit cleanly\r\n{}.\r\n{}=\"Hold\"\r\n",
|
||||||
self.command_description, EXIT_BEHAVIOR
|
self.command_description,
|
||||||
|
status,
|
||||||
|
EXIT_BEHAVIOR
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
*proc = ProcessState::DeadPendingClose { killed: false }
|
*proc = ProcessState::DeadPendingClose { killed: false }
|
||||||
|
@ -154,30 +154,76 @@ pub trait SlavePty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the exit status of a child process.
|
/// Represents the exit status of a child process.
|
||||||
/// This is rather anemic in the current version of this crate,
|
|
||||||
/// holding only an indicator of success or failure.
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ExitStatus {
|
pub struct ExitStatus {
|
||||||
successful: bool,
|
code: u32,
|
||||||
|
signal: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExitStatus {
|
impl ExitStatus {
|
||||||
/// Construct an ExitStatus from a process return code
|
/// Construct an ExitStatus from a process return code
|
||||||
pub fn with_exit_code(code: u32) -> Self {
|
pub fn with_exit_code(code: u32) -> Self {
|
||||||
|
Self { code, signal: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct an ExitStatus from a signal name
|
||||||
|
pub fn with_signal(signal: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
successful: code == 0,
|
code: 1,
|
||||||
|
signal: Some(signal.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the status indicates successful completion
|
||||||
pub fn success(&self) -> bool {
|
pub fn success(&self) -> bool {
|
||||||
self.successful
|
match self.signal {
|
||||||
|
None => self.code == 0,
|
||||||
|
Some(_) => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::process::ExitStatus> for ExitStatus {
|
impl From<std::process::ExitStatus> for ExitStatus {
|
||||||
fn from(status: std::process::ExitStatus) -> ExitStatus {
|
fn from(status: std::process::ExitStatus) -> ExitStatus {
|
||||||
ExitStatus {
|
#[cfg(unix)]
|
||||||
successful: status.success(),
|
{
|
||||||
|
use std::os::unix::process::ExitStatusExt;
|
||||||
|
|
||||||
|
if let Some(signal) = status.signal() {
|
||||||
|
let signame = unsafe { libc::strsignal(signal) };
|
||||||
|
let signal = if signame.is_null() {
|
||||||
|
format!("Signal {}", signal)
|
||||||
|
} else {
|
||||||
|
let signame = unsafe { std::ffi::CStr::from_ptr(signame) };
|
||||||
|
signame.to_string_lossy().to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
return ExitStatus {
|
||||||
|
code: status.code().map(|c| c as u32).unwrap_or(1),
|
||||||
|
signal: Some(signal),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let code =
|
||||||
|
status
|
||||||
|
.code()
|
||||||
|
.map(|c| c as u32)
|
||||||
|
.unwrap_or_else(|| if status.success() { 0 } else { 1 });
|
||||||
|
|
||||||
|
ExitStatus { code, signal: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ExitStatus {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
if self.success() {
|
||||||
|
write!(fmt, "Success")
|
||||||
|
} else {
|
||||||
|
match &self.signal {
|
||||||
|
Some(sig) => write!(fmt, "Terminated by {}", sig),
|
||||||
|
None => write!(fmt, "Exited with code {}", self.code),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,10 @@ impl ChannelWrap {
|
|||||||
#[cfg(feature = "ssh2")]
|
#[cfg(feature = "ssh2")]
|
||||||
Self::Ssh2(chan) => {
|
Self::Ssh2(chan) => {
|
||||||
if chan.eof() && chan.wait_close().is_ok() {
|
if chan.eof() && chan.wait_close().is_ok() {
|
||||||
if let Some(_sig) = has_signal(chan) {
|
if let Some(sig) = has_signal(chan) {
|
||||||
Some(ExitStatus::with_exit_code(1))
|
Some(ExitStatus::with_signal(
|
||||||
|
sig.exit_signal.as_deref().unwrap_or("Unknown signal"),
|
||||||
|
))
|
||||||
} else if let Ok(status) = chan.exit_status() {
|
} else if let Ok(status) = chan.exit_status() {
|
||||||
Some(ExitStatus::with_exit_code(status as _))
|
Some(ExitStatus::with_exit_code(status as _))
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user