Fix first real-hardware install issues from tinkerpad run

- bootstrap: install bash before fetch (ash-only base installs)
- bootstrap/deploy: correct URL (drop /repo prefix, webroot is /srv/repo)
- 01_core: remove bash (bootstrap now handles it)
- ce-base/minimal/basic: BusyBox-compatible df check (drop --output=avail)
- ce-common: add ensure_testing_repo + install_pkg_testing
- 12_access: espeakup + espeakup-openrc from edge/testing
- 05_fonts: nerd-fonts → nerd-fonts-all (meta-package blocks by design)
- 06_utils: tealdeer + bash-completion from edge/testing
- 07_journal: jrnl test checks ~/.local/bin/jrnl (pipx not in PATH during install)
- 11_wiki: arch-aware CE_REPO (${ARCH} replaces hardcoded amd64); Forgejo TODO updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
John A. Hoeven 2026-06-11 21:55:21 +02:00
commit e1ee30812f
12 changed files with 57 additions and 31 deletions

View file

@ -2,22 +2,21 @@
# Created by John A. Hoeven with the ethical assistance of Claude AI
# ---------------------------------------------------------------------------
# bootstrap.sh
# Served at: http://192.168.0.138/repo/scripts/alpine-ceos-installer/bootstrap.sh
# Served at: http://192.168.0.138/scripts/alpine-ceos-installer/bootstrap.sh
# Version: v0.0.1 | Status: DEVELOPMENT
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Run this on tinkerpad to download the full CE OS installer from workbench.
# Usage: wget http://192.168.0.138/repo/scripts/alpine-ceos-installer/bootstrap.sh
# Usage: wget http://192.168.0.138/scripts/alpine-ceos-installer/bootstrap.sh
# bash bootstrap.sh
#
# TODO — Forgejo: when git.jahnet.lan is deployed, replace the wget block
# below with these three lines and delete the rest of this file:
# TODO — Forgejo: replace the wget block below with these three lines and delete the rest of this file:
# doas apk add git
# git clone -b dev http://git.jahnet.lan/john/ceos-alpine-installer.git
# git clone -b dev https://git.jhoeven.net/giovannino/ceos-alpine-installer.git
# cd ceos-alpine-installer && bash ce-install.sh
# ---------------------------------------------------------------------------
BASE="http://192.168.0.138/repo/scripts/alpine-ceos-installer"
BASE="http://192.168.0.138/scripts/alpine-ceos-installer"
DEST="/tmp/ceos-installer-$(date +%Y%m%d%H%M%S)"
echo "CE OS Alpine Installer — Bootstrap"
@ -26,6 +25,11 @@ echo "Source: ${BASE}"
echo "Dest: ${DEST}"
echo ""
if ! command -v bash > /dev/null 2>&1; then
echo "Installing bash..."
doas apk add bash || { echo "ERROR: could not install bash"; exit 1; }
fi
mkdir -p \
"${DEST}/lib/base" \
"${DEST}/lib/minimal" \

View file

