use crate::args::RepairArgs;
use crate::installer;
use crate::style::Palette;
use anyhow::Result;
use std::process::ExitCode;
const EXIT_REPAIR_FAILED: u8 = 4;
pub async fn run(args: RepairArgs) -> Result<ExitCode> {
let Palette {
green,
red,
yellow,
dim,
bold,
reset,
} = Palette::for_stdout();
println!("{bold}keyhog repair{reset}");
let healthy = installer::scan_engine_self_test().unwrap_or(false);
if healthy && !args.force {
println!(" {green}scan engine healthy{reset} - nothing to repair.");
println!(" {dim}use --force to reinstall the latest release anyway.{reset}");
return Ok(ExitCode::SUCCESS);
}
if healthy {
println!(" {dim}--force: reinstalling a fresh binary.{reset}");
} else {
println!(" {yellow}self-test failed{reset} - reinstalling a fresh binary.");
}
let client = installer::http_client()?;
let release = installer::resolve_release(&client, args.version.as_deref()).await?;
let want_cuda = args.variant.as_deref() == Some("cuda");
let asset = installer::select_asset(&release, want_cuda)?;
println!(" downloading {} ({})", asset.name, release.tag_name);
let bytes = installer::download_verified_asset(&client, asset).await?;
let exe = installer::current_binary()?;
installer::reap_stale_binaries(&exe);
println!("\n{dim}reinstalling and verifying the new binary...{reset}\n");
match installer::install_with_rollback(&exe, &bytes, installer::verify_via_doctor) {
Ok(()) => {
println!(
"\n{green}{bold}✓ repaired: reinstalled {} and verified healthy.{reset}",
release.tag_name
);
Ok(ExitCode::SUCCESS)
}
Err(e) => {
eprintln!(
"\n{red}{bold}✗ repair of {} did not produce a healthy binary:{reset} {e}\n\
{dim}If a shared library is missing, install it (see the doctor output above) \
and retry, or try `keyhog repair --version <older-tag>`.{reset}",
release.tag_name
);
Ok(ExitCode::from(EXIT_REPAIR_FAILED))
}
}
}