fix: handle broken pipe errors gracefully

When a broken pipe error occurs, we want to exit gracefully with a
success exit code. This matches existing Unix convention.
This commit is contained in:
Wenxuan Zhang 2024-12-28 23:34:07 +08:00
parent 2770e0259c
commit 79819fcae8
No known key found for this signature in database
GPG key ID: CCAF35548C65530F
2 changed files with 33 additions and 4 deletions

View file

@ -2,10 +2,37 @@ yazi_macro::mod_pub!(package);
yazi_macro::mod_flat!(args);
use std::process::ExitCode;
use clap::Parser;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
async fn main() -> ExitCode {
match run().await {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
// Look for a broken pipe error. In this case, we generally want
// to exit "gracefully" with a success exit code. This matches
// existing Unix convention. We need to handle this explicitly
// since the Rust runtime doesn't ask for PIPE signals, and thus
// we get an I/O error instead. Traditional C Unix applications
// quit by getting a PIPE signal that they don't handle, and thus
// the unhandled signal causes the process to unceremoniously
// terminate.
for cause in err.chain() {
if let Some(ioerr) = cause.downcast_ref::<std::io::Error>() {
if ioerr.kind() == std::io::ErrorKind::BrokenPipe {
return ExitCode::from(0);
}
}
}
eprintln!("{:#}", err);
ExitCode::FAILURE
}
}
}
async fn run() -> anyhow::Result<()> {
yazi_shared::init();
yazi_fs::init();

View file

@ -1,3 +1,5 @@
use std::io::{self, Write};
use anyhow::{Context, Result, bail};
use tokio::fs;
use toml_edit::{Array, DocumentMut, InlineTable, Item, Value};
@ -78,13 +80,13 @@ impl Package {
};
let deps = deps.as_array().context("`deps` must be an array")?;
println!("{section}s:");
writeln!(io::stdout(), "{section}s:")?;
for dep in deps {
let Some(dep) = dep.as_inline_table() else { continue };
match (dep.get("use").and_then(Value::as_str), dep.get("rev").and_then(Value::as_str)) {
(Some(use_), None) => println!("\t{use_}"),
(Some(use_), Some(rev)) => println!("\t{use_} ({rev})"),
(Some(use_), None) => writeln!(io::stdout(), "\t{use_}")?,
(Some(use_), Some(rev)) => writeln!(io::stdout(), "\t{use_} ({rev})")?,
_ => {}
}
}