kasl/commands/update.rs
1//! Application self-update command.
2//!
3//! Handles checking for and installing newer versions of kasl from GitHub releases with automatic binary replacement and backup capabilities.
4//!
5//! ## Features
6//!
7//! - **GitHub Integration**: Checks latest releases via GitHub API
8//! - **Cross-Platform Support**: Works on Windows, macOS, and Linux
9//! - **Safe Updates**: Creates backups before replacing binaries
10//! - **Watcher Management**: Automatically stops and restarts monitoring daemon
11//! - **Version Detection**: Compares current version with latest available
12//!
13//! ## Usage
14//!
15//! ```bash
16//! # Check for and install updates
17//! kasl update
18//! ```
19
20use crate::{
21 libs::{daemon, messages::Message, update::Updater},
22 msg_info, msg_success,
23};
24use anyhow::Result;
25
26/// Executes the application update process.
27///
28/// Performs a complete update workflow including version check, platform detection,
29/// download, extraction, and safe replacement of the current executable.
30///
31/// # Returns
32///
33/// Returns `Ok(())` on successful update or if no update is needed.
34/// Returns an error if the update process fails.
35pub async fn cmd() -> Result<()> {
36 // Check if watcher is currently running before update
37 let watcher_was_running = daemon::is_running();
38
39 if watcher_was_running {
40 msg_info!(Message::WatcherStoppingForUpdate);
41 daemon::stop()?;
42 }
43
44 // Create a new Updater instance with GitHub API configuration
45 let mut updater = Updater::new()?;
46
47 // Check GitHub API for the latest release version
48 let needs_update = updater.check_for_latest_release().await?;
49
50 if !needs_update {
51 msg_info!(Message::NoUpdateRequired);
52
53 // If watcher was running before update check, restart it
54 if watcher_was_running {
55 msg_info!(Message::WatcherRestartingAfterUpdate);
56 daemon::spawn()?;
57 }
58
59 return Ok(());
60 }
61
62 // Download and install the latest version
63 // This includes downloading the archive, extracting the binary,
64 // backing up the current executable, and replacing it
65 updater.perform_update().await?;
66
67 // Restart watcher if it was running before the update
68 if watcher_was_running {
69 msg_info!(Message::WatcherRestartingAfterUpdate);
70 daemon::spawn()?;
71 }
72
73 // Confirm successful update with version information
74 msg_success!(Message::UpdateCompleted {
75 app_name: updater.name,
76 version: updater.latest_version.as_deref().unwrap_or("unknown").to_string()
77 });
78
79 Ok(())
80}