Files
platform/scripts/setup/machine-setup/lib/tools.sh
T
pastilhasandClaude Opus 5 f896d4882f one section per concern, each announced and confirmed before it acts
Three sections where there were two, and none of them touches the machine until
you say so:

  2. System update      upgrades what is already installed
  3. Core utils         what the distribution provides
  4. Command-line tools lazydocker, lazygit, starship, fastfetch

The split matters because these are different kinds of change and deserve
separate answers. System update is the only step in the whole script that moves
versions of software already on the machine; core utils only ever adds what is
absent; and the four tools are upstream binaries the distribution does not ship
at all. Previously the update and the core packages were one step and the tools
were tacked onto the end of it, so agreeing to "essentials" meant agreeing to all
three at once.

Every section now prints what it will install and what it is leaving alone, then
asks. Enter means yes — unlike the machine-role question, which has no default,
because these are "do the thing you already asked for" and making twenty of them
require a deliberate keystroke would train people to hold the y key down.
ASSUME_YES=1 answers all of them for an unattended run, and EOF fails with that
named rather than spinning.

Refusing is recorded rather than glossed: LAST_SKIPPED feeds the summary, so a
declined section reads "Core utils: SKIPPED by request — cowsay neofetch" instead
of quietly reporting nothing installed.

Nothing to install means no prompt at all — there is nothing to agree to.

announce_plan takes the array NAMES rather than their contents, because once a
list has been through word splitting an empty one cannot be told from a missing
one.

Verified all three paths: accept, refuse, and nothing-to-do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 17:37:31 +00:00

127 lines
4.8 KiB
Bash

#!/bin/bash
# =============================================================================
# machine-setup — command-line tools that do not come from the distribution
# =============================================================================
#
# Definitions only, like the other lib/ files.
#
# These four were buried inside "System Update & Essentials", after the package
# install and with no announcement, so a run appeared to be installing system
# packages and then started downloading tarballs and printing a shell tutorial.
# They are their own concern: upstream binaries, fetched from upstream, on their
# own release cadence.
#
# Each one is checked before it is fetched. The original re-ran every installer
# on every run — which is how a machine that already had starship got it
# reinstalled, along with its "add this to your ~/.zshrc" instructions, which we
# do not want because this script writes the shell config itself.
[[ -n "${MACHINE_SETUP_TOOLS_LOADED:-}" ]] && return 0
MACHINE_SETUP_TOOLS_LOADED=1
# The set installed on every machine, in the order they are fetched.
tools_default() { echo lazydocker lazygit starship fastfetch; }
# The command that proves a tool is already here. Same as the tool name for all
# four today, but kept as a mapping because that is not a rule — a package and
# the binary it provides disagree often enough (fd-find/fdfind) to be worth the
# indirection.
tool_command() {
case "$1" in
lazydocker) echo lazydocker ;;
lazygit) echo lazygit ;;
starship) echo starship ;;
fastfetch) echo fastfetch ;;
*) echo "$1" ;;
esac
}
tool_is_installed() { command -v "$(tool_command "$1")" &>/dev/null; }
# -----------------------------------------------------------------------------
# The installers
# -----------------------------------------------------------------------------
tool_install_lazydocker() {
curl -fsSL https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh |
DIR=/usr/local/bin bash
}
# The one that was actually broken on arm64: the asset name was hardcoded to
# x86_64, so an arm machine downloaded a 404 and tar failed halfway through the
# run. lazygit spells the architectures x86_64 and arm64, which is neither of the
# two spellings ARCH uses, hence the mapping.
tool_install_lazygit() {
local version asset url
case "$ARCH" in
amd64) asset="x86_64" ;;
arm64) asset="arm64" ;;
esac
version="$(curl -fsSL https://api.github.com/repos/jesseduffield/lazygit/releases/latest | jq -r '.tag_name')"
# Strip only the leading v. The original used `tr -d 'v'`, which deletes every
# v in the string and would mangle any tag that had one anywhere else.
version="${version#v}"
[[ -n "$version" ]] || {
warn "could not read the latest lazygit version — skipping"
return 0
}
url="https://github.com/jesseduffield/lazygit/releases/download/v${version}/lazygit_${version}_Linux_${asset}.tar.gz"
curl -fsSLo /tmp/lazygit.tar.gz "$url"
tar -C /usr/local/bin -xzf /tmp/lazygit.tar.gz lazygit
rm -f /tmp/lazygit.tar.gz
}
# Quiet on purpose. The installer ends by printing how to add starship to bash,
# zsh, ion, tcsh and xonsh — five shells' worth of instructions for a step that
# already writes the zsh config itself. Errors still come through.
tool_install_starship() {
curl -fsSL https://starship.rs/install.sh | sh -s -- -y -b /usr/local/bin >/dev/null
}
# A distribution package everywhere, but not always one the distribution ships:
# Ubuntu only picked fastfetch up in 24.10, so on noble and older the PPA is the
# only source. Checked rather than assumed, so the PPA stops being added the
# moment the archive has it.
tool_install_fastfetch() {
if [[ "$PM" == "apt" ]] && ! apt-cache policy fastfetch 2>/dev/null | grep -q 'Candidate: [0-9]'; then
info " fastfetch is not in this release's archive — adding the upstream PPA"
add-apt-repository -y ppa:zhangsongcui3371/fastfetch >/dev/null 2>&1 ||
{
warn "could not add the fastfetch PPA — skipping"
return 0
}
pkg_refresh >/dev/null 2>&1
fi
pkg_install_now fastfetch
}
# -----------------------------------------------------------------------------
# Acting
# -----------------------------------------------------------------------------
# Announce the section, then fetch only what is absent — same contract and same
# output shape as pkg_install, so the two read alike in a transcript.
tools_install() {
local label="$1"
shift
local tool
local -a missing=() present=()
LAST_SKIPPED=()
for tool in "$@"; do
if tool_is_installed "$tool"; then present+=("$tool"); else missing+=("$tool"); fi
done
LAST_INSTALLED=("${missing[@]}")
LAST_KEPT=("${present[@]}")
announce_plan "$label" present missing || return 0
for tool in "${missing[@]}"; do
info " installing ${tool}..."
"tool_install_${tool}"
done
}