This repository has been archived on 2026-10-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
omarchy-pkgs/bin/setup
T
David Heinemeier HanssonandClaude Opus 5 daf98026bc Make bin/setup work on Ubuntu, which is what the host runs
The first version checked for pacman and refused anything else, so it would
have declined to run on the actual repository host. Nothing about that host
needs to be Arch: makepkg, repo-add and signing all happen inside containers.

Setup now detects apt or pacman and installs the right names for each --
bsdtar is libarchive-tools on Debian and libarchive on Arch. The requirement
list drops gnupg and the Arch build tools, which the host never runs directly,
leaving Docker, rclone, bsdtar, jq, git and rsync.

Docker is checked before being installed. A host may be running a version from
Docker's own repository, and replacing that underneath a working builder would
be a poor trade for consistency; setup starts it if stopped and otherwise
leaves it alone.

Verified both paths: apt installs the five dependencies and docker.io on a
bare Ubuntu 24.04 container, and an Arch host with Docker already running is
left untouched. A missing systemctl now reports that a container cannot be a
repository host instead of failing on an unknown command.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 05:43:23 -07:00

247 lines
7.6 KiB
Bash
Executable File

#!/bin/bash
# Prepare this machine to serve as the Omarchy repository host.
#
# The host receives uploads, promotes packages into the published tree, and
# syncs that tree to the mirror. Everything Arch-specific — makepkg, repo-add,
# package signing — happens inside containers, so the host itself needs very
# little and does not need to be Arch. The production host is Ubuntu.
#
# Run this on the host itself:
# ssh root@<host> 'cd /root/omarchy-pkgs && bin/setup'
#
# It is idempotent — run it again after adding a dependency.
set -e
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
source "$BUILD_ROOT/helpers/message-helpers.sh"
CHECK_ONLY=false
SKIP_TIMERS=false
STATE_DIR="${OMARCHY_STATE_DIR:-/root/.state}"
CREDENTIALS="/root/.omarchy/build-credentials"
print_header "Omarchy Repository Host Setup"
while [[ $# -gt 0 ]]; do
case $1 in
--check)
CHECK_ONLY=true
shift
;;
--skip-timers)
SKIP_TIMERS=true
shift
;;
-h | --help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Install and enable everything the repository host needs."
echo "Works on Debian/Ubuntu (apt) and Arch (pacman)."
echo ""
echo "Options:"
echo " --check Report what is missing, change nothing"
echo " --skip-timers Do not install or enable the release timers"
echo " -h, --help Show this help message"
exit 0
;;
*)
print_error "Unknown option: $1"
exit 1
;;
esac
done
# --- distribution ------------------------------------------------------------
# Package names differ where it matters: bsdtar is libarchive-tools on Debian
# and libarchive on Arch, and Docker is docker.io rather than docker.
if command -v apt-get >/dev/null 2>&1; then
DISTRO="debian"
PKG_BSDTAR="libarchive-tools"
PKG_DOCKER="docker.io"
elif command -v pacman >/dev/null 2>&1; then
DISTRO="arch"
PKG_BSDTAR="libarchive"
PKG_DOCKER="docker"
else
print_error "Unsupported distribution — need apt-get or pacman"
exit 1
fi
print_info "Distribution: $DISTRO"
if [[ "$CHECK_ONLY" != true && $EUID -ne 0 ]]; then
print_error "Run as root (installing packages and systemd units)"
exit 1
fi
# Docker and the release timers are both systemd units. Say so plainly rather
# than failing later on a missing command — a container is the usual way to end
# up here, and it cannot be a repository host.
if [[ "$CHECK_ONLY" != true ]] && ! command -v systemctl >/dev/null 2>&1; then
print_error "systemctl not found — the repository host must run systemd"
echo ""
echo "Docker and the release timers are systemd units. This looks like a"
echo "container; run setup on the host itself."
exit 1
fi
install_packages() {
case "$DISTRO" in
debian)
apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y "$@"
;;
arch)
pacman -S --needed --noconfirm "$@"
;;
esac
}
# --- dependencies ------------------------------------------------------------
# Only what the host runs directly. Signing and repo-add happen in containers,
# so gnupg and the Arch build tools are deliberately absent from this list.
REQUIREMENTS=(
"bsdtar:$PKG_BSDTAR" # reads repo databases and .PKGINFO out of packages
"git:git" # pulls this repository
"jq:jq" # package metadata in .omarchy/package.json
"rsync:rsync" # receives uploads from bin/repo push
"rclone:rclone" # publishes to the mirror
)
print_info "Checking dependencies..."
MISSING_PACKAGES=()
for requirement in "${REQUIREMENTS[@]}"; do
cmd="${requirement%%:*}"
pkg="${requirement#*:}"
if command -v "$cmd" >/dev/null 2>&1; then
print_step "$cmd"
else
print_warning "$cmd missing (provided by $pkg)"
MISSING_PACKAGES+=("$pkg")
fi
done
echo ""
if [[ ${#MISSING_PACKAGES[@]} -gt 0 ]]; then
if [[ "$CHECK_ONLY" == true ]]; then
print_warning "Would install: ${MISSING_PACKAGES[*]}"
else
print_info "Installing: ${MISSING_PACKAGES[*]}"
install_packages "${MISSING_PACKAGES[@]}"
print_success "Dependencies installed"
fi
else
print_success "All dependencies present"
fi
echo ""
# --- docker ------------------------------------------------------------------
# Docker is left alone when it already works. A host may well be running a
# version from Docker's own repository rather than the distribution's, and
# replacing that underneath a working builder would be a poor trade for
# tidiness.
print_info "Checking Docker..."
if command -v docker >/dev/null 2>&1; then
print_step "docker present: $(docker --version 2>/dev/null | head -1)"
if docker info >/dev/null 2>&1; then
print_success "Docker is installed and running — leaving it alone"
elif [[ "$CHECK_ONLY" == true ]]; then
print_warning "Docker is installed but not running; would start it"
else
print_info "Docker is installed but not running — starting it"
systemctl enable --now docker.service
if docker info >/dev/null 2>&1; then
print_success "Docker started"
else
print_error "Docker is installed but still not responding"
echo " Check 'systemctl status docker' — builds cannot run without it."
exit 1
fi
fi
elif [[ "$CHECK_ONLY" == true ]]; then
print_warning "Would install $PKG_DOCKER and enable it"
else
print_info "Installing $PKG_DOCKER..."
install_packages "$PKG_DOCKER"
systemctl enable --now docker.service
if docker info >/dev/null 2>&1; then
print_success "Docker installed and running"
else
print_error "Docker installed but not responding"
echo " Check 'systemctl status docker' — builds cannot run without it."
exit 1
fi
fi
echo ""
# --- state directory ---------------------------------------------------------
if [[ -d "$STATE_DIR" ]]; then
print_success "State directory present: $STATE_DIR"
elif [[ "$CHECK_ONLY" == true ]]; then
print_warning "Would create $STATE_DIR"
else
mkdir -p "$STATE_DIR"
print_success "Created $STATE_DIR"
fi
echo ""
# --- release timers ----------------------------------------------------------
TIMERS=(omarchy-check-versions omarchy-auto-release-edge omarchy-auto-release-stable)
if [[ "$SKIP_TIMERS" == true ]]; then
print_info "Skipping release timers (--skip-timers)"
elif [[ "$CHECK_ONLY" == true ]]; then
for timer in "${TIMERS[@]}"; do
if systemctl is-enabled "$timer.timer" >/dev/null 2>&1; then
print_success "$timer.timer is enabled"
else
print_warning "$timer.timer would be enabled"
fi
done
else
print_info "Installing release timers..."
cp "$BUILD_ROOT"/systemd/*.service "$BUILD_ROOT"/systemd/*.timer /etc/systemd/system/
systemctl daemon-reload
for timer in "${TIMERS[@]}"; do
systemctl enable --now "$timer.timer"
print_step "$timer.timer"
done
print_success "Release timers enabled"
fi
echo ""
# --- credentials -------------------------------------------------------------
# These hold secrets, so setup reports on them rather than creating them.
print_info "Checking credentials..."
if [[ -f "$CREDENTIALS" ]]; then
print_success "Signing credentials present: $CREDENTIALS"
else
print_warning "Missing $CREDENTIALS"
echo " Must export GPG_PRIVATE_KEY and GPG_PASSPHRASE; the release"
echo " services source it before signing."
fi
if rclone listremotes 2>/dev/null | grep -q '^pkgs.omarchy.org:'; then
print_success "rclone remote 'pkgs.omarchy.org' configured"
else
print_warning "rclone remote 'pkgs.omarchy.org' not configured"
echo " bin/repo sync publishes there; configure it with 'rclone config'."
fi
echo ""
if [[ "$CHECK_ONLY" == true ]]; then
print_info "Check complete — nothing was changed"
else
print_success "Repository host ready"
fi