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>
195 lines
5.6 KiB
Bash
Executable File
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
|