#!/bin/sh
set -eu

build_script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd)
. "$build_script_dir/account-gateway-sources.sh"

usage() {
  echo "usage: $0 <service> <repo> <main> <image> <cluster> <arch> <work-dir> [mode] [live-update-fallback-paths]" >&2
  exit 2
}

[ "$#" -ge 7 ] || usage

service=$1
repo=$2
main_path=$3
image=$4
cluster=$5
arch=$6
work_dir=$7
mode=${8:-generic}
fallback_paths=${9:-}

repo=$(cd "$repo" && pwd)
mkdir -p "$work_dir"
work_dir=$(cd "$work_dir" && pwd)

required_k3d_node_containers() {
  node_containers=$(k3d node list --no-headers |
    awk -v cluster="$cluster" '$3 == cluster && ($2 == "server" || $2 == "agent") { print $1 }')
  if [ -z "$node_containers" ]; then
    printf '%s\n' "[cp9 persona build] $service: k3d cluster $cluster has no server or agent nodes" >&2
    return 1
  fi
  printf '%s\n' "$node_containers"
}

docker_image_config_digest() {
  config_digest=$(docker image inspect "$image" --format '{{index .Descriptor.Annotations "config.digest"}}' 2>/dev/null || true)
  case "$config_digest" in
    sha256:*) ;;
    *) config_digest=$(docker image inspect "$image" --format '{{.Id}}' 2>/dev/null || true) ;;
  esac
  [ -n "$config_digest" ] || return 1
  printf '%s\n' "$config_digest"
}

verify_imported_image() {
  expected_config_digest=$1
  verify_attempt=0
  verify_retries=${CP9_PREMIUM_K3D_IMPORT_VERIFY_RETRIES:-12}
  verify_sleep=${CP9_PREMIUM_K3D_IMPORT_VERIFY_SLEEP_SECONDS:-2}
  node_containers=$(required_k3d_node_containers) || return 1
  while :; do
    all_visible=true
    for node_container in $node_containers; do
      if ! docker exec "$node_container" sh -c '
        image=$1
        expected_config_digest=$2
        command -v crictl >/dev/null 2>&1 || exit 1
        config_digest=$(crictl inspecti -o go-template --template '\''{{.status.id}}'\'' "$image" 2>/dev/null || true)
        [ -n "$config_digest" ] && [ "$config_digest" = "$expected_config_digest" ]
      ' sh "$image" "$expected_config_digest"; then
        all_visible=false
        break
      fi
    done
    if [ "$all_visible" = "true" ]; then
      printf '%s\n' "[cp9 persona build] $service: verified every k3d server and agent can resolve $image"
      return 0
    fi
    verify_attempt=$((verify_attempt + 1))
    if [ "$verify_attempt" -gt "$verify_retries" ]; then
      printf '%s\n' "[cp9 persona build] $service: k3d import completed but $image is not visible in every server and agent" >&2
      return 1
    fi
    printf '%s\n' "[cp9 persona build] $service: waiting for k3d node image visibility ($verify_attempt/$verify_retries)" >&2
    sleep "$verify_sleep"
  done
}

if [ -n "$fallback_paths" ]; then
  fallback_snapshot=$work_dir/live-update-fallback.tar
  fallback_snapshot_next=$work_dir/live-update-fallback.tar.next
  old_ifs=$IFS
  IFS=,
  set -- $fallback_paths
  IFS=$old_ifs
  rm -f "$fallback_snapshot_next"
  tar \
    --sort=name \
    --mtime='UTC 1970-01-01' \
    --owner=0 \
    --group=0 \
    --numeric-owner \
    --format=posix \
    --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime \
    -C "$repo" \
    -cf "$fallback_snapshot_next" "$@" \
    -C "$build_script_dir" build-local-image.sh account-gateway-sources.sh || exit 1
  if [ -s "$work_dir/image.stamp" ] && [ -f "$fallback_snapshot" ] && cmp -s "$fallback_snapshot_next" "$fallback_snapshot"; then
    stamped_config_digest=$(awk 'NR == 1 { print $1; exit }' "$work_dir/image.stamp")
    config_digest=$(docker_image_config_digest 2>/dev/null || true)
    if [ -n "$stamped_config_digest" ] && [ "$config_digest" = "$stamped_config_digest" ] && { [ -z "$cluster" ] || verify_imported_image "$stamped_config_digest"; }; then
      rm -f "$fallback_snapshot_next"
      printf '%s\n' "[cp9 persona build] $service: live-update fallback inputs unchanged; skipped image build"
      exit 0
    fi
    printf '%s\n' "[cp9 persona build] $service: snapshot matches but image visibility is stale; rebuilding"
  fi
fi

cache_root=${CP9_PREMIUM_BUILD_CACHE_DIR:-$(dirname "$work_dir")/cache}
mkdir -p "$cache_root"
cache_root=$(cd "$cache_root" && pwd)
GOCACHE=${CP9_PREMIUM_GOCACHE:-$cache_root/go-build}
mkdir -p "$GOCACHE"
GOPRIVATE=${GOPRIVATE:-github.com/tidbcloud/*}
GONOSUMDB=${GONOSUMDB:-github.com/tidbcloud/*}
export GOPRIVATE GONOSUMDB GOCACHE
goflags=${GOFLAGS:-}
case " $goflags " in
  *" -buildvcs="*) ;;
  *)
    if [ -n "$goflags" ]; then
      goflags="$goflags -buildvcs=false"
    else
      goflags="-buildvcs=false"
    fi
    ;;
esac

main_dir=$(dirname "$main_path")
build_root=$repo
if [ "$main_dir" != "." ]; then
  current=$repo/$main_dir
  while [ "$current" != "$repo" ] && [ "$current" != "/" ]; do
    if [ -f "$current/go.mod" ]; then
      build_root=$current
      break
    fi
    current=$(dirname "$current")
  done
fi
if [ ! -f "$build_root/go.mod" ]; then
  build_root=$repo
fi

rel_pkg=.
case "$main_path" in
  */*) rel_pkg=./$(dirname "$main_path") ;;
esac
case "$build_root" in
  "$repo")
    ;;
  "$repo"/*)
    rel_root=${build_root#"$repo"/}
    rel_pkg=./$(dirname "$main_path")
    rel_pkg=${rel_pkg#./$rel_root/}
    rel_pkg=./$rel_pkg
    ;;
esac

rootfs=$work_dir/rootfs
dockerfile=$work_dir/Dockerfile
rm -rf "$rootfs"
mkdir -p "$rootfs/usr/local/bin"

entrypoint=/usr/local/bin/service
case "$mode" in
  account|account-provider|account-acl|account-central|account-openapi)
    generate_account_gateway_sources \
      "$repo" "$work_dir/account-tools" "[cp9 persona build] $service"
    ;;
esac

if [ "$mode" != "account" ]; then
  binary=$work_dir/service
  printf '%s\n' "[cp9 persona build] $service: go build $rel_pkg"
  if [ -f "$build_root/go.mod" ]; then
    GOFLAGS="$goflags" \
      CGO_ENABLED=0 GOOS=linux GOARCH="$arch" \
      go -C "$build_root" build -o "$binary" "$rel_pkg"
  else
    GO111MODULE=off CGO_ENABLED=0 GOOS=linux GOARCH="$arch" \
      go -C "$build_root" build -o "$binary" "$rel_pkg"
  fi

  mkdir -p "$work_dir/live"
  cp "$binary" "$work_dir/live/service"
  chmod 755 "$work_dir/live/service"

  write_live_update_entrypoint_wrapper() {
    wrapper=$1
    mkdir -p "$(dirname "$rootfs$wrapper")"
    cat >"$rootfs$wrapper" <<'EOF'
#!/bin/sh
set -u

marker=/tmp/cp9-live-update.restart
child=0
stopping=0

marker_stamp() {
  if [ -e "$marker" ]; then
    stat -c %Y "$marker" 2>/dev/null || echo 0
    return
  fi
  echo 0
}

stop_child() {
  stopping=1
  if [ "$child" != 0 ]; then
    kill "$child" 2>/dev/null || true
  fi
}

trap stop_child INT TERM

last_stamp=$(marker_stamp)
while :; do
  /workspace/service "$@" &
  child=$!

  while kill -0 "$child" 2>/dev/null; do
    if [ "$stopping" = 1 ]; then
      wait "$child"
      exit $?
    fi
    current_stamp=$(marker_stamp)
    if [ "$current_stamp" != "$last_stamp" ]; then
      last_stamp=$current_stamp
      kill "$child" 2>/dev/null || true
      wait "$child" 2>/dev/null || true
      child=0
      break
    fi
    sleep 1
  done

  if [ "$child" != 0 ]; then
    wait "$child"
    exit $?
  fi
done
EOF
    chmod 755 "$rootfs$wrapper"
  }

  cp "$binary" "$rootfs/usr/local/bin/service"
  chmod 755 "$rootfs/usr/local/bin/service"

  case "$service" in
    tidb-mgmt-portal|tidb-mgmt-service|tempo-proxy|tempo-wrapper|nextgen-global-service|dedicated-global-service)
      # These tidb-management-service binaries run from /command/<svc>/<svc>
      # (the deployment pins `command: [/command/<svc>/<svc>]`), so stage the
      # compiled binary at both the historical `cmd` name and the service name.
      mkdir -p "$rootfs/command/$service"
      cp "$binary" "$rootfs/command/$service/cmd"
      chmod 755 "$rootfs/command/$service/cmd"
      cp "$binary" "$rootfs/command/$service/$service"
      chmod 755 "$rootfs/command/$service/$service"
      ;;
  esac
fi

case "$mode" in
  account)
    for account_binary in account-provider account-acl account-central; do
      case "$account_binary" in
        account-provider) account_pkg=./central/cmd/provider ;;
        account-acl) account_pkg=./central/cmd/acl ;;
        account-central) account_pkg=./central/cmd/central ;;
      esac
      printf '%s\n' "[cp9 persona build] $service: go build $account_pkg"
      GOFLAGS="$goflags" \
        CGO_ENABLED=0 GOOS=linux GOARCH="$arch" \
        go -C "$repo" build -o "$rootfs/usr/local/bin/$account_binary" "$account_pkg"
      chmod 755 "$rootfs/usr/local/bin/$account_binary"
    done
    entrypoint=/usr/local/bin/account-provider
    ;;
  account-provider|account-acl|account-central|account-openapi)
    entrypoint=/usr/local/bin/$mode
    mv "$rootfs/usr/local/bin/service" "$rootfs$entrypoint"
    ;;
  cluster-ng-server)
    if [ -d "$repo/deployments/templates" ]; then
      mkdir -p "$rootfs/templates"
      cp -R "$repo/deployments/templates"/. "$rootfs/templates/"
      if [ -f "$rootfs/templates/tidb_cluster.templ" ]; then
        sed -i.bak \
          -e '/name: UsePDReadyAPIV2/d' \
          -e '/name: UseSchedulingReadyAPI/d' \
          -e '/name: UseTiKVReadyAPI/d' \
          -e '/name: UseTiFlashReadyAPI/d' \
          "$rootfs/templates/tidb_cluster.templ" && rm -f "$rootfs/templates/tidb_cluster.templ.bak"
      fi
    fi
    entrypoint=/cluster_ng_server
    mv "$rootfs/usr/local/bin/service" "$rootfs$entrypoint"
    ;;
  cluster-ng-executor)
    if [ -d "$repo/deployments/templates" ]; then
      mkdir -p "$rootfs/templates"
      cp -R "$repo/deployments/templates"/. "$rootfs/templates/"
      if [ -f "$rootfs/templates/tidb_cluster.templ" ]; then
        sed -i.bak \
          -e '/name: UsePDReadyAPIV2/d' \
          -e '/name: UseSchedulingReadyAPI/d' \
          -e '/name: UseTiKVReadyAPI/d' \
          -e '/name: UseTiFlashReadyAPI/d' \
          "$rootfs/templates/tidb_cluster.templ" && rm -f "$rootfs/templates/tidb_cluster.templ.bak"
      fi
    fi
    entrypoint=/executor
    mv "$rootfs/usr/local/bin/service" "$rootfs$entrypoint"
    ;;
  config-center-regional|config-center)
    # Both the regional and the shared-base global config-center build from the
    # config-center repo (bin/server -> /config-center, ENTRYPOINT ["/config-center"])
    # and read migrations staged under /workspace/migration.
    if [ -d "$repo/migration" ]; then
      mkdir -p "$rootfs/workspace/migration"
      cp -R "$repo/migration"/. "$rootfs/workspace/migration/"
    fi
    entrypoint=/config-center
    mv "$rootfs/usr/local/bin/service" "$rootfs$entrypoint"
    ;;
  ticdc-service)
    entrypoint=/manager
    mv "$rootfs/usr/local/bin/service" "$rootfs$entrypoint"
    ;;
  dataflow)
    entrypoint=/dataflow
    mv "$rootfs/usr/local/bin/service" "$rootfs$entrypoint"
    ;;
  dedicated-dataflow-svc)
    entrypoint=/dataflow
    mv "$rootfs/usr/local/bin/service" "$rootfs$entrypoint"
    ;;
  dataplane-manager)
    if [ -d "$repo/helm" ]; then
      mkdir -p "$rootfs/etc/helm"
      cp -R "$repo/helm"/. "$rootfs/etc/helm/"
    fi
    ;;
esac
case "$service" in
  dataflow|dedicated-dataflow-svc|ticdc-service|dataplane-manager|account-provider|account-acl|account-central|cluster-controller|cluster-control-server|regional-server|regional-tcidm-service|dedicated-ticdc-service|config-center|dedicated-global-service|tidb-mgmt-portal|tidb-mgmt-service|nextgen-global-service|cluster-ng-server|cluster-ng-executor|config-center-regional)
    mkdir -p "$rootfs/workspace"
    cp "$binary" "$rootfs/workspace/service"
    chmod 755 "$rootfs/workspace/service"
    # The live-update wrapper must live at the path the deployment's `command`
    # invokes, so the image entrypoint the container starts is the wrapper (which
    # re-execs /workspace/service on live-update). The Dedicated app-delivery
    # base workloads pin `command: [/eks-provider]` (cluster-controller) and
    # `command: [/server]` (cluster-control-server) — the staging binary paths —
    # so the source-built wrapper is staged there too, leaving staging behavior
    # unchanged while source-build boots through its own entrypoint.
    # dedicated-ticdc-service pins `command: [/manager]` (infra-provider/ticdc-service
    # Dockerfile ENTRYPOINT ["/manager"]); regional-tcidm-service pins
    # `command: [regional_tcidm_service]` (tcidm Dockerfile installs the binary at
    # /usr/local/bin/regional_tcidm_service, resolved via PATH); regional-server sets
    # no command and boots through the image entrypoint, so the wrapper matches the
    # infra-provider/regional-server Dockerfile ENTRYPOINT ["/regional-server"].
    # config-center pins `command: [/config-center]`; dedicated-global-service pins
    # `command: [/command/dedicated-global-service/dedicated-global-service]`, so
    # the wrapper is staged over that /command binary while /workspace/service holds
    # the live-updatable binary.
    case "$service" in
      dataflow) live_update_wrapper=/dataflow ;;
      dedicated-dataflow-svc) live_update_wrapper=/dataflow ;;
      ticdc-service) live_update_wrapper=/manager ;;
      dataplane-manager) live_update_wrapper=/usr/local/bin/service ;;
      account-provider|account-acl|account-central) live_update_wrapper=/usr/local/bin/$service ;;
      cluster-controller) live_update_wrapper=/eks-provider ;;
      cluster-control-server) live_update_wrapper=/server ;;
      regional-server) live_update_wrapper=/regional-server ;;
      regional-tcidm-service) live_update_wrapper=/usr/local/bin/regional_tcidm_service ;;
      dedicated-ticdc-service) live_update_wrapper=/manager ;;
      config-center) live_update_wrapper=/config-center ;;
      dedicated-global-service) live_update_wrapper=/command/dedicated-global-service/dedicated-global-service ;;
      tidb-mgmt-portal) live_update_wrapper=/command/tidb-mgmt-portal/tidb-mgmt-portal ;;
      tidb-mgmt-service) live_update_wrapper=/command/tidb-mgmt-service/tidb-mgmt-service ;;
      nextgen-global-service) live_update_wrapper=/command/nextgen-global-service/nextgen-global-service ;;
      cluster-ng-server) live_update_wrapper=/cluster_ng_server ;;
      cluster-ng-executor) live_update_wrapper=/executor ;;
      config-center-regional) live_update_wrapper=/config-center ;;
    esac
    write_live_update_entrypoint_wrapper "$live_update_wrapper"
    entrypoint=$live_update_wrapper
    ;;
esac

needs_aws_iam_authenticator=false
case "$mode" in
  dataplane-manager|cluster-ng-server|cluster-ng-executor|cluster-controller|regional-server|ticdc-service|dedicated-ticdc-service)
    # These controllers reach the dataplane EKS through a kubeconfig, so their
    # Dockerfiles install aws-iam-authenticator; regional-tcidm-service (tcidm) does not.
    needs_aws_iam_authenticator=true
    ;;
esac

# The Dedicated cluster-controller and regional-server read packaged helm charts
# from /etc/helm at runtime; their Dockerfiles stage them from the monorepo root
# (`COPY helm-charts/* /etc/helm`). Each source repo is a module dir under
# infra-provider (cluster-controller, regional-server), so the charts live one
# level up at infra-provider/helm-charts.
if { [ "$mode" = "cluster-controller" ] || [ "$mode" = "regional-server" ]; } && [ -d "$repo/../helm-charts" ]; then
  mkdir -p "$rootfs/etc/helm"
  cp -R "$repo"/../helm-charts/. "$rootfs/etc/helm/"
fi

# Source checkouts inherit the caller's umask. Normalize all runtime assets so
# the distroless non-root user can traverse directories and read copied files.
chmod -R a+rX "$rootfs"

if [ "$needs_aws_iam_authenticator" = "true" ]; then
  cat >"$dockerfile" <<EOF
FROM public.ecr.aws/docker/library/alpine:3.19
ARG TARGETARCH
ARG AWS_IAM_AUTHENTICATOR_VERSION=0.7.8
ARG AWS_IAM_AUTHENTICATOR_SHA256_AMD64=19145c00f8492253e63d2eb9019fa907b528deffa6b7f2e205e860e213b8e8d6
ARG AWS_IAM_AUTHENTICATOR_SHA256_ARM64=529621b7abbb72722b6a7fe1af743a82bb7942129a3ec6c26aa9ac4098323b69
COPY rootfs/ /
RUN apk add --no-cache ca-certificates wget && update-ca-certificates && \\
    auth_arch="\${TARGETARCH:-amd64}" && \\
    case "\${auth_arch}" in \\
      amd64) auth_sha256="\${AWS_IAM_AUTHENTICATOR_SHA256_AMD64}" ;; \\
      arm64) auth_sha256="\${AWS_IAM_AUTHENTICATOR_SHA256_ARM64}" ;; \\
      *) echo "unsupported aws-iam-authenticator arch: \${auth_arch}" >&2; exit 1 ;; \\
    esac && \\
    wget -O /usr/local/bin/aws-iam-authenticator "https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v\${AWS_IAM_AUTHENTICATOR_VERSION}/aws-iam-authenticator_\${AWS_IAM_AUTHENTICATOR_VERSION}_linux_\${auth_arch}" && \\
    echo "\${auth_sha256}  /usr/local/bin/aws-iam-authenticator" | sha256sum -c - && \\
    chmod +x /usr/local/bin/aws-iam-authenticator && \\
    mkdir -p /workspace && chown -R 65532:65532 /workspace
WORKDIR /workspace
USER 65532:65532
ENTRYPOINT ["$entrypoint"]
EOF
else
  cat >"$dockerfile" <<EOF
FROM public.ecr.aws/docker/library/alpine:3.19
COPY rootfs/ /
RUN apk add --no-cache ca-certificates && update-ca-certificates && mkdir -p /workspace && chown -R 65532:65532 /workspace
WORKDIR /workspace
USER 65532:65532
ENTRYPOINT ["$entrypoint"]
EOF
fi

if [ "$mode" = "config-center-regional" ]; then
  cat >"$dockerfile" <<EOF
FROM public.ecr.aws/docker/library/debian:12
COPY rootfs/ /
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/* && mkdir -p /workspace && chown -R 65532:65532 /workspace
WORKDIR /workspace
USER 65532:65532
ENTRYPOINT ["$entrypoint"]
EOF
fi

docker_buildx_image() {
  DOCKER_BUILDKIT=1 docker buildx build \
    --load \
    --provenance=false \
    "$@" \
    --platform="linux/$arch" \
    -t "$image" \
    -f "$dockerfile" \
    "$work_dir"
}

docker_build_image() {
  docker_cache=$cache_root/docker-buildx/$arch
  docker_cache_next=$cache_root/docker-buildx-next/$arch
  mkdir -p "$docker_cache" "$(dirname "$docker_cache_next")"
  if docker buildx version >/dev/null 2>&1; then
    buildx_driver=$(docker buildx inspect 2>/dev/null | awk '$1 == "Driver:" { print $2; exit }' || true)
    if [ "$buildx_driver" = "docker" ] || [ -z "$buildx_driver" ]; then
      printf '%s\n' "[cp9 persona build] $service: docker buildx build $image (buildx driver ${buildx_driver:-unknown}; local cache export unavailable; daemon cache only)"
      docker_buildx_image
      return
    fi
    rm -rf "$docker_cache_next"
    printf '%s\n' "[cp9 persona build] $service: docker buildx build $image (cache $docker_cache)"
    if [ -f "$docker_cache/index.json" ]; then
      docker_buildx_image \
        --cache-from "type=local,src=$docker_cache" \
        --cache-to "type=local,dest=$docker_cache_next,mode=max"
    else
      docker_buildx_image --cache-to "type=local,dest=$docker_cache_next,mode=max"
    fi
    rm -rf "$docker_cache"
    mv "$docker_cache_next" "$docker_cache"
    return
  fi
  printf '%s\n' "[cp9 persona build] $service: docker build $image (buildx unavailable; daemon cache only)"
  DOCKER_BUILDKIT=1 docker build --platform="linux/$arch" -t "$image" -f "$dockerfile" "$work_dir"
}

write_image_stamp() {
  stamp_tmp=$work_dir/image.stamp.tmp.$$
  config_digest=$(docker_image_config_digest 2>/dev/null || true)
  if [ -z "$config_digest" ]; then
    printf '%s\n' "[cp9 persona build] $service: docker build completed but $image is not visible to docker image inspect" >&2
    return 1
  fi
  build_time=$(date -u +%Y%m%dT%H%M%SZ)
  printf '%s\n' "$config_digest $build_time" >"$stamp_tmp"
  mv "$stamp_tmp" "$work_dir/image.stamp"
  printf '%s\n' "[cp9 persona build] $service: wrote image rollout stamp $work_dir/image.stamp"
}

docker_build_image

if [ -n "$cluster" ]; then
  printf '%s\n' "[cp9 persona build] $service: import $image into k3d cluster $cluster"
  import_image() {
    node_containers=$(required_k3d_node_containers) || return 1
    import_archive=$work_dir/k3d-image.tar
    rm -f "$import_archive"
    if ! docker save -o "$import_archive" "$image"; then
      rm -f "$import_archive"
      return 1
    fi
    for node_container in $node_containers; do
      if ! docker exec -i "$node_container" ctr -n k8s.io images import --platform "linux/$arch" - <"$import_archive"; then
        rm -f "$import_archive"
        return 1
      fi
    done
    rm -f "$import_archive"
  }
  import_and_verify_image() {
    expected_config_digest=$(docker_image_config_digest)
    import_image
    verify_imported_image "$expected_config_digest"
  }
  if [ "${CP9_PREMIUM_SERIALIZE_IMAGE_IMPORT:-true}" = "true" ]; then
    lock_dir=${CP9_PREMIUM_IMAGE_IMPORT_LOCK_DIR:-.cp9-build/locks}
    mkdir -p "$lock_dir"
    lock_name=$(printf '%s' "$cluster" | tr -c 'A-Za-z0-9_.-' '_')
    lock_path=$lock_dir/k3d-image-import-$lock_name.lockdir
    lock_wait=0
    while ! mkdir "$lock_path" 2>/dev/null; do
      lock_wait=$((lock_wait + 1))
      if [ "$lock_wait" -gt 300 ]; then
        echo "timed out waiting for k3d image import lock $lock_path" >&2
        exit 1
      fi
      sleep 1
    done
    trap 'rmdir "$lock_path" 2>/dev/null || true' EXIT INT TERM HUP
    if ! import_and_verify_image; then
      exit 1
    fi
    rmdir "$lock_path"
    trap - EXIT INT TERM HUP
  else
    if ! import_and_verify_image; then
      exit 1
    fi
  fi
fi
write_image_stamp

if [ -n "${fallback_snapshot_next:-}" ]; then
  mv "$fallback_snapshot_next" "$fallback_snapshot"
fi
