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}