#!/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" source "$BUILD_ROOT/helpers/lock-helpers.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" require_valid_mirror "$MIRROR" update_arch_paths shift 2 ;; --dry-run) DRY_RUN=true shift ;; -h | --help) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --arch Target architecture (x86_64 or aarch64, default: x86_64)" echo " --mirror Mirror to use (edge, rc, 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 if [[ "$DRY_RUN" != true ]]; then acquire_release_lock || exit 1 fi 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