A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go
72
fork

Configure Feed

Select the types of activity you want to include in your feed.

at refactor 187 lines 5.7 kB view raw
1#!/bin/bash 2set -e 3 4# Usage function 5usage() { 6 echo "Usage: $0 <source-image> [target-image]" 7 echo "" 8 echo "Examples:" 9 echo " $0 ghcr.io/evanjarrett/myapp:latest" 10 echo " $0 ghcr.io/evanjarrett/myapp:latest atcr.io/evan.jarrett.net/myapp:latest" 11 echo "" 12 echo "If target-image is not specified, it will use atcr.io/<username>/<repo>:<tag>" 13 exit 1 14} 15 16# Check arguments 17if [ $# -lt 1 ]; then 18 usage 19fi 20 21SOURCE_IMAGE="$1" 22TARGET_IMAGE="${2:-}" 23 24# Parse source image to extract components 25# Format: [registry/]repository[:tag|@digest] 26parse_image_ref() { 27 local ref="$1" 28 local registry="" 29 local repository="" 30 local tag="latest" 31 32 # Remove digest if present (we'll fetch the manifest-list) 33 ref="${ref%@*}" 34 35 # Extract tag 36 if [[ "$ref" == *:* ]]; then 37 tag="${ref##*:}" 38 ref="${ref%:*}" 39 fi 40 41 # Extract registry and repository 42 if [[ "$ref" == */*/* ]]; then 43 # Has registry 44 registry="${ref%%/*}" 45 repository="${ref#*/}" 46 else 47 # No registry, assume Docker Hub 48 registry="docker.io" 49 repository="$ref" 50 fi 51 52 echo "$registry" "$repository" "$tag" 53} 54 55# Parse source image 56read -r SOURCE_REGISTRY SOURCE_REPO SOURCE_TAG <<< "$(parse_image_ref "$SOURCE_IMAGE")" 57 58# If no target specified, auto-generate it 59if [ -z "$TARGET_IMAGE" ]; then 60 # Extract just the repo name (last component) 61 REPO_NAME="${SOURCE_REPO##*/}" 62 # Try to extract username from source 63 if [[ "$SOURCE_REPO" == */* ]]; then 64 USERNAME="${SOURCE_REPO%/*}" 65 USERNAME="${USERNAME##*/}" 66 else 67 USERNAME="default" 68 fi 69 TARGET_IMAGE="atcr.io/${USERNAME}/${REPO_NAME}:${SOURCE_TAG}" 70fi 71 72# Parse target image 73read -r TARGET_REGISTRY TARGET_REPO TARGET_TAG <<< "$(parse_image_ref "$TARGET_IMAGE")" 74 75echo "=== Migrating multi-arch image ===" 76echo "Source: ${SOURCE_REGISTRY}/${SOURCE_REPO}:${SOURCE_TAG}" 77echo "Target: ${TARGET_REGISTRY}/${TARGET_REPO}:${TARGET_TAG}" 78echo "" 79 80# Full source reference 81SOURCE_REF="${SOURCE_REGISTRY}/${SOURCE_REPO}:${SOURCE_TAG}" 82TARGET_REF="${TARGET_REGISTRY}/${TARGET_REPO}:${TARGET_TAG}" 83 84# Fetch the manifest list 85echo ">>> Fetching manifest list from source..." 86MANIFEST_JSON=$(docker manifest inspect "$SOURCE_REF" 2>/dev/null || { 87 echo "Error: Failed to fetch manifest list. This may not be a multi-arch image." 88 echo "Trying as single-arch image..." 89 90 # Try pulling as single image 91 docker pull "$SOURCE_REF" 92 docker tag "$SOURCE_REF" "$TARGET_REF" 93 docker push "$TARGET_REF" 94 echo "=== Migration complete (single-arch) ===" 95 exit 0 96}) 97 98# Check if this is a manifest list 99MEDIA_TYPE=$(echo "$MANIFEST_JSON" | jq -r '.mediaType // .schemaVersion') 100if [[ ! "$MEDIA_TYPE" =~ "manifest.list" ]] && [[ ! "$MEDIA_TYPE" =~ "index" ]]; then 101 echo "Warning: Source appears to be a single-arch image, not a manifest list." 102 docker pull "$SOURCE_REF" 103 docker tag "$SOURCE_REF" "$TARGET_REF" 104 docker push "$TARGET_REF" 105 echo "=== Migration complete (single-arch) ===" 106 exit 0 107fi 108 109echo "Found multi-arch manifest list" 110echo "" 111 112# Extract platform information and digests (skip unknown/unknown for cosign artifacts) 113PLATFORMS=$(echo "$MANIFEST_JSON" | jq -r '.manifests[] | select(.platform.os != "unknown" and .platform.architecture != "unknown") | "\(.platform.os)|\(.platform.architecture)|\(.platform.variant // "")|\(.digest)"') 114 115# Arrays to store pushed images for manifest creation 116declare -a PUSHED_IMAGES 117declare -a PLATFORM_INFO 118 119# Process each platform 120while IFS='|' read -r os arch variant digest; do 121 # Create platform tag (e.g., "linux-amd64" or "linux-arm-v7") 122 PLATFORM_TAG="${os}-${arch}" 123 if [ -n "$variant" ]; then 124 PLATFORM_TAG="${PLATFORM_TAG}-${variant}" 125 fi 126 127 echo ">>> Processing ${os}/${arch}${variant:+/$variant}..." 128 echo " Digest: $digest" 129 130 # Pull by digest 131 echo " Pulling image..." 132 docker pull "${SOURCE_REGISTRY}/${SOURCE_REPO}@${digest}" 133 134 # Tag for target 135 TARGET_PLATFORM_REF="${TARGET_REGISTRY}/${TARGET_REPO}:${TARGET_TAG}-${PLATFORM_TAG}" 136 echo " Tagging as: ${TARGET_PLATFORM_REF}" 137 docker tag "${SOURCE_REGISTRY}/${SOURCE_REPO}@${digest}" "${TARGET_PLATFORM_REF}" 138 139 # Push platform-specific image 140 echo " Pushing..." 141 docker push "${TARGET_PLATFORM_REF}" 142 143 # Store for manifest creation 144 PUSHED_IMAGES+=("${TARGET_PLATFORM_REF}") 145 PLATFORM_INFO+=("${os}|${arch}|${variant}") 146 147 echo "" 148done <<< "$PLATFORMS" 149 150# Create multi-arch manifest 151echo ">>> Creating multi-arch manifest..." 152MANIFEST_CREATE_CMD="docker manifest create ${TARGET_REF}" 153for img in "${PUSHED_IMAGES[@]}"; do 154 MANIFEST_CREATE_CMD="${MANIFEST_CREATE_CMD} --amend ${img}" 155done 156 157eval "$MANIFEST_CREATE_CMD" 158echo "" 159 160# Annotate each platform 161echo ">>> Annotating manifest with platform information..." 162for i in "${!PUSHED_IMAGES[@]}"; do 163 IFS='|' read -r os arch variant <<< "${PLATFORM_INFO[$i]}" 164 165 ANNOTATE_CMD="docker manifest annotate ${TARGET_REF} ${PUSHED_IMAGES[$i]} --os ${os} --arch ${arch}" 166 if [ -n "$variant" ]; then 167 ANNOTATE_CMD="${ANNOTATE_CMD} --variant ${variant}" 168 fi 169 170 echo " Annotating ${os}/${arch}${variant:+/$variant}..." 171 eval "$ANNOTATE_CMD" 172done 173echo "" 174 175# Push the manifest list 176echo ">>> Pushing multi-arch manifest..." 177docker manifest push "${TARGET_REF}" 178echo "" 179 180echo "=== Migration complete! ===" 181echo "You can now pull: docker pull ${TARGET_REF}" 182echo "" 183echo "Migrated platforms:" 184for i in "${!PLATFORM_INFO[@]}"; do 185 IFS='|' read -r os arch variant <<< "${PLATFORM_INFO[$i]}" 186 echo " - ${os}/${arch}${variant:+/$variant}" 187done