install what is missing and keep what is there, per package manager
lib/packages.sh, and section 2 wired to it.
The rule it exists to enforce: `apt-get install <present-package>` is not a
no-op, it upgrades the package if the repository has a newer one. On a machine
somebody already uses that silently moves a version they chose, and a setup
script is the last thing that should do that behind their back. pkg_install
queries the package database first and names only the genuinely absent packages
on the command line — a package already installed is never passed to apt at all.
It also says so out loud, every time, because a provisioning run should not be
opaque about what it is doing to the machine:
:: Core packages — installs what is missing, keeps what you already have
already here: curl ca-certificates gnupg git jq …
to install: btop tmux
Section 2's flat list of 19 is now pkgs_core(), split per package manager rather
than through a canonical-name table with overrides. The names genuinely disagree
(build-essential/base-devel, fd-find/fd) and three of them are not packages
elsewhere at all — apt-transport-https, lsb-release and software-properties-common
are apt concepts that exist to let later steps add the Docker repo and the
fastfetch PPA. A `case $PM` shows what each system actually gets, in one place.
Of those 19, six are load-bearing and the rest are the environment. Only
build-essential reaches beyond itself: it is a meta-package, so on a box with a
pinned gcc it pulls the distribution default alongside. Noted where it is
declared; it is the first thing to move out of core if that ever bites.
apt-get upgrade stays, but as its own announced step — it is the one place that
deliberately moves versions, rather than something that happens as a side effect
of asking for a tool.
DEBIAN_FRONTEND=noninteractive and NEEDRESTART_MODE=a now live inside the
helpers. needrestart has been on by default since Ubuntu 22.04 and stops to ask
which services to restart, which is how an unattended run ends up silently
waiting for a keypress.
dpkg-query on the status field rather than `dpkg -s`, which also succeeds for a
package removed but leaving its config behind — that state would read as present
and never be reinstalled.
Verified against this host's real dpkg database: all 19 report present, and a
mixed list correctly passes only the absent ones through.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,8 @@ PROGRESS_FILE="$SCRIPT_DIR/.setup-progress"
|
||||
# whole script in. Definitions only; nothing in there acts.
|
||||
# shellcheck source=lib/base.sh
|
||||
source "$SCRIPT_DIR/lib/base.sh"
|
||||
# shellcheck source=lib/packages.sh
|
||||
source "$SCRIPT_DIR/lib/packages.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.
|
||||
@@ -76,14 +78,16 @@ USER_HOME="/home/$USERNAME"
|
||||
|
||||
step "System Update & Essentials"
|
||||
if ! skip; then
|
||||
info "Updating system packages..."
|
||||
apt-get update -y && apt-get upgrade -y
|
||||
info "Refreshing the package index..."
|
||||
pkg_refresh
|
||||
|
||||
info "Installing essential packages..."
|
||||
apt-get install -y \
|
||||
curl wget git zip unzip build-essential btop net-tools \
|
||||
software-properties-common jq htop tree ripgrep fd-find tmux \
|
||||
apt-transport-https ca-certificates gnupg lsb-release
|
||||
# The one place that deliberately moves versions of things already installed.
|
||||
# Everything else in this script only ever adds what is absent.
|
||||
info "Upgrading installed packages..."
|
||||
pkg_upgrade_all
|
||||
|
||||
# shellcheck disable=SC2046 # word splitting is how the list is passed
|
||||
pkg_install "Core packages" $(pkgs_core)
|
||||
|
||||
ok "System updated and essentials installed"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user