Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trap panics and silence bad pipe errors #862

Merged
merged 2 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ _Unreleased_

- Updated to `uv` 0.1.6. #850

- Trap panics and silence bad pipe errors. #862

## 0.28.0

Released on 2024-03-07
Expand Down
45 changes: 24 additions & 21 deletions rye/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};

use crate::utils::panic::trap_bad_pipe;
use crate::utils::QuietExit;

#[macro_use]
Expand Down Expand Up @@ -34,6 +34,8 @@ pub fn disable_ctrlc_handler() {
}

pub fn main() {
crate::utils::panic::set_panic_hook();

ctrlc::set_handler(move || {
if !DISABLE_CTRLC_HANDLER.load(Ordering::Relaxed) {
let term = console::Term::stderr();
Expand All @@ -48,26 +50,27 @@ pub fn main() {
})
.unwrap();

let result = cli::execute();
let status = match result {
Ok(()) => 0,
Err(err) => {
if let Some(err) = err.downcast_ref::<clap::Error>() {
err.print().ok();
err.exit_code()
} else if let Some(QuietExit(code)) = err.downcast_ref() {
*code
} else {
error!("{:?}", err);
1
trap_bad_pipe(|| {
let result = cli::execute();
let status = match result {
Ok(()) => 0,
Err(err) => {
if let Some(err) = err.downcast_ref::<clap::Error>() {
err.print().ok();
err.exit_code()
} else if let Some(QuietExit(code)) = err.downcast_ref() {
*code
} else {
error!("{:?}", err);
1
}
}
}
};
};

if SHOW_CONTINUE_PROMPT.load(Ordering::Relaxed) {
echo!("Press any key to continue");
console::Term::buffered_stderr().read_key().ok();
}

process::exit(status);
if SHOW_CONTINUE_PROMPT.load(Ordering::Relaxed) {
echo!("Press any key to continue");
console::Term::buffered_stderr().read_key().ok();
}
status
});
}
1 change: 1 addition & 0 deletions rye/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub(crate) mod windows;
#[cfg(unix)]
pub(crate) mod unix;

pub(crate) mod panic;
pub(crate) mod ruff;
pub(crate) mod toml;

Expand Down
32 changes: 32 additions & 0 deletions rye/src/utils/panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::any::Any;
use std::{panic, process};

fn is_bad_pipe(payload: &dyn Any) -> bool {
payload
.downcast_ref::<String>()
.map_or(false, |x| x.contains("failed printing to stdout: "))
}

/// Registers a panic hook that hides stdout printing failures.
pub fn set_panic_hook() {
let default_hook = panic::take_hook();
panic::set_hook(Box::new(move |info| {
if !is_bad_pipe(info.payload()) {
default_hook(info)
}
}));
}

/// Catches down panics that are caused by bad pipe errors.
pub fn trap_bad_pipe<F: FnOnce() -> i32 + Send + Sync>(f: F) -> ! {
process::exit(match panic::catch_unwind(panic::AssertUnwindSafe(f)) {
Ok(status) => status,
Err(panic) => {
if is_bad_pipe(&panic) {
1
} else {
panic::resume_unwind(panic);
}
}
});
}
Loading