#!/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. # # fastfetch was here until 2026-08-14 and was removed after it stopped a real # install. It is the only one of these with no source but a third-party PPA on # Ubuntu 24.04 and older, and the failure was in the half that was not guarded: # a PPA that ADDS cleanly but carries no package for the running codename gets # past the `|| skip` and dies on the install instead. A neofetch clone is not # worth a branch in a script that has to survive on machines nobody has seen. tools_default() { echo lazydocker lazygit starship; } # The command that proves a tool is already here. Same as the tool name for all # three 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 ;; *) 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 } # ----------------------------------------------------------------------------- # 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 }