Files
omarchy-pkgs/bin/deploy
T
David Heinemeier HanssonandClaude Opus 5 fd9c078bf2 Fix nine defects in the push/sync path found in review
The worst was fatal: push passed --skip-prod-check to upload-prebuilt, which
forwards every argument to sign, promote and update as well, and sign rejects
unknown options. Every non-dry-run push and deploy would have uploaded and
verified its artifacts and then failed before signing. upload-prebuilt now
routes publishing flags to sync alone.

The partial-tree guard was weaker than it looked:

  - it counted archive files locally against package names in the remote
    database, and this tree keeps two versions per package, so a checkout with
    a spare version of half the repository could pass while still hiding
    hundreds of packages. It now compares package-name sets and lists what
    would be hidden.
  - it treated any unreadable remote as an empty one, so an auth failure or a
    corrupt database disabled it. Only rclone's "directory not found" now
    counts as a fresh mirror; every other failure aborts.

Also:

  - sync had no set -e, so a failed package upload fell through to publishing
    the database, advertising packages that were never uploaded. Each transfer
    is now checked before the next step.
  - --package with no names silently meant "every package", which under --yes
    could publish everything from one unset variable in a script.
  - push now refuses to run when the host has packages staged from an earlier
    failure, since publishing would sign and promote those too.
  - epoch versions contain a colon, which rsync reads as host:path, so no
    package with an epoch could be transferred. Sources are ./-prefixed.
  - remote paths are quoted for the remote shell.
  - sync spun forever on a missing option value.

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

139 lines
3.8 KiB
Bash
Executable File

#!/bin/bash
# Build packages locally, then publish them from the build host.
#
# The two halves of shipping a package built on a local machine: bin/build
# produces the artifacts, bin/push-build hands them to the host that owns the
# signing key and the complete repository.
set -e
SCRIPT_DIR=$(realpath "${BASH_SOURCE[0]%/*}")
BUILD_ROOT=$(realpath "$SCRIPT_DIR/..")
source "$BUILD_ROOT/helpers/message-helpers.sh"
source "$BUILD_ROOT/helpers/paths.sh"
PACKAGES=()
PACKAGE_FLAG_GIVEN=false
HOST=""
REMOTE_ROOT=""
DRY_RUN=false
ASSUME_YES=false
print_header "Deploy (build + push)"
while [[ $# -gt 0 ]]; do
case $1 in
--arch)
ARCH="$2"
update_arch_paths
shift 2
;;
--mirror)
MIRROR="$2"
if [[ "$MIRROR" != "edge" && "$MIRROR" != "stable" ]]; then
print_error "Invalid mirror: $MIRROR (must be 'edge' or 'stable')"
exit 1
fi
update_arch_paths
shift 2
;;
--package)
shift
PACKAGE_FLAG_GIVEN=true
while [[ $# -gt 0 && ! "$1" =~ ^-- ]]; do
[[ -n "$1" ]] && PACKAGES+=("$1")
shift
done
;;
--host)
HOST="$2"
shift 2
;;
--remote-root)
REMOTE_ROOT="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
-y | --yes)
ASSUME_YES=true
shift
;;
-h | --help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Build packages here, then publish them from the build host."
echo ""
echo "Options:"
echo " --arch <arch> Target architecture (default: x86_64)"
echo " --mirror <mirror> Mirror to publish to (edge or stable, default: edge)"
echo " --package <names> Build and push only these packages (space-separated)"
echo " --host <host> ssh destination (default: \$OMARCHY_BUILD_HOST or .build-host)"
echo " --remote-root <path> Repository path on the host (default: /root/omarchy-pkgs)"
echo " --dry-run Show the plan, build nothing and transfer nothing"
echo " -y, --yes Do not ask for confirmation before publishing"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 --package nvidia-580xx-utils"
echo " $0 --package nvidia-580xx-utils --host root@example.com"
exit 0
;;
*)
print_error "Unknown option: $1"
exit 1
;;
esac
done
if [[ "$PACKAGE_FLAG_GIVEN" == true && ${#PACKAGES[@]} -eq 0 ]]; then
print_error "--package requires at least one package name"
exit 1
fi
echo ""
print_info "This will:"
echo " 1. Build packages locally"
echo " 2. Upload them to the build host"
echo " 3. Sign, promote, update and sync them there"
echo ""
BUILD_ARGS=("--arch" "$ARCH" "--mirror" "$MIRROR")
PUSH_ARGS=("--arch" "$ARCH" "--mirror" "$MIRROR")
if [[ ${#PACKAGES[@]} -gt 0 ]]; then
BUILD_ARGS+=("--package" "${PACKAGES[@]}")
PUSH_ARGS+=("--package" "${PACKAGES[@]}")
fi
[[ -n "$HOST" ]] && PUSH_ARGS+=("--host" "$HOST")
[[ -n "$REMOTE_ROOT" ]] && PUSH_ARGS+=("--remote-root" "$REMOTE_ROOT")
[[ "$DRY_RUN" == true ]] && BUILD_ARGS+=("--dry-run") && PUSH_ARGS+=("--dry-run")
[[ "$ASSUME_YES" == true ]] && PUSH_ARGS+=("--yes")
# Resolve the host before spending build time on packages that cannot ship.
if [[ "$DRY_RUN" != true ]]; then
resolved_host="$HOST"
if [[ -z "$resolved_host" ]]; then
resolved_host="${OMARCHY_BUILD_HOST:-}"
[[ -z "$resolved_host" && -f "$BUILD_ROOT/.build-host" ]] && resolved_host=$(<"$BUILD_ROOT/.build-host")
fi
if [[ -z "$resolved_host" ]]; then
print_error "No build host configured"
echo ""
echo "Pass --host, set OMARCHY_BUILD_HOST, or write the destination to:"
echo " $BUILD_ROOT/.build-host"
exit 1
fi
fi
print_info "Step 1/2: Building..."
echo ""
"$SCRIPT_DIR/build" "${BUILD_ARGS[@]}"
echo ""
print_info "Step 2/2: Pushing to the build host..."
echo ""
"$SCRIPT_DIR/push-build" "${PUSH_ARGS[@]}"