Skip to main content

git_stk/
upgrade.rs

1use std::process::Command;
2
3use anyhow::{Context, Result, bail};
4use axoupdater::AxoUpdater;
5
6use crate::prompt::confirm;
7
8/// Source repository used for `--head` installs.
9const REPO_URL: &str = "https://github.com/lararosekelley/git-stk";
10
11pub fn upgrade(head: bool, force: bool, yes: bool) -> Result<()> {
12    if head {
13        upgrade_to_head(yes)
14    } else {
15        upgrade_to_latest_release(force)
16    }
17}
18
19fn upgrade_to_head(yes: bool) -> Result<()> {
20    println!("--head builds and installs the latest unreleased commit from {REPO_URL}");
21    println!("HEAD is a pre-release snapshot: it may be broken or untested");
22
23    if !yes && !confirm("continue? [y/N] ")? {
24        println!("upgrade cancelled");
25        return Ok(());
26    }
27
28    let status = Command::new("cargo")
29        .args(["install", "--git", REPO_URL, "--locked", "git-stk"])
30        .status()
31        .context("failed to run cargo; --head requires a Rust toolchain")?;
32
33    if !status.success() {
34        bail!("cargo install exited with status {status}");
35    }
36
37    println!("installed git-stk from HEAD");
38    println!("to return to the latest release, run: git stk upgrade --force");
39    refresh_assets_with_new_binary();
40    Ok(())
41}
42
43/// Re-render generated assets (man page) after an upgrade, using the newly
44/// installed binary so the assets match its version rather than the running
45/// (pre-upgrade) one. Failure is a warning, not an error: the upgrade itself
46/// already succeeded.
47fn refresh_assets_with_new_binary() {
48    let refreshed = Command::new("git-stk")
49        .args(["setup", "--refresh"])
50        .status()
51        .map(|status| status.success())
52        .unwrap_or(false);
53
54    if !refreshed {
55        eprintln!("warning: failed to refresh generated assets; run `git stk setup` manually");
56    }
57}
58
59fn upgrade_to_latest_release(force: bool) -> Result<()> {
60    let mut updater = AxoUpdater::new_for("git-stk");
61    updater
62        .load_receipt()
63        .map_err(anyhow::Error::from)
64        .context(
65            "no usable install receipt found; if git-stk was installed with cargo, \
66             upgrade with `cargo install git-stk --locked` instead",
67        )?;
68    updater.always_update(force);
69
70    match updater
71        .run_sync()
72        .context("failed to upgrade to the latest release")?
73    {
74        Some(result) => {
75            let old = result
76                .old_version
77                .map(|version| version.to_string())
78                .unwrap_or_else(|| "unknown".to_owned());
79            println!("upgraded git-stk {old} -> {}", result.new_version);
80            refresh_assets_with_new_binary();
81        }
82        None => println!(
83            "git-stk {} is already the latest release",
84            env!("CARGO_PKG_VERSION")
85        ),
86    }
87
88    Ok(())
89}