cargo_mobile2/
update.rs

1use crate::{
2    util::{
3        self,
4        cli::{Report, TextWrapper},
5        repo::{self, Repo},
6    },
7    DuctExpressionExt,
8};
9use std::{
10    fmt::{self, Display},
11    fs::{self, File},
12    io,
13    path::PathBuf,
14};
15
16static ENABLED_FEATURES: &[&str] = &[
17    #[cfg(feature = "brainium")]
18    "brainium",
19    "cli",
20];
21
22#[derive(Debug)]
23pub enum Error {
24    NoHomeDir(util::NoHomeDir),
25    StatusFailed(repo::Error),
26    MarkerCreateFailed { path: PathBuf, cause: io::Error },
27    UpdateFailed(repo::Error),
28    InstallFailed(std::io::Error),
29    MarkerDeleteFailed { path: PathBuf, cause: io::Error },
30}
31
32impl Display for Error {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        match self {
35            Self::NoHomeDir(err) => write!(f, "{err}"),
36            Self::StatusFailed(err) => {
37                write!(f, "Failed to check status of `cargo-mobile2` repo: {err}")
38            }
39            Self::MarkerCreateFailed { path, cause } => {
40                write!(f, "Failed to create marker file at {path:?}: {cause}")
41            }
42            Self::UpdateFailed(err) => write!(f, "Failed to update `cargo-mobile2` repo: {err}"),
43            Self::InstallFailed(err) => {
44                write!(f, "Failed to install new version of `cargo-mobile2`: {err}")
45            }
46            Self::MarkerDeleteFailed { path, cause } => {
47                write!(f, "Failed to delete marker file at {path:?}: {cause}")
48            }
49        }
50    }
51}
52
53pub(crate) fn cargo_mobile_repo() -> Result<Repo, util::NoHomeDir> {
54    Repo::checkouts_dir("cargo-mobile2")
55}
56
57pub(crate) fn updating_marker_path(repo: &Repo) -> PathBuf {
58    repo.path()
59        .parent()
60        .expect("developer error: repo path had no parent")
61        .parent()
62        .expect("developer error: checkouts dir had no parent")
63        .join(".updating")
64}
65
66pub fn update(wrapper: &TextWrapper) -> Result<(), Error> {
67    let repo = cargo_mobile_repo().map_err(Error::NoHomeDir)?;
68    let marker = updating_marker_path(&repo);
69    let marker_exists = marker.is_file();
70    if marker_exists {
71        log::info!("marker file present at {:?}", marker);
72    } else {
73        log::info!("no marker file present at {:?}", marker);
74    }
75    let msg = if marker_exists || repo.status().map_err(Error::StatusFailed)?.stale() {
76        File::create(&marker).map_err(|cause| Error::MarkerCreateFailed {
77            path: marker.to_owned(),
78            cause,
79        })?;
80        repo.update("https://github.com/tauri-apps/cargo-mobile2", "dev")
81            .map_err(Error::UpdateFailed)?;
82        println!("Installing updated `cargo-mobile2`...");
83        let repo_c = repo.clone();
84        duct::cmd("cargo", ["install", "--force", "--path"])
85            .dup_stdio()
86            .before_spawn(move |cmd| {
87                cmd.arg(repo_c.path());
88                cmd.args(["--no-default-features", "--features"]);
89                cmd.arg(ENABLED_FEATURES.join(" "));
90                Ok(())
91            })
92            .run()
93            .map_err(Error::InstallFailed)?;
94        fs::remove_file(&marker).map_err(|cause| Error::MarkerDeleteFailed {
95            path: marker.to_owned(),
96            cause,
97        })?;
98        log::info!("deleted marker file at {:?}", marker);
99        "installed new version of `cargo-mobile2`"
100    } else {
101        "`cargo-mobile2` is already up-to-date"
102    };
103    let details = util::unwrap_either(
104        repo.latest_subject()
105            .map(util::format_commit_msg)
106            .map_err(|err| format!("But we failed to get the latest commit message: {err}")),
107    );
108    Report::victory(msg, details).print(wrapper);
109    Ok(())
110}