#!/bin/bash

echo ">>> Pushing images..."

export DOCKER_CLI_EXPERIMENTAL=enabled

declare -A annotations=(
    [amd64]="--os linux --arch amd64"
    [arm32v6]="--os linux --arch arm --variant v6"
    [arm32v7]="--os linux --arch arm --variant v7"
    [arm64v8]="--os linux --arch arm64 --variant v8"
)

source ./hooks/arches.sh

set -ex

declare -A images
for arch in ${arches[@]}; do
    images[$arch]="${DOCKER_REPO}:${DOCKER_TAG}-${arch}"
done

# Push the images that were just built; manifest list creation fails if the
# images (manifests) referenced don't already exist in the Docker registry.
for image in "${images[@]}"; do
    docker push "${image}"
done

manifest_lists=("${DOCKER_REPO}:${DOCKER_TAG}")

# If the Docker tag starts with a version number, assume the latest release is
# being pushed. Add an extra manifest (`latest` or `alpine`, as appropriate)
# to make it easier for users to track the latest release.
if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
    if [[ "${DOCKER_TAG}" == *alpine ]]; then
        manifest_lists+=(${DOCKER_REPO}:alpine)
    else
        manifest_lists+=(${DOCKER_REPO}:latest)

        # Add an extra `latest-arm32v6` tag; Docker can't seem to properly
        # auto-select that image on Armv6 platforms like Raspberry Pi 1 and Zero
        # (https://github.com/moby/moby/issues/41017).
        #
        # Add this tag only for the SQLite image, as the MySQL and PostgreSQL
        # builds don't currently work on non-amd64 arches.
        #
        # TODO: Also add an `alpine-arm32v6` tag if multi-arch support for
        # Alpine-based bitwarden_rs images is implemented before this Docker
        # issue is fixed.
        if [[ ${DOCKER_REPO} == *server ]]; then
            docker tag "${DOCKER_REPO}:${DOCKER_TAG}-arm32v6" "${DOCKER_REPO}:latest-arm32v6"
            docker push "${DOCKER_REPO}:latest-arm32v6"
        fi
    fi
fi

for manifest_list in "${manifest_lists[@]}"; do
    # Create the (multi-arch) manifest list of arch-specific images.
    docker manifest create ${manifest_list} ${images[@]}

    # Make sure each image manifest is annotated with the correct arch info.
    # Docker does not auto-detect the arch of each cross-compiled image, so
    # everything would appear as `linux/amd64` otherwise.
    for arch in "${arches[@]}"; do
        docker manifest annotate ${annotations[$arch]} ${manifest_list} ${images[$arch]}
    done

    # Push the manifest list.
    docker manifest push --purge ${manifest_list}
done

# Avoid logging credentials and tokens.
set +ex

# Delete the arch-specific tags, if credentials for doing so are available.
# Note that `DOCKER_PASSWORD` must be the actual user password. Passing a JWT
# obtained using a personal access token results in a 403 error with
# {"detail": "access to the resource is forbidden with personal access token"}
if [[ -z "${DOCKER_USERNAME}" || -z "${DOCKER_PASSWORD}" ]]; then
    exit 0
fi

# Given a JSON input on stdin, extract the string value associated with the
# specified key. This avoids an extra dependency on a tool like `jq`.
extract() {
    local key="$1"
    # Extract "<key>":"<val>" (assumes key/val won't contain double quotes).
    # The colon may have whitespace on either side.
    grep -o "\"${key}\"[[:space:]]*:[[:space:]]*\"[^\"]\+\"" |
    # Extract just <val> by deleting the last '"', and then greedily deleting
    # everything up to '"'.
    sed -e 's/"$//' -e 's/.*"//'
}

echo ">>> Getting API token..."
jwt=$(curl -sS -X POST \
           -H "Content-Type: application/json" \
           -d "{\"username\":\"${DOCKER_USERNAME}\",\"password\": \"${DOCKER_PASSWORD}\"}" \
           "https://hub.docker.com/v2/users/login" |
      extract 'token')

# Strip the registry portion from `index.docker.io/user/repo`.
repo="${DOCKER_REPO#*/}"

for arch in ${arches[@]}; do
    # Don't delete the `arm32v6` tag; Docker can't seem to properly
    # auto-select that image on Armv6 platforms like Raspberry Pi 1 and Zero
    # (https://github.com/moby/moby/issues/41017).
    if [[ ${arch} == 'arm32v6' ]]; then
        continue
    fi
    tag="${DOCKER_TAG}-${arch}"
    echo ">>> Deleting '${repo}:${tag}'..."
    curl -sS -X DELETE \
         -H "Authorization: Bearer ${jwt}" \
         "https://hub.docker.com/v2/repositories/${repo}/tags/${tag}/"
done