Skip to main content

git_stk/
upgrade.rs

1use std::io::{self, BufRead, Write};
2use std::process::Command;
3
4use anyhow::{Context, Result, bail};
5use axoupdater::AxoUpdater;
6
7/// Source repository used for `--head` installs.
8const REPO_URL: &str = "https://github.com/lararosekelley/git-stk";
9
10pub fn upgrade(head: bool, force: bool, yes: bool) -> Result<()> {
11    if head {
12        upgrade_to_head(yes)
13    } else {
14        upgrade_to_latest_release(force)
15    }
16}
17
18fn upgrade_to_head(yes: bool) -> Result<()> {
19    println!("--head builds and installs the latest unreleased commit from {REPO_URL}");
20    println!("HEAD is a pre-release snapshot: it may be broken or untested");
21
22    if !yes && !confirm("continue? [y/N] ")? {
23        println!("upgrade cancelled");
24        return Ok(());
25    }
26
27    let status = Command::new("cargo")
28        .args(["install", "--git", REPO_URL, "--locked", "git-stk"])
29        .status()
30        .context("failed to run cargo; --head requires a Rust toolchain")?;
31
32    if !status.success() {
33        bail!("cargo install exited with status {status}");
34    }
35
36    println!("installed git-stk from HEAD");
37    println!("to return to the latest release, run: git stk upgrade --force");
38    Ok(())
39}
40
41fn upgrade_to_latest_release(force: bool) -> Result<()> {
42    let mut updater = AxoUpdater::new_for("git-stk");
43    updater
44        .load_receipt()
45        .map_err(anyhow::Error::from)
46        .context(
47            "no usable install receipt found; if git-stk was installed with cargo, \
48             upgrade with `cargo install git-stk --locked` instead",
49        )?;
50    updater.always_update(force);
51
52    match updater
53        .run_sync()
54        .context("failed to upgrade to the latest release")?
55    {
56        Some(result) => {
57            let old = result
58                .old_version
59                .map(|version| version.to_string())
60                .unwrap_or_else(|| "unknown".to_owned());
61            println!("upgraded git-stk {old} -> {}", result.new_version);
62        }
63        None => println!(
64            "git-stk {} is already the latest release",
65            env!("CARGO_PKG_VERSION")
66        ),
67    }
68
69    Ok(())
70}
71
72fn confirm(prompt: &str) -> Result<bool> {
73    print!("{prompt}");
74    io::stdout().flush().context("failed to flush stdout")?;
75
76    let mut answer = String::new();
77    io::stdin()
78        .lock()
79        .read_line(&mut answer)
80        .context("failed to read confirmation")?;
81
82    Ok(matches!(answer.trim(), "y" | "Y" | "yes" | "Yes" | "YES"))
83}