ajhahn.de
← eeco
Shell 138 lines
#!/bin/sh
# Generates the package-manager manifests for a release from the
# already-built archives:
#   dist/eeco.rb    formula for a personal tap
#   dist/eeco.json  Windows package manifest
#
# Deterministic and offline: reads dist/SHA256SUMS (written by
# scripts/build.sh) and substitutes the version + per-archive hashes.
# Run after `make release`. Signing/attestation stay in CI only; this
# script performs no network and no git writes.
#
# Inputs (env, with defaults):
#   VERSION  git describe --tags --dirty --always, or "dev"
set -eu

VERSION="${VERSION:-$(git describe --tags --dirty --always 2>/dev/null || echo dev)}"

# Tag carries a leading "v"; the manifest version field does not.
TAG="${VERSION}"
VER="${VERSION#v}"

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
DIST="${ROOT}/dist"
SUMS="${DIST}/SHA256SUMS"

if [ ! -f "${SUMS}" ]; then
	echo "error: ${SUMS} not found; run 'make release' first" >&2
	exit 1
fi

DESC="Self-maintaining workflow ecosystem for a coding project"
HOMEPAGE="https://github.com/ajhahnde/eeco"
BASE="https://github.com/ajhahnde/eeco/releases/download/${TAG}"

# sha256 for one archive basename, read from SHA256SUMS ($NF == name
# tolerates the two-space shasum separator).
sum_for() {
	awk -v f="$1" '$NF == f { print $1 }' "${SUMS}"
}

archive() { echo "eeco_${TAG}_$1.tar.gz"; }
zipname() { echo "eeco_${TAG}_$1.zip"; }

DARWIN_AMD64="$(sum_for "$(archive darwin_amd64)")"
DARWIN_ARM64="$(sum_for "$(archive darwin_arm64)")"
LINUX_AMD64="$(sum_for "$(archive linux_amd64)")"
LINUX_ARM64="$(sum_for "$(archive linux_arm64)")"
WIN_AMD64="$(sum_for "$(zipname windows_amd64)")"
WIN_ARM64="$(sum_for "$(zipname windows_arm64)")"

for pair in \
	"darwin_amd64:${DARWIN_AMD64}" "darwin_arm64:${DARWIN_ARM64}" \
	"linux_amd64:${LINUX_AMD64}"   "linux_arm64:${LINUX_ARM64}" \
	"windows_amd64:${WIN_AMD64}"   "windows_arm64:${WIN_ARM64}"; do
	if [ -z "${pair#*:}" ]; then
		echo "error: no SHA256 for ${pair%%:*} in ${SUMS}" >&2
		exit 1
	fi
done

# Formula for a personal tap. Archives stage the binary under a
# <goos>_<goarch>/ directory (see scripts/build.sh), but Homebrew strips
# a single top-level wrapper directory on extract, so by install time the
# binary sits at the staging root — install the bare basename.
cat > "${DIST}/eeco.rb" <<EOF
class Eeco < Formula
  desc "${DESC}"
  homepage "${HOMEPAGE}"
  version "${VER}"
  license "Apache-2.0"

  on_macos do
    if Hardware::CPU.arm?
      url "${BASE}/$(archive darwin_arm64)"
      sha256 "${DARWIN_ARM64}"
    else
      url "${BASE}/$(archive darwin_amd64)"
      sha256 "${DARWIN_AMD64}"
    end
  end

  on_linux do
    if Hardware::CPU.arm?
      url "${BASE}/$(archive linux_arm64)"
      sha256 "${LINUX_ARM64}"
    else
      url "${BASE}/$(archive linux_amd64)"
      sha256 "${LINUX_AMD64}"
    end
  end

  def install
    bin.install "eeco"
    man1.install "eeco.1"
  end

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

# Windows package manifest. "bin" points at the nested staged path.
cat > "${DIST}/eeco.json" <<EOF
{
  "version": "${VER}",
  "description": "${DESC}",
  "homepage": "${HOMEPAGE}",
  "license": "Apache-2.0",
  "architecture": {
    "64bit": {
      "url": "${BASE}/$(zipname windows_amd64)",
      "hash": "${WIN_AMD64}",
      "bin": "windows_amd64\\\\eeco.exe"
    },
    "arm64": {
      "url": "${BASE}/$(zipname windows_arm64)",
      "hash": "${WIN_ARM64}",
      "bin": "windows_arm64\\\\eeco.exe"
    }
  },
  "checkver": "github",
  "autoupdate": {
    "architecture": {
      "64bit": {
        "url": "${HOMEPAGE}/releases/download/v\$version/eeco_v\$version_windows_amd64.zip"
      },
      "arm64": {
        "url": "${HOMEPAGE}/releases/download/v\$version/eeco_v\$version_windows_arm64.zip"
      }
    }
  }
}
EOF

printf 'wrote:\n  %s\n  %s\n' "${DIST}/eeco.rb" "${DIST}/eeco.json"