@ -35,7 +35,7 @@ phase_preflight() {
run_test "bash >= 4" '[[ "${BASH_VERSINFO[0]}" -ge 4 ]]' fail
run_test "arch detected" '[[ -n "${ARCH}" ]]' fail
run_test "apk available" 'command -v apk >/dev/null 2>&1' fail
run_test "disk >= 500MB" '[[ $(df / --output=avail | tail -1) -ge 512000 ]]' warn
run_test "disk >= 500MB" '[[ $(df -k / | awk "NR==2{print \$4}") -ge 512000 ]]' warn
run_test "internet reachable" \
'curl --silent --max-time 10 --output /dev/null https://dl-cdn.alpinelinux.org' warn
log_info "Arch: ${ARCH}"

View file

@ -40,7 +40,7 @@ phase_preflight() {
run_test "community repo enabled" 'grep -q "^[^#].*community" /etc/apk/repositories' fail
run_test "internet reachable" \
'curl --silent --max-time 10 --output /dev/null https://dl-cdn.alpinelinux.org' warn
run_test "disk >= 2GB" '[[ $(df / --output=avail | tail -1) -ge 2097152 ]]' warn
run_test "disk >= 2GB" '[[ $(df -k / | awk "NR==2{print \$4}") -ge 2097152 ]]' warn
log_info "Arch: ${ARCH}"
log_info "Pre-flight complete"
}

View file

@ -40,7 +40,7 @@ phase_preflight() {
run_test "community repo enabled" 'grep -q "^[^#].*community" /etc/apk/repositories' fail
run_test "internet reachable" \
'curl --silent --max-time 10 --output /dev/null https://dl-cdn.alpinelinux.org' warn
run_test "disk >= 1GB" '[[ $(df / --output=avail | tail -1) -ge 1048576 ]]' warn
run_test "disk >= 1GB" '[[ $(df -k / | awk "NR==2{print \$4}") -ge 1048576 ]]' warn
log_info "Arch: ${ARCH}"
log_info "Pre-flight complete"
}

View file

@ -41,5 +41,5 @@ doas chmod +x \
echo ""
echo "Deploy complete."
echo "Pull URL: http://192.168.0.138/repo/scripts/alpine-ceos-installer/"
echo "Bootstrap: wget http://192.168.0.138/repo/scripts/alpine-ceos-installer/bootstrap.sh"
echo "Pull URL: http://192.168.0.138/scripts/alpine-ceos-installer/"
echo "Bootstrap: wget http://192.168.0.138/scripts/alpine-ceos-installer/bootstrap.sh"

View file

@ -24,7 +24,7 @@ install_base_core() {
log_info "--- base/01_core: verifying core packages available ---"
local missing=()
for pkg in bash bash-completion ca-certificates curl openssh tzdata utmps; do
for pkg in bash-completion ca-certificates curl openssh tzdata utmps; do
apk search "${pkg}" 2>/dev/null | grep -q "^${pkg}" \
|| missing+=("${pkg}")
done
@ -33,7 +33,7 @@ install_base_core() {
fi
log_info "--- base/01_core: installing core packages ---"
local -a PKGS=(bash bash-completion ca-certificates curl openssh tzdata utmps)
local -a PKGS=(bash-completion ca-certificates curl openssh tzdata utmps)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done

View file

@ -18,15 +18,15 @@ install_basic_fonts() {
install_pkg "figlet"
run_test "figlet present" 'command -v figlet >/dev/null 2>&1' warn
# nerd-fonts — edge/community; package name verified as 'nerd-fonts'
# nerd-fonts-all — edge/community; 'nerd-fonts' meta-package blocks install by design
ensure_edge_repo
log_info "Installing nerd-fonts from @edge/community..."
if install_pkg_edge "nerd-fonts"; then
log_info "nerd-fonts installed"
log_info "Installing nerd-fonts-all from @edge/community..."
if install_pkg_edge "nerd-fonts-all"; then
log_info "nerd-fonts-all installed"
else
log_warn "nerd-fonts@edge not available — skipping gracefully"
MANUAL_PKGS+=("nerd-fonts: edge install failed — check pkgs.alpinelinux.org/packages?name=nerd-fonts&branch=edge")
log_warn "nerd-fonts-all@edge not available — skipping gracefully"
MANUAL_PKGS+=("nerd-fonts: edge install failed — check pkgs.alpinelinux.org/packages?name=nerd-fonts-all&branch=edge")
fi
}

View file

@ -7,14 +7,16 @@
# Target: Alpine Linux x86-64 (tinkerpad / ThinkPad T480)
# ---------------------------------------------------------------------------
# Basic Tier subscript: additional utilities —
# tealdeer, restic, jq, bc, zip, unzip, xz.
# Note: package name is 'tealdeer' (not 'tldr').
# tealdeer (@edge/testing), restic, jq, bc, zip, unzip, xz.
# Defines install_basic_utils().
# ---------------------------------------------------------------------------
install_basic_utils() {
log_info "--- basic/06_utils: additional utilities ---"
local -a PKGS=(tealdeer restic jq bc zip unzip xz)
ensure_testing_repo
install_pkg_testing "tealdeer"
install_pkg_testing "tealdeer-bash-completion"
local -a PKGS=(restic jq bc zip unzip xz)
for pkg in "${PKGS[@]}"; do
install_pkg "${pkg}"
done

View file

@ -106,6 +106,27 @@ ensure_edge_repo() {
fi
}
# ensure_testing_repo — add @testing tag if not present
ensure_testing_repo() {
if ! grep -q "^@testing" /etc/apk/repositories 2>/dev/null; then
log_info "Adding @testing edge/testing tag to /etc/apk/repositories"
printf '@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing\n' \
| doas tee -a /etc/apk/repositories > /dev/null 2>&1 \
|| log_warn "Could not add @testing tag — testing installs may fail"
fi
}
# install_pkg_testing <package> — install with @testing tag, warn on fail
install_pkg_testing() {
local pkg="${1}"
if doas apk add "${pkg}@testing" >> "${LOG_FILE}" 2>&1; then
log_info "Installed: ${pkg} (@testing)"
else
log_warn "FAILED: ${pkg}@testing — manual verification required"
FAILED_PKGS+=("${pkg} (testing, manual verification required)")
fi
}
# ---------------------------------------------------------------------------
# Guards and prompts
# ---------------------------------------------------------------------------

View file

@ -33,7 +33,7 @@ install_minimal_journal() {
FAILED_PKGS+=("jrnl (pipx install failed)")
fi
run_test "jrnl present" 'command -v jrnl >/dev/null 2>&1' warn
run_test "jrnl present" 'command -v jrnl >/dev/null 2>&1 || [[ -x "${HOME}/.local/bin/jrnl" ]]' warn
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then

View file

@ -9,13 +9,15 @@
# Minimal Tier subscript: wiki viewer — glow from CE repo.
# Downloads binary, verifies sha256 and GPG signature, installs to ~/.local/bin/.
# Gracefully skips if CE repo is unreachable or verification fails.
# TODO — Forgejo: update CE_REPO_HOST to https://git.jhoeven.net/giovannino/ceos-alpine-installer/raw/branch/main/bin
# Defines install_minimal_wiki().
# ---------------------------------------------------------------------------
install_minimal_wiki() {
log_info "--- minimal/11_wiki: glow (CE repo) ---"
local CE_REPO="https://cervelloelettrico.it/bin/amd64/alpine"
local CE_REPO_HOST="https://cervelloelettrico.it/bin"
local CE_REPO="${CE_REPO_HOST}/${ARCH}/alpine"
local INSTALL_DIR="${HOME}/.local/bin"
local TEMP_DIR
TEMP_DIR="$(mktemp -d /tmp/ce-glow-XXXXXX)"

View file

@ -27,13 +27,10 @@ install_minimal_access() {
install_pkg "espeak-ng"
run_test "espeak-ng present" 'command -v espeak-ng >/dev/null 2>&1' warn
# espeakup — verify package exists in current repo before attempting install
if apk search espeakup 2>/dev/null | grep -q "^espeakup"; then
install_pkg "espeakup"
else
log_warn "espeakup not found in current Alpine repos — skipping"
MANUAL_PKGS+=("espeakup: not found in Alpine v3.23 — check https://github.com/dermotbradley/alpine-espeakup")
fi
# espeakup — in edge/testing; also install espeakup-openrc for service management
ensure_testing_repo
install_pkg_testing "espeakup"
install_pkg_testing "espeakup-openrc"
# speech-dispatcher — edge package
ensure_edge_repo