new file: Makefile
new file: TODO.md modified: src/config.rs modified: src/detect.rs modified: src/diagnose.rs new file: src/gui.rs modified: src/main.rs modified: src/service.rs modified: src/setup.rs modified: src/tray.rs new file: src/util.rs new file: umutray.desktop
This commit is contained in:
+42
-46
@@ -4,38 +4,30 @@ use std::os::unix::fs::MetadataExt;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
struct Check {
|
||||
label: String,
|
||||
pass: bool,
|
||||
detail: String,
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CheckResult {
|
||||
pub label: String,
|
||||
pub pass: bool,
|
||||
pub detail: String,
|
||||
}
|
||||
|
||||
impl Check {
|
||||
impl CheckResult {
|
||||
fn pass(label: impl Into<String>, detail: impl Into<String>) -> Self {
|
||||
Self {
|
||||
label: label.into(),
|
||||
pass: true,
|
||||
detail: detail.into(),
|
||||
}
|
||||
Self { label: label.into(), pass: true, detail: detail.into() }
|
||||
}
|
||||
fn fail(label: impl Into<String>, detail: impl Into<String>) -> Self {
|
||||
Self {
|
||||
label: label.into(),
|
||||
pass: false,
|
||||
detail: detail.into(),
|
||||
}
|
||||
Self { label: label.into(), pass: false, detail: detail.into() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(config: &Config, name: Option<&str>) -> Result<()> {
|
||||
let mut checks: Vec<Check> = vec![
|
||||
pub fn run_checks(config: &Config, name: Option<&str>) -> Result<Vec<CheckResult>> {
|
||||
let mut checks = vec![
|
||||
global_umu_check(),
|
||||
global_vulkan_check(),
|
||||
global_display_check(),
|
||||
compat_dir_check(config),
|
||||
wineserver_check(config),
|
||||
];
|
||||
|
||||
let launchers: Vec<&Launcher> = if let Some(n) = name {
|
||||
let l = config
|
||||
.find(n)
|
||||
@@ -47,7 +39,11 @@ pub fn run(config: &Config, name: Option<&str>) -> Result<()> {
|
||||
for l in launchers {
|
||||
checks.extend(launcher_checks(l));
|
||||
}
|
||||
Ok(checks)
|
||||
}
|
||||
|
||||
pub fn run(config: &Config, name: Option<&str>) -> Result<()> {
|
||||
let checks = run_checks(config, name)?;
|
||||
let mut issues = 0u32;
|
||||
println!();
|
||||
for c in &checks {
|
||||
@@ -71,14 +67,14 @@ pub fn run(config: &Config, name: Option<&str>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn global_umu_check() -> Check {
|
||||
fn global_umu_check() -> CheckResult {
|
||||
match which("umu-run") {
|
||||
Some(p) => Check::pass("umu-run", format!("found at {p}")),
|
||||
None => Check::fail("umu-run", "not found — install umu-launcher"),
|
||||
Some(p) => CheckResult::pass("umu-run", format!("found at {p}")),
|
||||
None => CheckResult::fail("umu-run", "not found — install umu-launcher"),
|
||||
}
|
||||
}
|
||||
|
||||
fn global_vulkan_check() -> Check {
|
||||
fn global_vulkan_check() -> CheckResult {
|
||||
let ok = Command::new("vulkaninfo")
|
||||
.arg("--summary")
|
||||
.stdout(Stdio::null())
|
||||
@@ -87,33 +83,33 @@ fn global_vulkan_check() -> Check {
|
||||
.map(|s| s.success())
|
||||
.unwrap_or(false);
|
||||
if ok {
|
||||
Check::pass("vulkan", "vulkaninfo OK")
|
||||
CheckResult::pass("vulkan", "vulkaninfo OK")
|
||||
} else {
|
||||
Check::fail(
|
||||
CheckResult::fail(
|
||||
"vulkan",
|
||||
"vulkaninfo failed — check GPU drivers / vulkan-tools",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn global_display_check() -> Check {
|
||||
fn global_display_check() -> CheckResult {
|
||||
let display = std::env::var("DISPLAY").ok();
|
||||
let wayland = std::env::var("WAYLAND_DISPLAY").ok();
|
||||
match (display, wayland) {
|
||||
(Some(d), Some(_)) => Check::pass("display", format!("XWayland (DISPLAY={d})")),
|
||||
(Some(d), None) => Check::pass("display", format!("X11 (DISPLAY={d})")),
|
||||
(None, Some(_)) => Check::fail(
|
||||
(Some(d), Some(_)) => CheckResult::pass("display", format!("XWayland (DISPLAY={d})")),
|
||||
(Some(d), None) => CheckResult::pass("display", format!("X11 (DISPLAY={d})")),
|
||||
(None, Some(_)) => CheckResult::fail(
|
||||
"display",
|
||||
"Wayland session but DISPLAY unset; XWayland needed",
|
||||
),
|
||||
(None, None) => Check::fail("display", "neither DISPLAY nor WAYLAND_DISPLAY set"),
|
||||
(None, None) => CheckResult::fail("display", "neither DISPLAY nor WAYLAND_DISPLAY set"),
|
||||
}
|
||||
}
|
||||
|
||||
fn compat_dir_check(config: &Config) -> Check {
|
||||
fn compat_dir_check(config: &Config) -> CheckResult {
|
||||
let n = count_ge_proton(&config.proton_compat_dir);
|
||||
if config.proton_version == "GE-Proton" {
|
||||
Check::pass(
|
||||
CheckResult::pass(
|
||||
"proton",
|
||||
format!(
|
||||
"tracking latest; {n} version(s) in {}",
|
||||
@@ -123,9 +119,9 @@ fn compat_dir_check(config: &Config) -> Check {
|
||||
} else {
|
||||
let path = config.proton_compat_dir.join(&config.proton_version);
|
||||
if path.exists() {
|
||||
Check::pass("proton", format!("{} installed", config.proton_version))
|
||||
CheckResult::pass("proton", format!("{} installed", config.proton_version))
|
||||
} else {
|
||||
Check::fail(
|
||||
CheckResult::fail(
|
||||
"proton",
|
||||
format!(
|
||||
"{} missing — run: umutray update-proton --version={}",
|
||||
@@ -136,19 +132,19 @@ fn compat_dir_check(config: &Config) -> Check {
|
||||
}
|
||||
}
|
||||
|
||||
fn wineserver_check(config: &Config) -> Check {
|
||||
fn wineserver_check(config: &Config) -> CheckResult {
|
||||
let count = wineserver_count();
|
||||
if count == 0 {
|
||||
return Check::pass("wine procs", "no wineserver running");
|
||||
return CheckResult::pass("wine procs", "no wineserver running");
|
||||
}
|
||||
let any_running = config.launchers.iter().any(crate::launcher::is_running);
|
||||
if any_running {
|
||||
Check::pass(
|
||||
CheckResult::pass(
|
||||
"wine procs",
|
||||
format!("{count} wineserver process(es); launcher active"),
|
||||
)
|
||||
} else {
|
||||
Check::fail(
|
||||
CheckResult::fail(
|
||||
"wine procs",
|
||||
format!("{count} stale wineserver process(es) — try: umutray kill"),
|
||||
)
|
||||
@@ -165,12 +161,12 @@ fn wineserver_count() -> usize {
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn launcher_checks(l: &Launcher) -> Vec<Check> {
|
||||
fn launcher_checks(l: &Launcher) -> Vec<CheckResult> {
|
||||
let mut out = Vec::new();
|
||||
let tag = format!("[{}]", l.name);
|
||||
|
||||
if !l.prefix_dir.exists() {
|
||||
out.push(Check::fail(
|
||||
out.push(CheckResult::fail(
|
||||
format!("{tag} prefix"),
|
||||
format!(
|
||||
"{} missing — run: umutray setup {}",
|
||||
@@ -180,34 +176,34 @@ fn launcher_checks(l: &Launcher) -> Vec<Check> {
|
||||
));
|
||||
return out;
|
||||
}
|
||||
out.push(Check::pass(
|
||||
out.push(CheckResult::pass(
|
||||
format!("{tag} prefix"),
|
||||
l.prefix_dir.display().to_string(),
|
||||
));
|
||||
|
||||
let exe = l.full_exe_path();
|
||||
if exe.exists() {
|
||||
out.push(Check::pass(format!("{tag} exe"), "installed"));
|
||||
out.push(CheckResult::pass(format!("{tag} exe"), "installed"));
|
||||
} else {
|
||||
out.push(Check::fail(
|
||||
out.push(CheckResult::fail(
|
||||
format!("{tag} exe"),
|
||||
format!("missing — run: umutray setup {}", l.name),
|
||||
));
|
||||
}
|
||||
|
||||
if is_owned_by_current_user(&l.prefix_dir) {
|
||||
out.push(Check::pass(format!("{tag} owner"), "owned by current user"));
|
||||
out.push(CheckResult::pass(format!("{tag} owner"), "owned by current user"));
|
||||
} else {
|
||||
out.push(Check::fail(
|
||||
out.push(CheckResult::fail(
|
||||
format!("{tag} owner"),
|
||||
"not owned by current user",
|
||||
));
|
||||
}
|
||||
|
||||
if crate::launcher::is_running(l) {
|
||||
out.push(Check::pass(format!("{tag} process"), "currently running"));
|
||||
out.push(CheckResult::pass(format!("{tag} process"), "currently running"));
|
||||
} else {
|
||||
out.push(Check::pass(format!("{tag} process"), "not running"));
|
||||
out.push(CheckResult::pass(format!("{tag} process"), "not running"));
|
||||
}
|
||||
|
||||
out
|
||||
|
||||
Reference in New Issue
Block a user