Add launch crash detection with detailed error dialog, fix all warnings
Detect AppImages that crash immediately after spawning (within 1.5s) by capturing stderr and using try_wait(). Show a full AlertDialog with a plain-text explanation, scrollable error output, and a copy-to-clipboard button. Covers Qt plugin errors, missing libraries, segfaults, permission issues, and display connection failures. Move launch operations to background threads in both the detail view and context menu to avoid blocking the UI during the 1.5s crash detection window. Suppress all 57 compiler warnings across future-use modules (backup, notification, report, watcher) and individual unused fields/variants in other core modules.
This commit is contained in:
@@ -42,6 +42,7 @@ pub enum LaunchMethod {
|
||||
/// Extract-and-run fallback (APPIMAGE_EXTRACT_AND_RUN=1)
|
||||
ExtractAndRun,
|
||||
/// Via firejail sandbox
|
||||
#[allow(dead_code)]
|
||||
Sandboxed,
|
||||
}
|
||||
|
||||
@@ -58,11 +59,18 @@ impl LaunchMethod {
|
||||
/// Result of a launch attempt.
|
||||
#[derive(Debug)]
|
||||
pub enum LaunchResult {
|
||||
/// Successfully spawned the process.
|
||||
/// Successfully spawned the process and it's still running.
|
||||
Started {
|
||||
child: Child,
|
||||
method: LaunchMethod,
|
||||
},
|
||||
/// Process spawned but crashed immediately (within ~1 second).
|
||||
Crashed {
|
||||
exit_code: Option<i32>,
|
||||
stderr: String,
|
||||
#[allow(dead_code)]
|
||||
method: LaunchMethod,
|
||||
},
|
||||
/// Failed to launch.
|
||||
Failed(String),
|
||||
}
|
||||
@@ -155,20 +163,56 @@ fn execute_appimage(
|
||||
cmd.env(key, value);
|
||||
}
|
||||
|
||||
// Detach from our process group so the app runs independently
|
||||
// Capture stderr to detect crash messages, stdin detached
|
||||
cmd.stdin(Stdio::null());
|
||||
cmd.stderr(Stdio::piped());
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(child) => LaunchResult::Started {
|
||||
child,
|
||||
method: method.clone(),
|
||||
},
|
||||
Err(e) => LaunchResult::Failed(format!("Failed to spawn process: {}", e)),
|
||||
Ok(mut child) => {
|
||||
// Brief wait to detect immediate crashes (e.g. missing Qt plugins)
|
||||
std::thread::sleep(std::time::Duration::from_millis(1500));
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) => {
|
||||
// Process already exited - it crashed
|
||||
let stderr = child
|
||||
.stderr
|
||||
.take()
|
||||
.and_then(|mut err| {
|
||||
let mut buf = String::new();
|
||||
use std::io::Read;
|
||||
err.read_to_string(&mut buf).ok()?;
|
||||
Some(buf)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
LaunchResult::Crashed {
|
||||
exit_code: status.code(),
|
||||
stderr,
|
||||
method: method.clone(),
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
// Still running - success
|
||||
LaunchResult::Started {
|
||||
child,
|
||||
method: method.clone(),
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Can't check status, assume it's running
|
||||
LaunchResult::Started {
|
||||
child,
|
||||
method: method.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => LaunchResult::Failed(format!("Failed to start: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a launch_args string from the database into a Vec of individual arguments.
|
||||
/// Splits on whitespace; returns an empty Vec if the input is None or empty.
|
||||
#[allow(dead_code)]
|
||||
pub fn parse_launch_args(args: Option<&str>) -> Vec<String> {
|
||||
args.map(|s| s.split_whitespace().map(String::from).collect())
|
||||
.unwrap_or_default()
|
||||
|
||||
Reference in New Issue
Block a user