Files
omarchy-pkgs/bin/promote-build
T
David Heinemeier HanssonandClaude Opus 5 0a80091fe6 Promote packages already in production idempotently
The dev packages are versioned off the quattro tip, so rebuilding the
same upstream commit yields the same filename. Promotion treated any
pre-existing filename as fatal, which wedged the release loop whenever a
run promoted but died before update-repo rebuilt the database: the stale
database kept advertising the older hash, so every later run rebuilt the
identical package and failed here again, retaining the state file each
time.

Compare the bytes instead. Identical packages are skipped and the run
continues, so the following update-repo step fixes the database and the
loop unsticks itself. Differing content under a published filename still
aborts. Signatures are judged by the package they sign, since gpg stamps
a timestamp into every signature and a re-signed package never matches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 16:37:01 -07:00

195 lines
5.6 KiB
Bash
Executable File

#!/bin/bash
# Promote packages from build-output to pkgs.omarchy.org
set -e
BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..")
source "$BUILD_ROOT/helpers/message-helpers.sh"
source "$BUILD_ROOT/helpers/paths.sh"
print_header "Promote Build to Production"
# Parse arguments
DRY_RUN=false
while [[ $# -gt 0 ]]; do
case $1 in
--arch)
ARCH="$2"
update_arch_paths
shift 2
;;
--mirror)
MIRROR="$2"
update_arch_paths
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
-h | --help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --arch <arch> Target architecture (x86_64 or aarch64, default: x86_64)"
echo " --mirror <mirror> Mirror to use (edge or stable, default: edge)"
echo " --dry-run Show what would be copied without copying"
echo " -h, --help Show this help message"
echo ""
echo "This script promotes packages from build-output/ to pkgs.omarchy.org/"
exit 0
;;
*)
print_error "Unknown option: $1"
exit 1
;;
esac
done
print_info "Mirror: $MIRROR"
print_info "Build output: $BUILD_OUTPUT_DIR"
print_info "Final output: $REPO_DIR"
# Check if build output exists
if [[ ! -d "$BUILD_OUTPUT_DIR" ]]; then
print_error "Build output directory not found: $BUILD_OUTPUT_DIR"
print_warning "Run bin/repo build first"
exit 1
fi
# Count packages in build output
cd "$BUILD_OUTPUT_DIR"
PACKAGE_COUNT=$(ls -1 *.pkg.tar.* 2>/dev/null | grep -v '\.sig$' | grep -v 'omarchy-build\.db' | wc -l)
if [[ $PACKAGE_COUNT -eq 0 ]]; then
print_warning "No packages found in build output"
exit 0
fi
print_info "Found $PACKAGE_COUNT package(s) to promote"
if [[ "$DRY_RUN" == true ]]; then
print_warning "DRY RUN MODE - No files will be copied"
echo ""
print_info "Packages that would be promoted:"
ls -1 *.pkg.tar.* 2>/dev/null | grep -v 'omarchy-build\.db' | grep -v 'omarchy-build\.files' | while read -r pkg; do
echo " - $pkg"
done
else
echo ""
mkdir -p "$REPO_DIR"
echo "==> Verifying all packages have signatures..."
MISSING_SIGS=()
for pkg_file in *.pkg.tar.*; do
# Skip build database files
[[ "$pkg_file" == omarchy-build.db* ]] && continue
[[ "$pkg_file" == omarchy-build.files* ]] && continue
# Skip signature files themselves
[[ "$pkg_file" == *.sig ]] && continue
[[ ! -f "$pkg_file" ]] && continue
# Check if signature exists
if [[ ! -f "$pkg_file.sig" ]]; then
MISSING_SIGS+=("$pkg_file")
fi
done
if [[ ${#MISSING_SIGS[@]} -gt 0 ]]; then
echo ""
print_error "ERROR: The following packages are missing signatures:"
for pkg in "${MISSING_SIGS[@]}"; do
echo " - $pkg (missing $pkg.sig)"
done
echo ""
print_error "All packages must be signed before promotion!"
echo ""
echo "To fix this, run:"
echo " bin/repo sign --mirror $MIRROR --arch $ARCH"
exit 1
fi
# VCS packages (omarchy-dev and friends) are versioned off the upstream commit,
# so rebuilding the same commit produces the same filename. That is harmless
# when the artifact is identical — a run that promoted but died before the
# database was updated leaves exactly this state, and failing here would wedge
# every later run. Re-promoting *different* content under a published filename
# is the real hazard, so only that aborts.
echo "==> Checking for existing files in production..."
CONFLICTS=()
declare -A ALREADY_PROMOTED=()
for pkg_file in *.pkg.tar.*; do
# Skip build database files
[[ "$pkg_file" == omarchy-build.db* ]] && continue
[[ "$pkg_file" == omarchy-build.files* ]] && continue
[[ "$pkg_file" == *.sig ]] && continue
[[ ! -f "$pkg_file" ]] && continue
if [[ -f "$REPO_DIR/$pkg_file" ]]; then
if cmp -s "$pkg_file" "$REPO_DIR/$pkg_file"; then
ALREADY_PROMOTED["$pkg_file"]=1
else
CONFLICTS+=("$pkg_file")
fi
fi
done
# Signatures carry a timestamp, so a re-signed package never matches byte for
# byte. Judge them by the package they sign and keep the published signature.
for pkg_file in *.pkg.tar.*.sig; do
[[ ! -f "$pkg_file" ]] && continue
[[ -f "$REPO_DIR/$pkg_file" ]] || continue
if [[ -n "${ALREADY_PROMOTED[${pkg_file%.sig}]:-}" ]]; then
ALREADY_PROMOTED["$pkg_file"]=1
else
CONFLICTS+=("$pkg_file")
fi
done
if [[ ${#CONFLICTS[@]} -gt 0 ]]; then
echo ""
print_error "ERROR: The following packages already exist in production with different contents:"
for conflict in "${CONFLICTS[@]}"; do
echo " - $conflict"
done
echo ""
print_error "Refusing to replace published packages in pkgs.omarchy.org!"
exit 1
fi
if [[ ${#ALREADY_PROMOTED[@]} -gt 0 ]]; then
print_info "Already in production (identical, skipping): ${#ALREADY_PROMOTED[@]} file(s)"
for promoted in "${!ALREADY_PROMOTED[@]}"; do
echo " - $promoted"
done
fi
print_info "Moving packages to production..."
MOVED=0
for pkg_file in *.pkg.tar.*; do
# Skip build database files
[[ "$pkg_file" == omarchy-build.db* ]] && continue
[[ "$pkg_file" == omarchy-build.files* ]] && continue
[[ ! -f "$pkg_file" ]] && continue
[[ -n "${ALREADY_PROMOTED[$pkg_file]:-}" ]] && continue
# Use mv to prevent race condition caused by cp
if mv -v "$pkg_file" "$REPO_DIR/"; then
MOVED=$((MOVED + 1))
else
print_error "Failed to move $pkg_file"
exit 1
fi
done
echo ""
print_success "Promoted $MOVED file(s) to pkgs.omarchy.org"
print_info "Cleaning up build directory..."
cd "$BUILD_OUTPUT_DIR"
rm -f *.pkg.tar.* omarchy-build.db* omarchy-build.files*
print_success "Build directory cleaned"
fi