#!/usr/bin/env bash

set -eu -o pipefail

: ${BUILDX_CMD=docker buildx}
: ${BUILDKIT_IMAGE=moby/buildkit:buildx-stable-1}
: ${BUILDKIT_CFG=}
: ${DRIVER=docker-container}
: ${DRIVER_OPT=}
: ${ENDPOINT=}
: ${MULTI_NODE=0}
: ${PLATFORMS=linux/amd64,linux/arm64}

function buildxCmd {
  (set -x ; $BUILDX_CMD "$@")
}

function clean {
  rm -rf "$context"
  if [ "$builderName" != "default" ]; then
    buildxCmd rm "$builderName"
  fi
}

context=$(mktemp -d -t buildx-output.XXXXXXXXXX)
dockerfile=${context}/Dockerfile
bakedef=${context}/docker-bake.hcl
trap clean EXIT

builderName=buildx-test-$(openssl rand -hex 16)
buildPlatformFlag=
if [ "$DRIVER" = "docker" ]; then
  builderName=default
else
  buildPlatformFlag=--platform="${PLATFORMS}"
fi

if [ "$DRIVER" != "remote" ]; then
  driverOpt=${driverOpt:+"${driverOpt},"}image=${BUILDKIT_IMAGE}
fi
if [ -n "$DRIVER_OPT" ]; then
  driverOpt=${driverOpt:+"${driverOpt},"}$DRIVER_OPT
fi

# create builder except for docker driver
if [ "$DRIVER" != "docker" ]; then
  if [ "${MULTI_NODE}" = "1" ]; then
    firstNode=1
    for platform in ${PLATFORMS//,/ }; do
      createFlags=""
      if [ -f "$BUILDKIT_CFG" ]; then
        createFlags="$createFlags --config=${BUILDKIT_CFG}"
      fi
      if [ "$firstNode" = "0" ]; then
        createFlags="$createFlags --append"
      fi
      buildxCmd create ${createFlags} \
        --bootstrap \
        --name="${builderName}" \
        --node="${builderName}-${platform/\//-}" \
        --platform="${platform}" \
        --driver="${DRIVER}" \
        ${driverOpt:+"--driver-opt=${driverOpt}"} \
        ${ENDPOINT}
      firstNode=0
    done
  else
    createFlags=""
    if [ -f "$BUILDKIT_CFG" ]; then
      createFlags="$createFlags --config=${BUILDKIT_CFG}"
    fi
    buildxCmd create ${createFlags} \
      --bootstrap \
      --name="${builderName}" \
      --platform="${PLATFORMS}" \
      --driver="${DRIVER}" \
      ${driverOpt:+"--driver-opt=${driverOpt}"} \
      ${ENDPOINT}
  fi
fi

function buildOutput {
  local name=$1
  if [ "$DRIVER" != "docker" ]; then
    if [ "${MULTI_NODE}" = "1" ]; then
      echo "type=cacheonly"
    else
      echo "type=oci,dest=${context}/${name}.tar"
    fi
  else
    echo "type=docker,name=${name}"
  fi
}

# multi-platform not supported by docker driver
buildPlatformFlag=
bakePlatformFlag=
if [ "$DRIVER" != "docker" ]; then
  buildPlatformFlag=--platform="${PLATFORMS}"
  bakePlatformFlag=--set="*.platform=${PLATFORMS}"
fi

# inspect and bootstrap
buildxCmd inspect --bootstrap --builder="${builderName}"

# create dockerfile
cat > "${dockerfile}" <<EOL
FROM busybox as build
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "I am running on \$BUILDPLATFORM, building for \$TARGETPLATFORM" > /log

FROM busybox AS log
COPY --from=build /log /log
RUN cat /log
RUN uname -a

FROM busybox AS hello
RUN echo hello > /hello

FROM scratch
COPY --from=log /log /log
COPY --from=hello /hello /hello
EOL

# build
buildxCmd build ${buildPlatformFlag} \
  --output="$(buildOutput buildx-test-build)" \
  --builder="${builderName}" \
  --metadata-file="${context}/metadata-build.json" \
  "${context}"
cat "${context}/metadata-build.json"

# create bake def
cat > "${bakedef}" <<EOL
group "default" {
  targets = ["release"]
}
group "all" {
  targets = ["log", "hello"]
}
target "release" {
  output = ["$(buildOutput buildx-test-bake-release)"]
}
target "log" {
  output = ["$(buildOutput buildx-test-bake-log)"]
}
target "hello" {
  output = ["$(buildOutput buildx-test-bake-hello)"]
}
EOL

# bake default target
buildxCmd bake ${bakePlatformFlag} \
  --file="${bakedef}" \
  --builder="${builderName}" \
  --set "*.context=${context}" \
  --metadata-file="${context}/metadata-bake-def.json"
cat "${context}/metadata-bake-def.json"

# bake all target
buildxCmd bake ${bakePlatformFlag} \
  --file="${bakedef}" \
  --builder="${builderName}" \
  --set "*.context=${context}" \
  --metadata-file="${context}/metadata-bake-all.json" \
  all
cat "${context}/metadata-bake-all.json"
