use anyhow::{Result, bail};
use std::fs;
use std::io::Write;
pub fn run() -> Result<i32> {
let current_version = env!("CARGO_PKG_VERSION");
println!("Current version: {}", current_version);
println!("Checking for updates...");
let releases = self_update::backends::github::ReleaseList::configure()
.repo_owner("yusukeshib")
.repo_name("babysit")
.build()
.map_err(|e| anyhow::anyhow!("Failed to build release list: {}", e))?
.fetch()
.map_err(|e| anyhow::anyhow!("Failed to fetch releases: {}", e))?;
let latest = releases
.first()
.ok_or_else(|| anyhow::anyhow!("No releases found"))?;
let latest_version = latest.version.trim_start_matches('v');
println!("Latest version: {}", latest_version);
if current_version == latest_version {
println!("Already at latest version.");
return Ok(0);
}
let asset_name = asset_name()?;
println!("Looking for asset: {}", asset_name);
let asset_exists = latest.assets.iter().any(|a| a.name == asset_name);
if !asset_exists {
bail!(
"Asset '{}' not found for this platform. Available assets: {}",
asset_name,
latest
.assets
.iter()
.map(|a| a.name.as_str())
.collect::<Vec<_>>()
.join(", ")
);
}
let download_url = format!(
"https://github.com/yusukeshib/babysit/releases/download/v{}/{}",
latest_version, asset_name
);
println!("Downloading new version...");
let tmp_path = download(&download_url)?;
let _guard = TempGuard(tmp_path.clone());
println!("Installing update...");
self_update::self_replace::self_replace(&tmp_path).map_err(|e| {
let msg = e.to_string();
if msg.to_lowercase().contains("permission denied") {
anyhow::anyhow!(
"Permission denied. Try running with elevated privileges (e.g., sudo babysit upgrade)."
)
} else {
anyhow::anyhow!("{}", msg)
}
})?;
println!("Upgraded from {} to {}.", current_version, latest_version);
Ok(0)
}
struct TempGuard(std::path::PathBuf);
impl Drop for TempGuard {
fn drop(&mut self) {
let _ = fs::remove_file(&self.0);
}
}
fn asset_name() -> Result<String> {
let arch = std::env::consts::ARCH;
let os_name = match std::env::consts::OS {
"macos" => "darwin",
"linux" => "linux",
other => bail!("Unsupported platform: {}", other),
};
Ok(format!("babysit-{}-{}", arch, os_name))
}
fn download(url: &str) -> Result<std::path::PathBuf> {
let tmp_path = std::env::temp_dir().join(format!("babysit-update-{}", std::process::id()));
let mut tmp_file = fs::File::create(&tmp_path)?;
self_update::Download::from_url(url)
.download_to(&mut tmp_file)
.map_err(|e| anyhow::anyhow!("Download failed: {}", e))?;
tmp_file.flush()?;
drop(tmp_file);
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(&tmp_path)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(&tmp_path, perms)?;
}
Ok(tmp_path)
}