packages(debian): rm stale /etc/apt/sources.list.d/eza.list + gierens.gpg left by the pre-fix run that used the now-dead apt.fury.io PPA — otherwise 'apt-get update' keeps hitting the 401 forever even though we now install eza from GH releases
195 lines
8.5 KiB
Bash
Executable File
195 lines
8.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# 10-packages — core CLI utilities, per distro.
|
|
|
|
step_name="packages"
|
|
step_desc="git byobu ufw mosh btop eza fzf ripgrep bat zoxide jq fd ..."
|
|
step_run="run_packages"
|
|
|
|
# Tools we want everywhere (names canonical, mapped per-distro).
|
|
PKGS_COMMON=(
|
|
git byobu ufw mosh btop fzf ripgrep fd bat dust procs jq yq tree ncdu duf
|
|
tldr httpie rsync lazygit neovim curl unzip less starship eza zoxide openssh
|
|
)
|
|
|
|
run_packages() {
|
|
log "installing core packages ($DISTRO)"
|
|
case "$DISTRO" in
|
|
arch) _pkg_arch ;;
|
|
debian) _pkg_debian ;;
|
|
esac
|
|
}
|
|
|
|
# ── arch ─────────────────────────────────────────────────────────────────────
|
|
# official-repo packages (verified in extra/core). Any name not in the official
|
|
# repos would abort the whole `pacman --needed` batch, so keep this list clean
|
|
# and route AUR-only tools through _install_aur_packages instead.
|
|
ARCH_OFFICIAL=(git ufw mosh btop fzf ripgrep fd bat dust procs jq yq tree
|
|
ncdu duf tldr httpie rsync lazygit neovim curl unzip less starship
|
|
eza zoxide openssh)
|
|
|
|
# AUR-only packages (not in official repos) — installed through yay after build.
|
|
ARCH_AUR=(byobu)
|
|
|
|
_pkg_arch() {
|
|
sudo_ pacman -Sy --noconfirm --needed base-devel openssh
|
|
sudo_ pacman -Sy --noconfirm --needed "${ARCH_OFFICIAL[@]}"
|
|
_install_yay
|
|
_install_aur_packages
|
|
# fd/bat ship with their real names on arch — no shims needed
|
|
}
|
|
|
|
_install_yay() {
|
|
if command -v yay >/dev/null 2>&1; then ok "yay already installed"; return; fi
|
|
log "building yay from AUR (requires a non-root sudoer)"
|
|
if (( EUID == 0 )) && [[ -z "${TARGET_USER:-${SUDO_USER:-}}" ]]; then
|
|
err "running as root with no target/sudo user — yay cannot build. Run the create-user step first, or re-run bootstrap as a normal user with sudo."
|
|
return 1
|
|
fi
|
|
local tmp; tmp="$(mktemp -d)"
|
|
# chown the build dir so the non-root build user can write into it
|
|
if (( EUID == 0 )); then
|
|
chown -R "${TARGET_USER:-${SUDO_USER}}" "$tmp"
|
|
fi
|
|
as_user git clone --depth 1 https://aur.archlinux.org/yay.git "$tmp/yay"
|
|
( cd "$tmp/yay" && as_user makepkg -si --noconfirm )
|
|
rm -rf "$tmp"
|
|
command -v yay >/dev/null 2>&1 && ok "yay installed" || warn "yay install may need a manual pass"
|
|
}
|
|
|
|
_install_aur_packages() {
|
|
[[ "${#ARCH_AUR[@]}" -eq 0 ]] && return
|
|
if ! command -v yay >/dev/null 2>&1; then
|
|
warn "yay not available — skipping AUR packages: ${ARCH_AUR[*]}"
|
|
return
|
|
fi
|
|
log "installing AUR-only packages: ${ARCH_AUR[*]}"
|
|
# yay -S as the non-root target user (makepkg refuses root; TARGET_USER via as_user).
|
|
as_user yay -S --noconfirm --needed "${ARCH_AUR[@]}" \
|
|
|| warn "some AUR packages failed: ${ARCH_AUR[*]} (install manually with: yay -S ${ARCH_AUR[*]})"
|
|
}
|
|
|
|
# ── debian/ubuntu ────────────────────────────────────────────────────────────
|
|
_pkg_debian() {
|
|
sudo_ apt-get update -y
|
|
sudo_ apt-get install -y ca-certificates curl gnupg lsb-release unzip less \
|
|
git byobu ufw mosh btop fzf ripgrep jq tree ncdu rsync neovim curl \
|
|
openssh-server sudo
|
|
|
|
# rename packages: fd -> fdfind, bat -> batcat (fix via aliases in zsh)
|
|
sudo_ apt-get install -y fdfind batcat 2>/dev/null || true
|
|
|
|
# eza: the old apt.fury.io/gierens PPA is dead (401 Unauthorized). Install the
|
|
# single binary from the upstream GitHub release tarball into /usr/local/bin
|
|
# (system-wide — works for root and every sudo user; no HOME dependency).
|
|
# Remove a stale eza.list left by the old (pre-fix) run that used the now-dead
|
|
# apt.fury.io PPA — otherwise 'apt-get update' keeps hitting the 401 forever.
|
|
sudo_ rm -f /etc/apt/sources.list.d/eza.list /etc/apt/keyrings/gierens.gpg
|
|
if ! command -v eza >/dev/null 2>&1; then
|
|
local eza_arch; case "$ARCH" in
|
|
amd64) eza_arch=x86_64-unknown-linux-gnu ;;
|
|
arm64) eza_arch=aarch64-unknown-linux-gnu ;;
|
|
*) eza_arch="${ARCH}-unknown-linux-gnu" ;;
|
|
esac
|
|
local url="https://github.com/eza-community/eza/releases/latest/download/eza_${eza_arch}.tar.gz"
|
|
local tmp; tmp="$(mktemp -d)"
|
|
if wget -qO "$tmp/eza.tgz" "$url" && tar xzf "$tmp/eza.tgz" -C "$tmp"; then
|
|
sudo_ install -m 0755 "$tmp/eza" /usr/local/bin/eza
|
|
else
|
|
warn "eza download failed ($url)"
|
|
fi
|
|
rm -rf "$tmp"
|
|
fi
|
|
|
|
# starship: official installer. NOTE — scrub $ARCH/$PLATFORM from the env first:
|
|
# the installer reuses a pre-set ARCH (our lib/detect.sh exports ARCH=amd64) and
|
|
# skips its own amd64->x86_64 mapping, yielding an unsupported 'amd64-unknown-linux-
|
|
# musl' target ('builds for amd64-unknown-linux-musl are not yet available').
|
|
# Default bin dir is /usr/local/bin (system-wide).
|
|
if ! command -v starship >/dev/null 2>&1; then
|
|
curl -sS https://starship.rs/install.sh \
|
|
| env -u ARCH -u PLATFORM sh -s -- -y || warn "starship install failed"
|
|
fi
|
|
|
|
# zoxide: official installer. Install system-wide (/usr/local/bin) instead of the
|
|
# default ~/.local/bin — when run as root the default lands in /root (wrong user
|
|
# for the create-user path) and isn't on $PATH; /usr/local/bin is on PATH for all.
|
|
if ! command -v zoxide >/dev/null 2>&1; then
|
|
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh \
|
|
| env -u ARCH sh -s -- --bin-dir /usr/local/bin --man-dir /usr/local/share/man \
|
|
|| warn "zoxide install failed"
|
|
fi
|
|
|
|
# yq: direct binary from mikefarah/yq releases (stable URL)
|
|
if ! command -v yq >/dev/null 2>&1; then
|
|
local suffix="amd64"; [[ "$ARCH" == "arm64" ]] && suffix="arm64"
|
|
sudo_ wget -qO /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${suffix}" \
|
|
&& sudo_ chmod +x /usr/local/bin/yq || warn "yq install failed"
|
|
fi
|
|
|
|
# tldr on debian: python3 package if present, else skip (npm-based out of scope here)
|
|
if ! command -v tldr >/dev/null 2>&1; then
|
|
sudo_ apt-get install -y tldr 2>/dev/null || warn "tldr not packaged on this release — skipped (install via npm later)"
|
|
fi
|
|
|
|
# rest via GitHub release tarballs where missing (best-effort, arch auto-detected)
|
|
_gh_release_binary bootandy/dust dust
|
|
_gh_release_binary muesli/duf duf
|
|
_gh_release_binary dalance/procs procs
|
|
_gh_release_binary jesseduffield/lazygit lazygit
|
|
# fd/bat on debian come from apt as fdfind/batcat (shimmed below)
|
|
|
|
_apt_aliases_fixup
|
|
}
|
|
|
|
|
|
# generic best-effort: fetch latest release archive matching host arch,
|
|
# extract a single binary into /usr/local/bin. Warns and continues on failure.
|
|
_gh_release_binary() {
|
|
local repo="$1" binname="$2"
|
|
command -v "$binname" >/dev/null 2>&1 && { ok "$binname already present"; return; }
|
|
local api="https://api.github.com/repos/$repo/releases/latest"
|
|
local archpat
|
|
case "$ARCH" in
|
|
amd64) archpat='(x86_64|amd64)' ;;
|
|
arm64) archpat='(aarch64|arm64)' ;;
|
|
*) archpat="$ARCH" ;;
|
|
esac
|
|
local url url_line
|
|
url_line=$(curl -fsSL "$api" \
|
|
| grep -oE '"browser_download_url":\s*"[^"]+"' \
|
|
| sed -E 's/.*"([^"]+)"/\1/' \
|
|
| grep -Ei "\\.(tar\\.gz|zip)$" \
|
|
| grep -Ei "$archpat" \
|
|
| grep -Ei 'linux|musl|gnu|unknown' \
|
|
| grep -viE 'sig|sha|checksum|deb|rpm|apk|msi|darwin|windows' \
|
|
| head -1)
|
|
url="$url_line"
|
|
if [[ -z "$url" ]]; then warn "could not resolve $binname release asset for $ARCH — skipped"; return; fi
|
|
local tmp; tmp="$(mktemp -d)"
|
|
if ! curl -fsSL "$url" -o "$tmp/asset"; then warn "download $binname failed"; rm -rf "$tmp"; return; fi
|
|
case "$url" in
|
|
*.tar.gz|*.tgz) tar -xzf "$tmp/asset" -C "$tmp" ;;
|
|
*.zip) unzip -oq "$tmp/asset" -d "$tmp" ;;
|
|
esac
|
|
local found
|
|
found=$(find "$tmp" -type f -name "$binname" -perm -u+x | head -1)
|
|
[[ -z "$found" ]] && found=$(find "$tmp" -type f -name "$binname" | head -1)
|
|
if [[ -n "$found" ]]; then
|
|
sudo_ install -m 0755 "$found" "/usr/local/bin/$binname"
|
|
ok "$binname installed from GitHub release"
|
|
else
|
|
warn "$binname binary not found in archive — skipped"
|
|
fi
|
|
rm -rf "$tmp"
|
|
}
|
|
|
|
# fd/bat: apt ships fdfind/batcat on debian; create canonical symlinks in ~/.local/bin.
|
|
_apt_aliases_fixup() {
|
|
local bin="$HOME/.local/bin"; mkdir -p "$bin"
|
|
if command -v fdfind >/dev/null 2>&1 && ! command -v fd >/dev/null 2>&1; then
|
|
ln -sf "$(command -v fdfind)" "$bin/fd"
|
|
fi
|
|
if command -v batcat >/dev/null 2>&1 && ! command -v bat >/dev/null 2>&1; then
|
|
ln -sf "$(command -v batcat)" "$bin/bat"
|
|
fi
|
|
} |