#!/bin/bash

set -euo pipefail

if [[ $# != 4 || "$1" == '--help' || "$1" == '-h' ]]; then
  cat <<USAGE
Usage: $0 REGISTRY IMAGE TAG OUTPUT_DIRECTORY

For example, '$0 infra.docker.zooxlabs.com driving 50 path/to/package' will
create '//path/to/package' which can be used as a base image for rules_docker
images. See the README at $(dirname $0) for more information.
USAGE
  exit
fi

registry=$1
image=$2
tag=$3
package=$4

full_image_name=$1/$2:$3
temp_directory=$(mktemp --directory)
target_package=$(pwd)/$package
package_basename=$(basename "$target_package")

echo Creating $target_package...
mkdir --parents "$target_package"

cleanup() {
  echo Deleting $temp_directory...
  rm -rf "$temp_directory"
}
trap cleanup EXIT

cd "$temp_directory"
echo Working directory: $temp_directory

function write_manifest {
  echo Downloading manifest json...
  curl \
    --header "Accept: application/vnd.docker.distribution.manifest.v2+json" \
    --header "Authorization: JWT surprisingly-this-can-be-anything" \
    --insecure \
    "https://$registry/v2/$image/manifests/$tag" \
   | sed 's|application/vnd.docker.image.rootfs.diff.tar.gzip|application/vnd.docker.image.rootfs.foreign.diff.tar.gzip|' \
   | jq . \
   > "$target_package"/manifest.json
}

function write_config {
  echo Pulling $full_image_name...
  docker pull "$full_image_name"

  echo Creating tarball...
  docker save "$full_image_name" --output image.tar

  echo Extracting config json...
  image_path=$(
    tar --list --file image.tar |
    grep '\.json$' |
    grep --invert-match 'manifest\.json'
  )
  tar --extract --file image.tar "$image_path"
  # Copy and pretty print it to the output package.
  cat *.json | jq . > "$target_package"/config.json
}

function write_build_file {
  echo Writing "$target_package"/BUILD

  cat <<EOF > "$target_package"/BUILD
load("@io_bazel_rules_docker//container:container.bzl", "container_import")

# NOTE: This file is autogenerated from ./docker_images/bazel_package/create.sh.

container_import(
    name = "$package_basename",
    config = "config.json",
    layers = [],
    manifest = "manifest.json",
    visibility = ["//visibility:public"],
)
EOF
}

function write_pull_script {
  echo Writing "$target_package"/pull.sh

  cat <<EOF > "$target_package"/pull.sh
#!/bin/bash

# NOTE: This file is autogenerated from ./docker_images/bazel_package/create.sh.

set -euo pipefail

echo Pulling $full_image_name

docker pull "$full_image_name"
EOF
  chmod +x "$target_package"/pull.sh
}

function write_readme {
  echo Writing "$target_package"/README.md

  cat <<EOF > "$target_package"/README.md
# $package_basename

This package provides \`$full_image_name\` as a base image for use in
rules_docker. This is a "shallow" image in that none of the base layers are
included in Bazel. More information can be found at
docker_images/bazel_package/README.md.

 - Run './pull.sh' to pull the base image
 - Run \`./docker_images/bazel_package/create.sh $registry $image <new-tag> $package\` with an updated tag to update the
   base image

It's recommended to commit the Dockerfile in this directory so a new base image
can be created by running \`docker build . --tag $registry/$image:<new-tag>\`.

NOTE: This file is autogenerated from
\`./docker_images/bazel_package/create.sh\`.
EOF
}

write_manifest
write_config
write_build_file
write_pull_script
write_readme
