Skip to main content

juliaup/
command_selfupdate.rs

1use crate::global_paths::GlobalPaths;
2use crate::operations::update_version_db;
3use anyhow::{Context, Result};
4
5#[cfg(feature = "selfupdate")]
6pub fn run_command_selfupdate(paths: &GlobalPaths) -> Result<()> {
7    use crate::config_file::{load_mut_config_db, save_config_db};
8    use crate::operations::{download_extract_sans_parent, download_juliaup_version};
9    use crate::utils::get_juliaserver_base_url;
10    use crate::{get_juliaup_target, get_own_version};
11    use anyhow::{anyhow, bail};
12
13    update_version_db(&None, paths).with_context(|| "Failed to update versions db.")?;
14
15    let mut config_file = load_mut_config_db(paths)
16        .with_context(|| "`selfupdate` command failed to load configuration db.")?;
17
18    let juliaup_channel = match &config_file.self_data.juliaup_channel {
19        Some(juliaup_channel) => juliaup_channel.to_string(),
20        None => "release".to_string(),
21    };
22
23    let juliaupserver_base =
24        get_juliaserver_base_url().with_context(|| "Failed to get Juliaup server base URL.")?;
25
26    let version_url_path = match juliaup_channel.as_str() {
27        "release" => "juliaup/RELEASECHANNELVERSION",
28        "releasepreview" => "juliaup/RELEASEPREVIEWCHANNELVERSION",
29        "dev" => "juliaup/DEVCHANNELVERSION",
30        _ => bail!(
31            "Juliaup is configured to a channel named '{}' that does not exist.",
32            &juliaup_channel
33        ),
34    };
35
36    eprintln!("Checking for self-updates");
37
38    let version_url = juliaupserver_base.join(version_url_path).with_context(|| {
39        format!(
40            "Failed to construct a valid url from '{}' and '{}'.",
41            juliaupserver_base, version_url_path
42        )
43    })?;
44
45    let version = download_juliaup_version(version_url.as_ref())?;
46
47    config_file.self_data.last_selfupdate = Some(chrono::Utc::now());
48
49    save_config_db(&mut config_file).with_context(|| "Failed to save configuration file.")?;
50
51    if version == get_own_version().unwrap() {
52        eprintln!(
53            "Juliaup unchanged on channel '{}' - {}",
54            juliaup_channel, version
55        );
56    } else {
57        let juliaup_target = get_juliaup_target();
58
59        let juliaupserver_base =
60            get_juliaserver_base_url().with_context(|| "Failed to get Juliaup server base URL.")?;
61
62        let download_url_path =
63            format!("juliaup/bin/juliaup-{}-{}.tar.gz", version, juliaup_target);
64
65        let new_juliaup_url = juliaupserver_base
66            .join(&download_url_path)
67            .with_context(|| {
68                format!(
69                    "Failed to construct a valid url from '{}' and '{}'.",
70                    juliaupserver_base, download_url_path
71                )
72            })?;
73
74        let my_own_path = std::env::current_exe()
75            .with_context(|| "Could not determine the path of the running exe.")?;
76
77        let my_own_folder = my_own_path
78            .parent()
79            .ok_or_else(|| anyhow!("Could not determine parent."))?;
80
81        eprintln!(
82            "Found new version {} on channel {}.",
83            version, juliaup_channel
84        );
85
86        download_extract_sans_parent(new_juliaup_url.as_ref(), my_own_folder, 0)?;
87        eprintln!("Updated Juliaup to version {}.", version);
88    }
89
90    Ok(())
91}
92
93#[cfg(feature = "windowsstore")]
94pub fn run_command_selfupdate(paths: &GlobalPaths) -> Result<()> {
95    use windows::{
96        core::Interface,
97        Win32::{System::Console::GetConsoleWindow, UI::Shell::IInitializeWithWindow},
98    };
99
100    update_version_db(&None, paths).with_context(|| "Failed to update versions db.")?;
101
102    let update_manager = windows::Services::Store::StoreContext::GetDefault()
103        .with_context(|| "Failed to get the store context.")?;
104
105    let interop: IInitializeWithWindow = update_manager
106        .cast()
107        .with_context(|| "Failed to cast the store context to IInitializeWithWindow.")?;
108
109    unsafe {
110        let x = GetConsoleWindow();
111
112        interop
113            .Initialize(x)
114            .with_context(|| "Call to IInitializeWithWindow.Initialize failed.")?;
115    }
116
117    let updates = update_manager
118        .GetAppAndOptionalStorePackageUpdatesAsync()
119        .with_context(|| "Call to GetAppAndOptionalStorePackageUpdatesAsync failed.")?
120        .join()
121        .with_context(|| {
122            "get on the return of GetAppAndOptionalStorePackageUpdatesAsync failed."
123        })?;
124
125    if updates
126        .Size()
127        .with_context(|| "Call to Size on update results failed.")?
128        > 0
129    {
130        eprintln!("An update is available.");
131
132        let download_operation = update_manager
133            .RequestDownloadAndInstallStorePackageUpdatesAsync(&updates)
134            .with_context(|| "Call to RequestDownloadAndInstallStorePackageUpdatesAsync failed.")?;
135
136        download_operation.join().with_context(|| {
137            "get on result from RequestDownloadAndInstallStorePackageUpdatesAsync failed."
138        })?;
139        // This code will not be reached if the user opts to install updates
140    } else {
141        eprintln!("No updates available.");
142    }
143
144    Ok(())
145}
146
147#[cfg(not(any(feature = "windowsstore", feature = "selfupdate")))]
148pub fn run_command_selfupdate(paths: &GlobalPaths) -> Result<()> {
149    update_version_db(&None, paths).with_context(|| "Failed to update versions db.")?;
150    Ok(())
151}