feat: add update command to CLI, relay, and client
This commit is contained in:
parent
835d20f734
commit
6345209538
9 changed files with 302 additions and 0 deletions
|
|
@ -337,6 +337,12 @@ enum Commands {
|
|||
device: String,
|
||||
},
|
||||
|
||||
/// Update all components (relay, client, CLI) if behind
|
||||
Update {
|
||||
/// Device label
|
||||
device: String,
|
||||
},
|
||||
|
||||
/// Fetch last N lines of client log file
|
||||
Logs {
|
||||
/// Device label
|
||||
|
|
@ -713,6 +719,139 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
Commands::Update { device } => {
|
||||
validate_label(&device);
|
||||
|
||||
// Fetch all three commits
|
||||
let relay_commit = match reqwest::blocking::get(&format!("{}/version", cfg.base_url)) {
|
||||
Ok(r) => r
|
||||
.json::<Value>()
|
||||
.ok()
|
||||
.and_then(|v| v["commit"].as_str().map(String::from))
|
||||
.unwrap_or_else(|| "?".into()),
|
||||
Err(e) => format!("error: {}", e),
|
||||
};
|
||||
|
||||
let client_commit = {
|
||||
let data = req(&cfg, "GET", &format!("/devices/{}/version", device), None, 10);
|
||||
data["commit"].as_str().unwrap_or("?").to_string()
|
||||
};
|
||||
|
||||
let cli_commit = GIT_COMMIT;
|
||||
|
||||
println!(" relay {}", relay_commit);
|
||||
println!(" cli {}", cli_commit);
|
||||
println!(" client {}", client_commit);
|
||||
|
||||
let all_same = relay_commit == cli_commit && cli_commit == client_commit;
|
||||
if all_same {
|
||||
println!(" ✅ Already up to date (commit: {})", cli_commit);
|
||||
return;
|
||||
}
|
||||
|
||||
println!();
|
||||
let mut updated_any = false;
|
||||
|
||||
// Update relay if needed
|
||||
if relay_commit != cli_commit {
|
||||
println!(" → Updating relay...");
|
||||
let data = req(&cfg, "POST", "/relay/update", None, 15);
|
||||
println!(" {}", data["message"].as_str().unwrap_or("triggered"));
|
||||
updated_any = true;
|
||||
}
|
||||
|
||||
// Update client if needed
|
||||
if client_commit != cli_commit {
|
||||
println!(" → Updating client on {}...", device);
|
||||
let data = req(
|
||||
&cfg,
|
||||
"POST",
|
||||
&format!("/devices/{}/update", device),
|
||||
None,
|
||||
65,
|
||||
);
|
||||
println!(
|
||||
" {}",
|
||||
data["message"].as_str().unwrap_or(
|
||||
if data["success"].as_bool() == Some(true) { "triggered" } else { "failed" }
|
||||
)
|
||||
);
|
||||
updated_any = true;
|
||||
}
|
||||
|
||||
// Self-update CLI if needed
|
||||
// (relay_commit is the "canonical" latest — if we differ from it, we're outdated)
|
||||
if cli_commit != relay_commit {
|
||||
println!(" → Updating CLI...");
|
||||
#[cfg(target_os = "windows")]
|
||||
let url = "https://agent-helios.me/downloads/helios-remote/helios-remote-cli-windows.exe";
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let url = "https://agent-helios.me/downloads/helios-remote/helios-remote-cli-linux";
|
||||
|
||||
let bytes = match reqwest::blocking::get(url) {
|
||||
Ok(r) => match r.bytes() {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
eprintln!("[helios-remote] CLI update: read failed: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
eprintln!("[helios-remote] CLI update: download failed: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let exe = std::env::current_exe().unwrap_or_else(|e| {
|
||||
eprintln!("[helios-remote] CLI update: current_exe failed: {}", e);
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let tmp = exe.with_extension("new");
|
||||
std::fs::write(&tmp, &bytes).unwrap_or_else(|e| {
|
||||
eprintln!("[helios-remote] CLI update: write failed: {}", e);
|
||||
process::exit(1);
|
||||
});
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let _ = std::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o755));
|
||||
std::fs::rename(&tmp, &exe).unwrap_or_else(|e| {
|
||||
eprintln!("[helios-remote] CLI update: rename failed: {}", e);
|
||||
process::exit(1);
|
||||
});
|
||||
println!(" CLI updated. Re-executing...");
|
||||
use std::os::unix::process::CommandExt;
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let err = std::process::Command::new(&exe).args(&args[1..]).exec();
|
||||
eprintln!("[helios-remote] CLI re-exec failed: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let tmp = exe.with_extension("update.exe");
|
||||
std::fs::write(&tmp, &bytes).unwrap_or_else(|e| {
|
||||
eprintln!("[helios-remote] CLI update: write failed: {}", e);
|
||||
process::exit(1);
|
||||
});
|
||||
let old = exe.with_extension("old.exe");
|
||||
let _ = std::fs::remove_file(&old);
|
||||
let _ = std::fs::rename(&exe, &old);
|
||||
std::fs::rename(&tmp, &exe).unwrap_or_else(|e| {
|
||||
eprintln!("[helios-remote] CLI update: rename failed: {}", e);
|
||||
process::exit(1);
|
||||
});
|
||||
println!(" CLI updated. Please restart the command.");
|
||||
}
|
||||
updated_any = true;
|
||||
}
|
||||
|
||||
if updated_any {
|
||||
println!();
|
||||
println!(" ✅ Update(s) triggered.");
|
||||
}
|
||||
}
|
||||
|
||||
Commands::Logs { device, lines } => {
|
||||
validate_label(&device);
|
||||
let data = req(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue