diff --git a/Cargo.lock b/Cargo.lock index a73b13c..d72c5c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -122,6 +122,14 @@ dependencies = [ "memchr", ] +[[package]] +name = "custom-message-test" +version = "0.1.0" +dependencies = [ + "human-panic", + "snapbox", +] + [[package]] name = "custom-panic-test" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index cb5b624..f376678 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "tests/single-panic", "tests/custom-panic", + "tests/custom-message", ] resolver = "2" diff --git a/src/lib.rs b/src/lib.rs index fb9a2aa..0a8a9f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,11 +58,11 @@ use std::path::{Path, PathBuf}; /// /// See [`metadata!`] pub struct Metadata { - name: Cow<'static, str>, - version: Cow<'static, str>, - authors: Option>, - homepage: Option>, - support: Option>, + pub name: Cow<'static, str>, + pub version: Cow<'static, str>, + pub authors: Option>, + pub homepage: Option>, + pub support: Option>, } impl Metadata { @@ -140,16 +140,22 @@ macro_rules! metadata { #[macro_export] macro_rules! setup_panic { ($meta:expr) => {{ - $crate::setup_panic(|| $meta); + $crate::setup_panic(|| $meta, None); + }}; + + ($meta:expr, $print_fn:expr) => {{ + $crate::setup_panic(|| $meta, Some($print_fn)); }}; () => { - $crate::setup_panic!($crate::metadata!()); + $crate::setup_panic(|| $crate::metadata!(), None); }; } +pub type WriteFunc = fn (&mut dyn std::io::Write, Option<&Path>, &Metadata) -> IoResult<()>; + #[doc(hidden)] -pub fn setup_panic(meta: impl Fn() -> Metadata) { +pub fn setup_panic(meta: impl Fn() -> Metadata, write_func: Option) { #![allow(deprecated)] #[allow(unused_imports)] @@ -162,7 +168,8 @@ pub fn setup_panic(meta: impl Fn() -> Metadata) { panic::set_hook(Box::new(move |info: &PanicInfo<'_>| { let file_path = handle_dump(&meta, info); - print_msg(file_path, &meta) + let write_func = write_func.unwrap_or(|mut buf,fp,meta| write_msg(&mut buf,fp,meta)); + print_msg(file_path, &meta, write_func) .expect("human-panic: printing error message to console failed"); })); } @@ -194,25 +201,27 @@ impl Default for PanicStyle { /// Utility function that prints a message to our human users #[cfg(feature = "color")] -pub fn print_msg>(file_path: Option

, meta: &Metadata) -> IoResult<()> { +pub fn print_msg>(file_path: Option

, meta: &Metadata, write_func: WriteFunc) -> IoResult<()> { use std::io::Write as _; let stderr = anstream::stderr(); let mut stderr = stderr.lock(); write!(stderr, "{}", anstyle::AnsiColor::Red.render_fg())?; - write_msg(&mut stderr, file_path, meta)?; + let fp = file_path.as_ref().map(|fp| fp.as_ref()); + write_func(&mut stderr, fp, meta)?; write!(stderr, "{}", anstyle::Reset.render())?; Ok(()) } #[cfg(not(feature = "color"))] -pub fn print_msg>(file_path: Option

, meta: &Metadata) -> IoResult<()> { +pub fn print_msg>(file_path: Option

, meta: &Metadata, write_func: WriteFunc) -> IoResult<()> { let stderr = std::io::stderr(); let mut stderr = stderr.lock(); - write_msg(&mut stderr, file_path, meta)?; + let fp = file_path.as_ref().map(|fp| fp.as_ref()); + write_func(&mut stderr, fp, meta)?; Ok(()) } diff --git a/tests/custom-message/Cargo.toml b/tests/custom-message/Cargo.toml new file mode 100644 index 0000000..22dde39 --- /dev/null +++ b/tests/custom-message/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "custom-message-test" +version = "0.1.0" +authors = ["Human Panic Authors "] +edition.workspace = true +publish = false + +[package.metadata.release] +release = false + +[dependencies] +human-panic = { path = "../.." } + +[dev-dependencies] +snapbox = { version = "0.6.4", features = ["cmd"] } diff --git a/tests/custom-message/src/main.rs b/tests/custom-message/src/main.rs new file mode 100644 index 0000000..18f2b4f --- /dev/null +++ b/tests/custom-message/src/main.rs @@ -0,0 +1,46 @@ +use std::path::Path; + +use human_panic::metadata; +use human_panic::Metadata; +use human_panic::setup_panic; + +fn custom_message( + buf: &mut dyn std::io::Write, + path: Option<&Path>, + meta: &Metadata +) -> std::io::Result<()> { + let Metadata { + name, + homepage, + .. + } = meta; + + writeln!(buf, "A fatal error ocurred!")?; + writeln!(buf,"{name} is DEAD :(")?; + writeln!( + buf, + "You can see details at \"{}\".", + match path { + Some(fp) => format!("{}", fp.display()), + None => "".to_owned(), + }, + )?; + + if let Some(homepage) = homepage { + writeln!(buf, "\nShare your condolences: {homepage}")?; + } + + Ok(()) +} + +fn main() { + setup_panic!( + metadata!() + .authors("My Company Support ") + .homepage("www.mycompany.com") + .support("- Open a support request by email to support@mycompany.com"), + custom_message); + + println!("A normal log message"); + panic!("OMG EVERYTHING IS ON FIRE!!!"); +} diff --git a/tests/custom-message/tests/integration.rs b/tests/custom-message/tests/integration.rs new file mode 100644 index 0000000..072577a --- /dev/null +++ b/tests/custom-message/tests/integration.rs @@ -0,0 +1,29 @@ +#[test] +#[cfg_attr(debug_assertions, ignore)] +fn release() { + snapbox::cmd::Command::new(snapbox::cmd::cargo_bin!("custom-message-test")) + .assert() + .stderr_eq(snapbox::str![[r#" +A fatal error ocurred! +custom-message-test is DEAD :( +You can see details at [..]. + +Share your condolences: www.mycompany.com + +"#]]) + .code(101); +} + +#[test] +#[cfg_attr(not(debug_assertions), ignore)] +fn debug() { + snapbox::cmd::Command::new(snapbox::cmd::cargo_bin!("custom-message-test")) + .assert() + .stderr_eq(snapbox::str![[r#" +thread 'main' panicked at tests/custom-message/src/main.rs:45:5: +OMG EVERYTHING IS ON FIRE!!! +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + +"#]]) + .code(101); +}