//! self-update: download a newer agent-manager binary from GitHub Releases. use super::*; use crate::download; use anyhow::{anyhow, bail, Context, Result}; use std::cmp::Ordering; use std::path::Path; pub fn run(app: &App, check: bool, to: Option<&Path>) -> Result { let Some(repo) = app.config.settings.self_update_repo.clone() else { bail!( "self-update is not configured: set 'settings.self_update_repo: \"owner/repo\"' in your config" ); }; let current = env!("CARGO_PKG_VERSION"); let release = download::latest_release_with_base( &repo, app.config.settings.self_update_base_url.as_deref(), )?; let tag = release.tag_name.trim_start_matches('v').to_string(); if check { match crate::version::compare(&tag, current) { Some(Ordering::Greater) => { println!("update available: {current} -> {tag}"); Ok(0) } _ => { println!("agent-manager {current} is up to date"); Ok(0) } } } else { if crate::version::compare(&tag, current) != Some(Ordering::Greater) { app.log.success(&format!( "agent-manager {current} is already the latest version" )); return Ok(0); } if app.dry_run() { app.log .dry(format!("would download agent-manager {tag}")); return Ok(0); } let picked = download::pick_asset(&release, &[], &[], None) .ok_or_else(|| anyhow!("no release asset of '{repo}' matches this platform"))?; app.log.info(&format!( "downloading agent-manager {tag} ({})", picked.name )); let current_exe = std::env::current_exe()?; let dest = to.map(|p| p.to_path_buf()).unwrap_or_else(|| current_exe.clone()); let tmpdir = tempfile::tempdir()?; let tmp = tmpdir.path().join("am.new"); download::download(&picked.url, &tmp, None, true)?; if dest == current_exe && cfg!(windows) { // The running executable is locked on Windows. let new_path = current_exe.with_extension("exe.new"); std::fs::copy(&tmp, &new_path) .with_context(|| format!("cannot write {}", new_path.display()))?; app.log.success(&format!( "downloaded {tag} to {} — replace the running binary manually", new_path.display() )); } else { std::fs::copy(&tmp, &dest) .with_context(|| format!("cannot write {}", dest.display()))?; #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let _ = std::fs::set_permissions( &dest, std::fs::Permissions::from_mode(0o755), ); } app.log .success(&format!("updated agent-manager to {tag} ({})", dest.display())); } Ok(0) } }