diff --git a/scripts/setup/machine-setup/lib/tools.sh b/scripts/setup/machine-setup/lib/tools.sh new file mode 100644 index 00000000..f13874d6 --- /dev/null +++ b/scripts/setup/machine-setup/lib/tools.sh @@ -0,0 +1,129 @@ +#!/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=() + for tool in "$@"; do + if tool_is_installed "$tool"; then present+=("$tool"); else missing+=("$tool"); fi + done + + info "$label — installs what is missing, keeps what you already have" + ((${#present[@]})) && echo " already here: ${present[*]}" + + if ((${#missing[@]} == 0)); then + echo " to install: nothing, all present" + return 0 + fi + + echo " to install: ${missing[*]}" + for tool in "${missing[@]}"; do + info " installing ${tool}..." + "tool_install_${tool}" + done +} diff --git a/scripts/setup/machine-setup/machine-setup.sh b/scripts/setup/machine-setup/machine-setup.sh index da456ccd..d2c0ea06 100755 --- a/scripts/setup/machine-setup/machine-setup.sh +++ b/scripts/setup/machine-setup/machine-setup.sh @@ -20,6 +20,8 @@ PROGRESS_FILE="$SCRIPT_DIR/.setup-progress" source "$SCRIPT_DIR/lib/base.sh" # shellcheck source=lib/packages.sh source "$SCRIPT_DIR/lib/packages.sh" +# shellcheck source=lib/tools.sh +source "$SCRIPT_DIR/lib/tools.sh" # Trap errors with context. Installed here rather than in lib/base.sh, because # that file is definitions only and a trap is a side effect on whoever sources it. @@ -89,34 +91,26 @@ if ! skip; then # shellcheck disable=SC2046 # word splitting is how the list is passed pkg_install "Core packages" $(pkgs_core) - ok "System updated and essentials installed" + ok "System updated and core packages in place" + SUMMARY+=("System packages updated, core packages installed") + step_ok +fi - # lazydocker - info "Installing lazydocker..." - curl -fsSL https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | DIR=/usr/local/bin bash - ok "lazydocker installed" +# ============================================================================= +# 2b. Command-line tools +# ============================================================================= +# +# Separate from the packages above because they are a different thing: upstream +# binaries on their own release cadence, not anything the distribution ships. +# Lumping them in made a run look like it was installing system packages and +# then start downloading tarballs unannounced. - # lazygit - info "Installing lazygit..." - LAZYGIT_VERSION=$(curl -fsSL "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | jq -r '.tag_name' | tr -d 'v') - curl -fsSLo /tmp/lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz" - tar -C /usr/local/bin -xzf /tmp/lazygit.tar.gz lazygit - rm -f /tmp/lazygit.tar.gz - ok "lazygit installed" +step "Command-line tools" +if ! skip; then + # shellcheck disable=SC2046 # word splitting is how the list is passed + tools_install "Command-line tools" $(tools_default) - # starship - info "Installing starship..." - curl -fsSL https://starship.rs/install.sh | sh -s -- -y - ok "starship installed" - - # fastfetch - info "Installing fastfetch..." - add-apt-repository -y ppa:zhangsongcui3371/fastfetch > /dev/null 2>&1 || true - apt-get update -y > /dev/null 2>&1 - apt-get install -y fastfetch - ok "fastfetch installed" - - SUMMARY+=("System packages updated and essentials installed") + SUMMARY+=("Command-line tools: $(tools_default)") step_ok fi