intelli_shell/process/
update.rs1use crossterm::style::Stylize;
2
3use crate::{
4 cli::UpdateProcess,
5 config::Config,
6 errors::AppError,
7 format_error,
8 process::{Process, ProcessOutput},
9 service::IntelliShellService,
10 utils::{InstallationMethod, detect_installation_method},
11};
12
13impl Process for UpdateProcess {
14 async fn execute(self, config: Config, service: IntelliShellService) -> color_eyre::Result<ProcessOutput> {
15 let current_version_str = env!("CARGO_PKG_VERSION");
16 let current_version_tag = format!("v{current_version_str}");
17 let latest_version = match service.check_new_version().await {
18 Ok(Some(v)) => v,
19 Ok(None) => {
20 return Ok(ProcessOutput::success().stdout(format!(
21 "You're all set! You are running the latest version of intelli-shell ({}).",
22 current_version_tag.cyan()
23 )));
24 }
25 Err(AppError::UserFacing(err)) => {
26 return Ok(ProcessOutput::fail().stderr(format_error!(config.theme, "{err}")));
27 }
28 Err(AppError::Unexpected(report)) => return Err(report),
29 };
30 let latest_version_tag = format!("v{latest_version}");
31
32 let header = format!(
34 "🚀 A new version is available! ({} -> {})",
35 current_version_tag.yellow(),
36 latest_version_tag.clone().green(),
37 );
38
39 match detect_installation_method(&config.data_dir) {
41 InstallationMethod::Installer => {
43 let initial_message = format!("{header}\n\nDownloading ...");
44 println!("{initial_message}");
45
46 let target_version_tag = latest_version_tag.clone();
47 let status = tokio::task::spawn_blocking(move || {
48 self_update::backends::github::Update::configure()
49 .repo_owner("lasantosr")
50 .repo_name("intelli-shell")
51 .bin_name("intelli-shell")
52 .show_output(false)
53 .show_download_progress(true)
54 .no_confirm(true)
55 .current_version(current_version_str)
56 .target_version_tag(&target_version_tag)
57 .build()?
58 .update()
59 })
60 .await?;
61
62 println!("\n");
63
64 match status {
65 Ok(self_update::Status::UpToDate(_)) => unreachable!(),
66 Ok(self_update::Status::Updated(_)) => Ok(ProcessOutput::success().stdout(format!(
67 "✅ Update complete! You are now on intelli-shell {}.",
68 latest_version_tag.cyan()
69 ))),
70 Err(e) => Ok(ProcessOutput::fail().stderr(format!(
71 "❌ Update failed:\n{e}\n\nPlease check your network connection or file permissions.",
72 ))),
73 }
74 }
75 installation_method => {
77 let instructions = get_manual_update_instructions(installation_method);
78 let full_message = format!("{header}\n\n{instructions}");
79 Ok(ProcessOutput::success().stdout(full_message))
80 }
81 }
82 }
83}
84
85fn get_manual_update_instructions(method: InstallationMethod) -> String {
87 match method {
88 InstallationMethod::Cargo => format!(
89 "It looks like you installed with {}. To update, please run:\n\n{}\n",
90 "cargo".yellow(),
91 " LIBSQLITE3_FLAGS=\"-DSQLITE_ENABLE_MATH_FUNCTIONS\" cargo install intelli-shell --locked".cyan()
92 ),
93 InstallationMethod::Nix => format!(
94 "It looks like you installed with {}. Consider updating it via your Nix configuration.",
95 "Nix".yellow()
96 ),
97 InstallationMethod::Source => format!(
98 "It looks like you installed from {}. You might need to run:\n\n{}\n",
99 "source".yellow(),
100 " git pull && cargo build --release".cyan()
101 ),
102 InstallationMethod::Unknown(Some(path)) => format!(
103 "Could not determine the installation method. Your executable is located at:\n\n {}\n\nPlease update \
104 manually or consider reinstalling with the recommended script.",
105 path.cyan()
106 ),
107 InstallationMethod::Unknown(None) => {
108 "Could not determine the installation method. Please update manually.".to_string()
109 }
110 InstallationMethod::Installer => unreachable!(),
111 }
112}