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}