#!/bin/bash # Source common functions BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..") source "$BUILD_ROOT/helpers/message-helpers.sh" source "$BUILD_ROOT/helpers/paths.sh" # Default remote (production) DEFAULT_REMOTE="pkgs.omarchy.org:omarchy-pkgs" REMOTE="$DEFAULT_REMOTE" SKIP_PROD_CHECK=false PRUNE=false # Print header print_header "Sync Repository to Remote" # Parse arguments while [[ $# -gt 0 ]]; do case $1 in --arch) ARCH="$2" update_arch_paths shift 2 ;; --mirror) MIRROR="$2" update_arch_paths shift 2 ;; --remote) REMOTE="$2" shift 2 ;; --skip-prod-check) SKIP_PROD_CHECK=true shift ;; --prune) PRUNE=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 or stable, default: edge)" echo " --remote Rclone remote destination (default: $DEFAULT_REMOTE)" echo " --skip-prod-check Skip production sync confirmation" echo " --prune Also delete remote packages missing locally" echo " -h, --help Show this help message" echo "" echo "Uploads are additive by default. Removing packages from the remote" echo "requires --prune, which only makes sense from a complete local tree." exit 0 ;; *) print_error "Unknown option: $1" exit 1 ;; esac done print_info "Mirror: $MIRROR" print_info "Architecture: $ARCH" print_info "Local Repository: $REPO_DIR" print_info "Remote: $REMOTE" echo "" # Check if local repo exists if [[ ! -d "$REPO_DIR" ]]; then print_error "Local repository directory not found: $REPO_DIR" exit 1 fi DESTINATION_DIRECTORY="$MIRROR/$ARCH" # Check if syncing to production and warn user if [[ "$REMOTE" == "$DEFAULT_REMOTE" ]] && [[ "$SKIP_PROD_CHECK" != true ]]; then print_warning "You are about to sync to PRODUCTION ($REMOTE/$DESTINATION_DIRECTORY)" echo "" read -p "Are you sure you want to sync to production? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then print_info "Sync cancelled" exit 0 fi fi print_info "Syncing to: $REMOTE/$DESTINATION_DIRECTORY" # The database is what users actually resolve against, and repo-add builds it # from this tree alone. Publishing one built from a partial tree hides every # package it does not know about, even though the files are still on the remote. # Refuse to shrink the package list unless that is the stated intent. LOCAL_COUNT=$(ls -1 "$REPO_DIR"/*.pkg.tar.* 2>/dev/null | grep -vc '\.sig$' || true) # bsdtar, not tar: the database is compressed and GNU tar will not detect that # on a pipe. repo-add has used both gzip and zstd, so let libarchive decide. REMOTE_COUNT=$(rclone cat "$REMOTE/$DESTINATION_DIRECTORY/omarchy.db" --s3-no-head 2>/dev/null | bsdtar -tf - 2>/dev/null | sed 's|/.*||' | sort -u | grep -c . || true) if [[ "${REMOTE_COUNT:-0}" -gt 0 && "${LOCAL_COUNT:-0}" -lt "$REMOTE_COUNT" && "$PRUNE" != true ]]; then print_error "Local tree has $LOCAL_COUNT package(s); the remote database lists $REMOTE_COUNT" echo "" echo "Publishing this database would hide the $((REMOTE_COUNT - LOCAL_COUNT)) package(s)" echo "missing from $REPO_DIR." echo "" echo "To publish packages built on this machine, push them to the build host," echo "which holds the complete repository:" echo " bin/repo push --mirror $MIRROR --arch $ARCH" echo "" echo "If shrinking the repository is genuinely what you want, pass --prune." exit 1 fi # Upload packages first, database last, so the remote never advertises a package # it does not yet have. # # This is `copy`, not `sync`: a local tree is not authoritative about what should # exist on the remote. Packages built on another machine live only in that # machine's build-output, and pkgs.omarchy.org/ is gitignored, so any checkout # that has not run a full release is missing nearly everything. `sync` would read # those absences as deletions and empty the repository. --ignore-existing keeps # versions already published from being overwritten. if [[ "$PRUNE" == true ]]; then print_warning "Pruning: remote packages missing from $REPO_DIR will be DELETED" if [[ "$SKIP_PROD_CHECK" != true ]]; then read -p "Prune the remote to match this tree? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then print_info "Sync cancelled" exit 0 fi fi print_info "Syncing packages (with prune)..." rclone sync "$REPO_DIR" "$REMOTE/$DESTINATION_DIRECTORY" \ --s3-no-head \ --exclude "omarchy.db*" \ --exclude "omarchy.files*" \ --ignore-existing \ --copy-links --delete-after -v else print_info "Syncing packages..." rclone copy "$REPO_DIR" "$REMOTE/$DESTINATION_DIRECTORY" \ --s3-no-head \ --exclude "omarchy.db*" \ --exclude "omarchy.files*" \ --ignore-existing \ --copy-links -v fi # Then sync database files last to ensure repository integrity print_info "Updating repository database..." rclone copy "$REPO_DIR" "$REMOTE/$DESTINATION_DIRECTORY" \ --s3-no-head \ --include "omarchy.*" \ --checksum --copy-links -v print_success "Sync complete!"