carch_cli/
commands.rs

1use carch_core::error::{CarchError, Result};
2use log::info;
3use std::fs;
4use std::io::{self, Write};
5use std::os::unix::fs::PermissionsExt;
6use std::process::{Command, Stdio};
7use tempfile::Builder;
8
9use carch_core::version;
10
11pub fn check_for_updates() -> Result<()> {
12    println!("Checking for updates...");
13
14    let current_version = env!("CARGO_PKG_VERSION");
15
16    match version::get_latest_version() {
17        Ok(latest_version) => {
18            println!("Current version: {current_version}");
19            println!("Latest version: {latest_version}");
20
21            if latest_version != current_version {
22                println!("\nA new version of Carch is available!");
23                println!("Run 'carch update' to update to the latest version.");
24            } else {
25                println!("\nYou are using the latest version of Carch.");
26            }
27        }
28        Err(e) => {
29            eprintln!("Error checking for updates: {e}");
30            return Err(e);
31        }
32    }
33
34    Ok(())
35}
36
37enum InstallMethod {
38    Cargo,
39    PackageManager,
40    Exit,
41    Invalid,
42}
43
44fn command_exists(command: &str) -> bool {
45    Command::new("sh")
46        .arg("-c")
47        .arg(format!("command -v {command}"))
48        .stdout(Stdio::null())
49        .stderr(Stdio::null())
50        .status()
51        .is_ok_and(|s| s.success())
52}
53
54fn run_command(command: &mut Command) -> Result<()> {
55    let status = command.status()?;
56    if !status.success() {
57        return Err(CarchError::Command(format!("Command failed with exit code {status}")));
58    }
59    Ok(())
60}
61
62fn get_installation_method() -> Result<InstallMethod> {
63    print!(
64        "From which install media have you installed carch? (c)argo, (p)ackage manager, or (e)xit: "
65    );
66    io::stdout().flush()?;
67    let mut choice = String::new();
68    io::stdin().read_line(&mut choice)?;
69    Ok(match choice.trim().to_lowercase().as_str() {
70        "c" | "cargo" => InstallMethod::Cargo,
71        "p" | "package manager" => InstallMethod::PackageManager,
72        "e" | "exit" => InstallMethod::Exit,
73        _ => InstallMethod::Invalid,
74    })
75}
76
77fn run_script_from_url(action: &str) -> Result<()> {
78    info!("Downloading install script...");
79    let script_contents =
80        reqwest::blocking::get("https://chalisehari.com.np/carchinstall")?.bytes()?;
81
82    let mut temp_script = Builder::new().prefix("carch-install-").suffix(".sh").tempfile()?;
83    temp_script.write_all(&script_contents)?;
84
85    let temp_path = temp_script.path().to_path_buf();
86    let mut perms = fs::metadata(&temp_path)?.permissions();
87    perms.set_mode(0o755); // rwxr-xr-x
88    fs::set_permissions(&temp_path, perms)?;
89
90    info!("Executing install script with action: {action}");
91    run_command(Command::new("sh").arg(&temp_path).arg(action))?;
92
93    Ok(())
94}
95
96pub fn update() -> Result<()> {
97    if !command_exists("carch") {
98        println!("Carch is not installed. Please install it first.");
99        return Ok(());
100    }
101
102    match get_installation_method()? {
103        InstallMethod::Cargo => update_via_cargo(),
104        InstallMethod::PackageManager => update_via_package_manager(),
105        InstallMethod::Exit => {
106            println!("Exiting update.");
107            Ok(())
108        }
109        InstallMethod::Invalid => {
110            println!("Invalid choice. Please run the command again.");
111            Ok(())
112        }
113    }
114}
115
116fn update_via_cargo() -> Result<()> {
117    info!("Updating via cargo...");
118    run_command(Command::new("cargo").arg("install").arg("carch-cli").arg("--force"))?;
119    println!("Update done.");
120    Ok(())
121}
122
123fn update_via_package_manager() -> Result<()> {
124    info!("Updating via install script...");
125    run_script_from_url("update")?;
126    println!("Update done.");
127    Ok(())
128}
129
130pub fn uninstall() -> Result<()> {
131    if !command_exists("carch") {
132        println!("Carch is not installed.");
133        return Ok(());
134    }
135
136    match get_installation_method()? {
137        InstallMethod::Cargo => uninstall_via_cargo(),
138        InstallMethod::PackageManager => uninstall_via_package_manager(),
139        InstallMethod::Exit => {
140            println!("Exiting uninstallation.");
141            Ok(())
142        }
143        InstallMethod::Invalid => {
144            println!("Invalid choice. Please run the command again.");
145            Ok(())
146        }
147    }
148}
149
150fn uninstall_via_cargo() -> Result<()> {
151    info!("Uninstalling via cargo...");
152    run_command(Command::new("cargo").arg("uninstall").arg("carch-cli"))?;
153    println!("Uninstallation done.");
154    Ok(())
155}
156
157fn uninstall_via_package_manager() -> Result<()> {
158    info!("Uninstalling via install script...");
159    run_script_from_url("uninstall")?;
160    println!("Uninstallation done.");
161    Ok(())
162}