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); 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}