Add bin/setup to prepare a repository host
The sync guard could not read the repository database because bsdtar was not installed on the host, and the first fix was to parse around its absence. The better answer is for the host to have what the tooling needs: libarchive ships the library pacman links against without necessarily installing the binary, so bsdtar being present was an assumption, not a fact. bin/setup installs the dependencies, enables Docker, creates the state directory, and installs and enables the release timers -- the steps the README previously listed by hand. It is idempotent and takes --check to report without changing anything. Signing credentials and the rclone remote hold secrets, so it reports on those rather than creating them. sync-repo goes back to reading the database with bsdtar alone, and says to run bin/setup when it is missing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
dbe1db4b03
commit
f8c1cbb072
@@ -60,6 +60,7 @@ show_usage() {
|
||||
echo " sync Sync repository to remote"
|
||||
echo " push Upload local builds to the repository host and publish them there"
|
||||
echo " deploy Build locally, then push: one command from a build machine"
|
||||
echo " setup Install everything the repository host needs"
|
||||
echo ""
|
||||
echo "Typical workflows:"
|
||||
echo " $0 release # Complete release workflow"
|
||||
@@ -135,6 +136,10 @@ deploy)
|
||||
"$SCRIPT_DIR/deploy" "$@" 2>&1 | tee "$LOG_FILE"
|
||||
exit ${PIPESTATUS[0]}
|
||||
;;
|
||||
setup)
|
||||
"$SCRIPT_DIR/setup" "$@" 2>&1 | tee "$LOG_FILE"
|
||||
exit ${PIPESTATUS[0]}
|
||||
;;
|
||||
-h | --help | help)
|
||||
show_usage
|
||||
;;
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
#!/bin/bash
|
||||
# Prepare this machine to serve as the Omarchy repository host.
|
||||
#
|
||||
# The repository host builds packages, signs them, keeps the published tree, and
|
||||
# syncs it to the mirror. Everything it needs is installed and enabled here, so
|
||||
# the tooling can assume its toolchain instead of working around whatever
|
||||
# happens to be present.
|
||||
#
|
||||
# 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
|
||||
|
||||
# Packages, in "command:package" form so a missing tool names its own fix.
|
||||
#
|
||||
# tar, vercmp and repo-add come from base and pacman, which any Arch install
|
||||
# already has. bsdtar does not: libarchive ships the library pacman links
|
||||
# against without necessarily installing the binary.
|
||||
REQUIREMENTS=(
|
||||
"bsdtar:libarchive" # reads repo databases and .PKGINFO out of packages
|
||||
"git:git" # PKGBUILD sources and release commits
|
||||
"jq:jq" # package metadata in .omarchy/package.json
|
||||
"curl:curl" # upstream version checks
|
||||
"rsync:rsync" # receives uploads from bin/repo push
|
||||
"gpg:gnupg" # package signing
|
||||
"rclone:rclone" # publishes to the mirror
|
||||
"docker:docker" # builds run in containers
|
||||
"makepkg:base-devel" # source verification for releases
|
||||
)
|
||||
|
||||
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 ""
|
||||
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
|
||||
|
||||
if ! command -v pacman >/dev/null 2>&1; then
|
||||
print_error "This is not an Arch system — the repository host must be Arch"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$CHECK_ONLY" != true && $EUID -ne 0 ]]; then
|
||||
print_error "Run as root (installing packages and systemd units)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- dependencies ------------------------------------------------------------
|
||||
|
||||
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[*]}"
|
||||
pacman -S --needed --noconfirm "${MISSING_PACKAGES[@]}"
|
||||
print_success "Dependencies installed"
|
||||
fi
|
||||
else
|
||||
print_success "All dependencies present"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- docker ------------------------------------------------------------------
|
||||
|
||||
if [[ "$CHECK_ONLY" == true ]]; then
|
||||
if systemctl is-enabled docker.service >/dev/null 2>&1; then
|
||||
print_success "docker.service is enabled"
|
||||
else
|
||||
print_warning "docker.service would be enabled"
|
||||
fi
|
||||
else
|
||||
print_info "Enabling docker..."
|
||||
systemctl enable --now docker.service
|
||||
print_success "docker.service enabled"
|
||||
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 ----------------------------------------------------------
|
||||
|
||||
if [[ "$SKIP_TIMERS" == true ]]; then
|
||||
print_info "Skipping release timers (--skip-timers)"
|
||||
elif [[ "$CHECK_ONLY" == true ]]; then
|
||||
for timer in omarchy-check-versions omarchy-auto-release-edge omarchy-auto-release-stable; 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 omarchy-check-versions omarchy-auto-release-edge omarchy-auto-release-stable; 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
|
||||
+12
-10
@@ -142,23 +142,25 @@ if grep -qx 'omarchy\.db' <<<"$REMOTE_LISTING"; then
|
||||
trap 'rm -f "$REMOTE_DB_FILE"' EXIT
|
||||
rclone cat "$REMOTE/$DESTINATION_DIRECTORY/omarchy.db" --s3-no-head >"$REMOTE_DB_FILE" 2>/dev/null
|
||||
|
||||
# Download to a file rather than piping: GNU tar detects the compression from
|
||||
# a seekable archive but not from a pipe, and the database has been both gzip
|
||||
# and zstd over its life. bsdtar reads either too, but it is not present on
|
||||
# every host, so tar leads and bsdtar covers a tar too old for zstd.
|
||||
REMOTE_ENTRIES=$(tar -tf "$REMOTE_DB_FILE" 2>/dev/null)
|
||||
if [[ -z "$REMOTE_ENTRIES" ]] && command -v bsdtar >/dev/null 2>&1; then
|
||||
REMOTE_ENTRIES=$(bsdtar -tf "$REMOTE_DB_FILE" 2>/dev/null)
|
||||
if ! command -v bsdtar >/dev/null 2>&1; then
|
||||
print_error "bsdtar is not installed"
|
||||
echo ""
|
||||
echo "The repository host needs it to read the repository database."
|
||||
echo "Run bin/setup to install everything this host requires."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REMOTE_NAMES=$(printf '%s\n' "$REMOTE_ENTRIES" | sed 's|/.*||' |
|
||||
sed -E 's/-[^-]+-[^-]+$//' | sort -u | grep -v '^$')
|
||||
# bsdtar, not tar: repo-add has used both gzip and zstd for the database, and
|
||||
# libarchive detects either without being told which.
|
||||
REMOTE_NAMES=$(bsdtar -tf "$REMOTE_DB_FILE" 2>/dev/null | sed 's|/.*||' |
|
||||
sed -E 's/-[^-]+-[^-]+$//' | sort -u)
|
||||
|
||||
if [[ -z "$REMOTE_NAMES" ]]; then
|
||||
print_error "The remote database exists but could not be read"
|
||||
echo ""
|
||||
echo "Refusing to sync rather than assume the remote is empty. Check that"
|
||||
echo "omarchy.db is not corrupt: rclone cat $REMOTE/$DESTINATION_DIRECTORY/omarchy.db | tar -t"
|
||||
echo "omarchy.db is not corrupt:"
|
||||
echo " rclone cat $REMOTE/$DESTINATION_DIRECTORY/omarchy.db | bsdtar -tf -"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user