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) => write!(
44                f,
45                "Failed to install new version of `cargo-mobile2`: {}",
46                err
47            ),
48            Self::MarkerDeleteFailed { path, cause } => {
49                write!(f, "Failed to delete marker file at {:?}: {}", path, cause)
50            }
51        }
52    }
53}
54
55pub(crate) fn cargo_mobile_repo() -> Result<Repo, util::NoHomeDir> {
56    Repo::checkouts_dir("cargo-mobile2")
57}
58
59pub(crate) fn updating_marker_path(repo: &Repo) -> PathBuf {
60    repo.path()
61        .parent()
62        .expect("developer error: repo path had no parent")
63        .parent()
64        .expect("developer error: checkouts dir had no parent")
65        .join(".updating")
66}
67
68pub fn update(wrapper: &TextWrapper) -> Result<(), Error> {
69    let repo = cargo_mobile_repo().map_err(Error::NoHomeDir)?;
70    let marker = updating_marker_path(&repo);
71    let marker_exists = marker.is_file();
72    if marker_exists {
73        log::info!("marker file present at {:?}", marker);
74    } else {
75        log::info!("no marker file present at {:?}", marker);
76    }
77    let msg = if marker_exists || repo.status().map_err(Error::StatusFailed)?.stale() {
78        File::create(&marker).map_err(|cause| Error::MarkerCreateFailed {
79            path: marker.to_owned(),
80            cause,
81        })?;
82        repo.update("https://github.com/tauri-apps/cargo-mobile2", "dev")
83            .map_err(Error::UpdateFailed)?;
84        println!("Installing updated `cargo-mobile2`...");
85        let repo_c = repo.clone();
86        duct::cmd("cargo", ["install", "--force", "--path"])
87            .dup_stdio()
88            .before_spawn(move |cmd| {
89                cmd.arg(repo_c.path());
90                cmd.args(["--no-default-features", "--features"]);
91                cmd.arg(ENABLED_FEATURES.join(" "));
92                Ok(())
93            })
94            .run()
95            .map_err(Error::InstallFailed)?;
96        fs::remove_file(&marker).map_err(|cause| Error::MarkerDeleteFailed {
97            path: marker.to_owned(),
98            cause,
99        })?;
100        log::info!("deleted marker file at {:?}", marker);
101        "installed new version of `cargo-mobile2`"
102    } else {
103        "`cargo-mobile2` is already up-to-date"
104    };
105    let details = util::unwrap_either(
106        repo.latest_subject()
107            .map(util::format_commit_msg)
108            .map_err(|err| format!("But we failed to get the latest commit message: {}", err)),
109    );
110    Report::victory(msg, details).print(wrapper);
111    Ok(())
112}