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