Skip to content

Commit

Permalink
handle signals and SIGPIPE like other unix utils
Browse files Browse the repository at this point in the history
"No exit code" means a signal was delivered. Also don't exit
with 0 anymore if input processing was interrupted (BrokenPipe).
  • Loading branch information
th1000s committed Dec 9, 2024
1 parent fc8d83e commit 0cddfdb
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 27 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ git2 = { version = "0.18.2", default-features = false, features = [] }
grep-cli = "0.1.8"
itertools = "0.10.5"
lazy_static = "1.4"
libc = "*"
palette = "0.7.2"
pathdiff = "0.2.1"
regex = "1.7.1"
Expand Down
75 changes: 48 additions & 27 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,14 @@ pub fn run_app(
let res = delta(io::stdin().lock().byte_lines(), &mut writer, &config);

if let Err(error) = res {
match error.kind() {
ErrorKind::BrokenPipe => return Ok(0),
_ => {
eprintln!("{error}");
return Ok(config.error_exit_code);
}
if error.kind() == ErrorKind::BrokenPipe {
// Not the entire input was processed, so we should not return 0.
// Other unix utils with a default SIGPIPE handler would have their exit code
// set to this code by the shell, emulate it:
return Ok(128 + libc::SIGPIPE);
} else {
eprintln!("{error}");
return Ok(config.error_exit_code);
}
}

Expand Down Expand Up @@ -246,25 +248,45 @@ pub fn run_app(

if let Err(error) = res {
let _ = cmd.wait(); // for clippy::zombie_processes
match error.kind() {
ErrorKind::BrokenPipe => return Ok(0),
_ => {
eprintln!("{error}");
return Ok(config.error_exit_code);
}
if error.kind() == ErrorKind::BrokenPipe {
// (see non-subcommand block above)
return Ok(128 + libc::SIGPIPE);
} else {
eprintln!("{error}");
return Ok(config.error_exit_code);
}
};

let subcmd_status = cmd
.wait()
.unwrap_or_else(|_| {
delta_unreachable(&format!("{subcmd_kind:?} process not running."));
})
.code()
.unwrap_or_else(|| {
eprintln!("delta: {subcmd_kind:?} process terminated without exit status.");
config.error_exit_code
});
let subcmd_status = cmd.wait().unwrap_or_else(|_| {
delta_unreachable(&format!("{subcmd_kind} process not running."));
});

let subcmd_code = subcmd_status.code().unwrap_or_else(|| {
#[cfg(unix)]
{
// On unix no exit status usually means the process was terminated
// by a signal (not using MT-unsafe `libc::strsignal` to get its name).
use std::os::unix::process::ExitStatusExt;

if let Some(signal) = subcmd_status.signal() {
// (note that by default the rust runtime blocks SIGPIPE)
if signal != libc::SIGPIPE {
eprintln!(
"delta: {subcmd_kind:?} received signal {signal}{}",
if subcmd_status.core_dumped() {
" (core dumped)"
} else {
""
}
);
}
// unix convention: 128 + signal
return 128 + signal;
}
}
eprintln!("delta: {subcmd_kind:?} process terminated without exit status.");
config.error_exit_code
});

let mut stderr_lines = io::BufReader::new(
cmd.stderr
Expand All @@ -282,8 +304,7 @@ pub fn run_app(

// On `git diff` unknown option error: stop after printing the first line above (which is
// an error message), because the entire --help text follows.
if !(subcmd_status == 129
&& matches!(subcmd_kind, SubCmdKind::GitDiff | SubCmdKind::Git(_)))
if !(subcmd_code == 129 && matches!(subcmd_kind, SubCmdKind::GitDiff | SubCmdKind::Git(_)))
{
for line in stderr_lines {
eprintln!(
Expand All @@ -293,9 +314,9 @@ pub fn run_app(
}
}

if matches!(subcmd_kind, SubCmdKind::GitDiff | SubCmdKind::Diff) && subcmd_status >= 2 {
if matches!(subcmd_kind, SubCmdKind::GitDiff | SubCmdKind::Diff) && subcmd_code >= 2 {
eprintln!(
"{subcmd_kind:?} process failed with exit status {subcmd_status}. Command was: {}",
"delta: {subcmd_kind:?} process failed with exit status {subcmd_code}. Command was: {}",
format_args!(
"{} {}",
subcmd_bin_path.display(),
Expand All @@ -308,7 +329,7 @@ pub fn run_app(
);
}

Ok(subcmd_status)
Ok(subcmd_code)
}

// `output_type` drop impl runs here
Expand Down

0 comments on commit 0cddfdb

Please sign in to comment.