1use std::process::ExitCode;
2
3const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
4const REPO_OWNER: &str = "StrangeDaysTech";
5const REPO_NAME: &str = "arborist-cli";
6
7pub fn run(check_only: bool) -> ExitCode {
8 println!("arborist-cli v{CURRENT_VERSION}");
9
10 if is_cargo_installed() {
11 eprintln!(
12 "hint: this binary appears to be installed via cargo. \
13 To update, run: cargo install arborist-cli"
14 );
15 if check_only {
16 return check_latest_version();
17 }
18 return ExitCode::SUCCESS;
19 }
20
21 if check_only {
22 return check_latest_version();
23 }
24
25 perform_update()
26}
27
28fn check_latest_version() -> ExitCode {
29 print!("Checking for updates... ");
30
31 match self_update::backends::github::Update::configure()
32 .repo_owner(REPO_OWNER)
33 .repo_name(REPO_NAME)
34 .bin_name("arborist")
35 .current_version(CURRENT_VERSION)
36 .build()
37 {
38 Ok(updater) => match updater.get_latest_release() {
39 Ok(release) => {
40 let latest = &release.version;
41 if latest == CURRENT_VERSION {
42 println!("already up to date.");
43 ExitCode::SUCCESS
44 } else {
45 println!("v{latest} available (current: v{CURRENT_VERSION})");
46 println!("Run `arborist update` to install it.");
47 ExitCode::SUCCESS
48 }
49 }
50 Err(e) => {
51 eprintln!("failed to check for updates: {e}");
52 ExitCode::from(2)
53 }
54 },
55 Err(e) => {
56 eprintln!("failed to configure updater: {e}");
57 ExitCode::from(2)
58 }
59 }
60}
61
62fn perform_update() -> ExitCode {
63 println!("Checking for updates...");
64
65 let result = self_update::backends::github::Update::configure()
66 .repo_owner(REPO_OWNER)
67 .repo_name(REPO_NAME)
68 .bin_name("arborist")
69 .current_version(CURRENT_VERSION)
70 .show_download_progress(true)
71 .show_output(false)
72 .no_confirm(true)
73 .build();
74
75 match result {
76 Ok(updater) => match updater.update() {
77 Ok(status) => {
78 if status.updated() {
79 println!("Updated to v{}.", status.version());
80 } else {
81 println!("Already up to date (v{CURRENT_VERSION}).");
82 }
83 ExitCode::SUCCESS
84 }
85 Err(e) => {
86 eprintln!("error: update failed: {e}");
87 ExitCode::from(2)
88 }
89 },
90 Err(e) => {
91 eprintln!("error: failed to configure updater: {e}");
92 ExitCode::from(2)
93 }
94 }
95}
96
97fn is_cargo_installed() -> bool {
100 let Ok(exe) = std::env::current_exe() else {
101 return false;
102 };
103 let path = exe.to_string_lossy();
104 path.contains(".cargo/bin") || path.contains(".cargo\\bin")
105}