#!/usr/bin/env bash
#
# Builds the `warmbly` CLI for every platform we publish, packages each one,
# and writes the manifests the package managers read.
#
# Run by the release workflow and by `make cli-dist`, so a release artifact can
# be reproduced locally byte for byte given the same VERSION and COMMIT.
#
#   ./scripts/build-cli.sh dist
#
# Assets are named without the version on purpose: the install script resolves
# https://github.com/warmbly/warmbly/releases/latest/download/warmbly_<os>_<arch>.tar.gz
# with no GitHub API call, and the unauthenticated API's rate limit is exactly
# what breaks a curl installer on a shared CI runner.
set -euo pipefail

cd "$(dirname "$0")/.."

OUT=${1:-dist}
REPO=warmbly/warmbly
MODULE=github.com/warmbly/warmbly

VERSION=${VERSION:-$(git describe --tags --always --dirty 2>/dev/null || echo dev)}
COMMIT=${COMMIT:-$(git rev-parse HEAD 2>/dev/null || echo "")}
BUILT_AT=${BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}

# Every platform the install script and the package managers know how to ask
# for. Keep this list and the one in site/public/cli.sh in step; the installer
# check verifies they agree.
PLATFORMS="darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64 windows/arm64"

LDFLAGS="-s -w
  -X ${MODULE}/internal/version.Version=${VERSION}
  -X ${MODULE}/internal/version.Commit=${COMMIT}
  -X ${MODULE}/internal/version.BuiltAt=${BUILT_AT}"

# macOS ships shasum and not GNU sha256sum, and this script is meant to be
# reproducible on a maintainer's laptop as well as on the release runner.
sha256_all() {
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$@"
  else
    shasum -a 256 "$@"
  fi
}

rm -rf "$OUT"
mkdir -p "$OUT"

# Completions ship inside every archive so the install script can drop them in
# without running the binary it just downloaded, which it cannot do for a
# cross-platform install anyway.
stage_completions() {
  local host_bin=$1 dest=$2
  mkdir -p "$dest"
  for shell in bash zsh fish powershell; do
    "$host_bin" completion "$shell" > "$dest/warmbly.$shell" 2>/dev/null || true
  done
}

echo "building warmbly ${VERSION}"

host_bin="$OUT/.host/warmbly"
mkdir -p "$OUT/.host"
# shellcheck disable=SC2086
go build -ldflags="$LDFLAGS" -o "$host_bin" ./cmd/cli

completions="$OUT/.completions"
stage_completions "$host_bin" "$completions"

for target in $PLATFORMS; do
  os=${target%/*}
  arch=${target#*/}
  ext=""
  if [ "$os" = "windows" ]; then ext=".exe"; fi

  stage="$OUT/.stage/warmbly_${os}_${arch}"
  mkdir -p "$stage"
  echo "  $os/$arch"
  # shellcheck disable=SC2086
  CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" \
    go build -ldflags="$LDFLAGS" -o "$stage/warmbly${ext}" ./cmd/cli

  cp LICENSE README.md "$stage/"
  cp -r "$completions" "$stage/completions"

  if [ "$os" = "windows" ]; then
    (cd "$stage" && zip -qr "../../warmbly_${os}_${arch}.zip" .)
  else
    tar -czf "$OUT/warmbly_${os}_${arch}.tar.gz" -C "$stage" .
  fi
done

rm -rf "$OUT/.stage" "$OUT/.host" "$OUT/.completions"

(cd "$OUT" && sha256_all warmbly_* > checksums.txt)
echo
cat "$OUT/checksums.txt"

# ─────────────────────────────────────────────────────────────────────────
# Package manager manifests
#
# Written here rather than by hand so the checksums in them can never drift
# from the archives they describe, which is the failure mode that makes a tap
# install fail for everyone at once.
# ─────────────────────────────────────────────────────────────────────────

sum_for() { awk -v f="$1" '$2 == f { print $1 }' "$OUT/checksums.txt"; }

BASE="https://github.com/${REPO}/releases/download/${VERSION}"

cat > "$OUT/warmbly.rb" <<EOF
# Homebrew formula for the Warmbly CLI. Generated by scripts/build-cli.sh;
# the release workflow pushes it to the warmbly/homebrew-tap repository.
class Warmbly < Formula
  desc "Warmbly from the command line: campaigns, contacts, mailboxes, inbox"
  homepage "https://warmbly.com"
  version "${VERSION#v}"
  license "Apache-2.0"

  on_macos do
    on_intel do
      url "${BASE}/warmbly_darwin_amd64.tar.gz"
      sha256 "$(sum_for warmbly_darwin_amd64.tar.gz)"
    end
    on_arm do
      url "${BASE}/warmbly_darwin_arm64.tar.gz"
      sha256 "$(sum_for warmbly_darwin_arm64.tar.gz)"
    end
  end

  on_linux do
    on_intel do
      url "${BASE}/warmbly_linux_amd64.tar.gz"
      sha256 "$(sum_for warmbly_linux_amd64.tar.gz)"
    end
    on_arm do
      url "${BASE}/warmbly_linux_arm64.tar.gz"
      sha256 "$(sum_for warmbly_linux_arm64.tar.gz)"
    end
  end

  def install
    bin.install "warmbly"
    bash_completion.install "completions/warmbly.bash" => "warmbly"
    zsh_completion.install "completions/warmbly.zsh" => "_warmbly"
    fish_completion.install "completions/warmbly.fish" => "warmbly.fish"
  end

  test do
    assert_match "warmbly", shell_output("#{bin}/warmbly version")
  end
end
EOF

cat > "$OUT/warmbly.json" <<EOF
{
  "version": "${VERSION#v}",
  "description": "Warmbly from the command line: campaigns, contacts, mailboxes, inbox",
  "homepage": "https://warmbly.com",
  "license": "Apache-2.0",
  "architecture": {
    "64bit": {
      "url": "${BASE}/warmbly_windows_amd64.zip",
      "hash": "$(sum_for warmbly_windows_amd64.zip)"
    },
    "arm64": {
      "url": "${BASE}/warmbly_windows_arm64.zip",
      "hash": "$(sum_for warmbly_windows_arm64.zip)"
    }
  },
  "bin": "warmbly.exe",
  "checkver": {
    "github": "https://github.com/${REPO}"
  },
  "autoupdate": {
    "architecture": {
      "64bit": {
        "url": "https://github.com/${REPO}/releases/download/v\$version/warmbly_windows_amd64.zip"
      },
      "arm64": {
        "url": "https://github.com/${REPO}/releases/download/v\$version/warmbly_windows_arm64.zip"
      }
    }
  }
}
EOF

echo
echo "wrote $OUT/ (archives, checksums.txt, warmbly.rb, warmbly.json)"
