Fix launcher/download bugs, add README and Cargo.lock

- launcher: set PROTONPATH to full install path for pinned Proton versions;
  the raw tag name doesn't resolve when umu-run looks it up.
- proton: stream GE-Proton tarballs straight to disk instead of buffering
  ~600 MB in RAM via .bytes(); add error_for_status() on all HTTP calls so
  rate limits and 404s surface clearly; avoid UTF-8 trap on tar args.
- config: fail loudly when $HOME is unset instead of silently writing a Wine
  prefix under /tmp.
- diagnose: replace stat+id shell-out with MetadataExt::uid().
- tray: grab handle() before spawn() consumes the service (the repo didn't
  compile against ksni 0.2 as shipped).
- launcher/diagnose: escape the dot in "battle.net" pgrep patterns so the
  match doesn't false-positive on our own "battlenet-manager" binary; pipe
  pgrep/pkill stdio to /dev/null so PID lists don't leak into our output.
- proton: handle empty release list in pick_interactively cleanly.
- Add README, .gitignore, and commit Cargo.lock for reproducible builds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-04-16 17:18:54 -07:00
parent 246ad03266
commit 7de6f6d938
8 changed files with 2260 additions and 30 deletions
+20 -14
View File
@@ -150,7 +150,9 @@ pub fn run(config: &Config) {
// ── Running processes ────────────────────────────────────────────────────
let bnet_running = Command::new("pgrep")
.args(["-fi", "battle.net"])
.args(["-fi", "Battle\\.net"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false);
@@ -209,19 +211,23 @@ fn count_ge_proton(dir: &Path) -> usize {
}
fn is_owned_by_current_user(path: &Path) -> bool {
// Compare stat uid with current euid via id command (avoids libc dependency)
let uid_output = Command::new("id").arg("-u").output().ok();
let stat_output = Command::new("stat")
.args(["-c", "%u", path.to_str().unwrap_or("")])
.output()
.ok();
use std::os::unix::fs::MetadataExt;
match (uid_output, stat_output) {
(Some(u), Some(s)) => {
let uid = String::from_utf8_lossy(&u.stdout).trim().to_string();
let owner = String::from_utf8_lossy(&s.stdout).trim().to_string();
uid == owner
}
_ => true, // assume OK if we can't check
let file_uid = match std::fs::metadata(path) {
Ok(m) => m.uid(),
Err(_) => return true, // assume OK if we can't check
};
// No std API for the current process uid; shell out once to `id -u`.
let current_uid: Option<u32> = Command::new("id")
.arg("-u")
.output()
.ok()
.and_then(|o| String::from_utf8(o.stdout).ok())
.and_then(|s| s.trim().parse().ok());
match current_uid {
Some(uid) => uid == file_uid,
None => true,
}
}