pacenotes_installer/
crash.rs1static LOG: std::sync::Mutex<Option<std::path::PathBuf>> = std::sync::Mutex::new(None);
8
9static QUIET: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
11
12pub fn install_panic_hook() {
13 std::panic::set_hook(Box::new(|info| {
14 let location = info.location().map_or_else(
15 || "unknown location".to_string(),
16 |location| format!("{}:{}", location.file(), location.line()),
17 );
18 let message = info
19 .payload()
20 .downcast_ref::<&str>()
21 .map(|text| text.to_string())
22 .or_else(|| info.payload().downcast_ref::<String>().cloned())
23 .unwrap_or_else(|| "no message".to_string());
24 let text = format!("pacenotes-installer panicked at {location}: {message}");
25 let written = record(&text);
26
27 static SHOWN: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
29 if QUIET.load(std::sync::atomic::Ordering::SeqCst)
30 || SHOWN.swap(true, std::sync::atomic::Ordering::SeqCst)
31 {
32 return;
33 }
34 crate::i18n::use_chosen_language();
36 tell_the_user(written.as_deref(), &text);
37 }));
38}
39
40pub fn log_to(path: std::path::PathBuf) {
42 if let Ok(mut slot) = LOG.lock() {
43 *slot = Some(path);
44 }
45}
46
47pub fn be_quiet() {
48 QUIET.store(true, std::sync::atomic::Ordering::SeqCst);
49}
50
51fn tell_the_user(written: Option<&std::path::Path>, text: &str) {
54 match written {
55 Some(path) => {
56 let ask =
57 crate::i18n::load_string_arg(crate::i18n::IDS_CRASH, &path.display().to_string());
58 if crate::ui::ask_error(core::ptr::null_mut(), &ask) {
59 crate::ui::reveal_in_explorer(path);
60 }
61 }
62 None => {
63 let nowhere = crate::i18n::load_string(crate::i18n::IDS_CRASH_NOFILE);
64 crate::ui::message_box_error(
65 core::ptr::null_mut(),
66 &format!("{nowhere}\r\n\r\n{text}"),
67 );
68 }
69 }
70}
71
72fn record(text: &str) -> Option<std::path::PathBuf> {
75 let path = LOG
76 .lock()
77 .ok()
78 .and_then(|slot| slot.clone())
79 .or_else(fallback)?;
80 let mut file = std::fs::OpenOptions::new()
81 .create(true)
82 .append(true)
83 .open(&path)
84 .ok()?;
85 let now = pacenotes_installer::utc_time::iso_stamp(pacenotes_installer::utc_time::unix_now());
87 std::io::Write::write_all(&mut file, format!("{now} {text}\n").as_bytes()).ok()?;
88 Some(path)
89}
90
91fn fallback() -> Option<std::path::PathBuf> {
93 let exe = std::env::current_exe().ok()?;
94 Some(exe.with_file_name("pacenotes-installer-crash.log"))
95}