check / check (push) Failing after 3s
gofumpt and protoc-gen-go are tools of a separate Go module in bin/tools, so `go tool` builds them from source checked against bin/tools/go.sum and mfer's own module gains no dependencies. script/bootstrap downloads that module, and unpacks protoc 33.4 into bin/protoc from its release archive after checking the sha256 it holds for the platform. script/generate runs that protoc with the pinned plugin, so mfer/mf.go and its go:generate line go. script/prettier runs only the node_modules prettier, fails when it differs from the package.json pin, finds the node bootstrap installed through nvm by the version in .nvmrc, and runs prettier once. Comment and package.json fixes. Model: opus-5-5
209 lines
6.9 KiB
Bash
Executable File
209 lines
6.9 KiB
Bash
Executable File
#!/bin/sh
|
|
# script/bootstrap: install all dependencies needed to build and develop
|
|
# this repo. Idempotent: every install is guarded by a check so already
|
|
# installed tools are skipped. Base tooling comes from nix, apt, brew,
|
|
# or apk (detected in that order); assumes NOTHING is present (not git,
|
|
# make, node, yarn, go, or python). Node is used directly if installed;
|
|
# otherwise a pinned version is installed via nvm (installing nvm
|
|
# itself first, from a hash-verified release archive, never curl | sh).
|
|
#
|
|
# Uncomment the language sections in main() that apply to this repo.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
# Pinned versions, 2026-07-06. Never "latest" or "lts"; exact versions.
|
|
# The node version is in .nvmrc, where script/prettier reads it too.
|
|
NODE_VERSION="$(cat "$ROOT/.nvmrc")"
|
|
NVM_VERSION="0.40.3"
|
|
# sha256 of https://github.com/nvm-sh/nvm/archive/refs/tags/v0.40.3.tar.gz
|
|
NVM_SHA256="5f4d6aaa04a177dc93c985e31dbc411ab6b8c6e1e21d8015dbc1372625fcd1d0"
|
|
YARN_VERSION="1.22.22"
|
|
# protoc v33.4, 2026-10-04, for script/generate. The sha256 of each
|
|
# platform's release archive is in ensure_protoc.
|
|
PROTOC_VERSION="33.4"
|
|
|
|
PKGMGR=""
|
|
SUDO=""
|
|
|
|
detect_pkgmgr() {
|
|
[ -n "$PKGMGR" ] && return 0
|
|
if command -v nix-env >/dev/null 2>&1; then
|
|
PKGMGR="nix"
|
|
elif command -v apt-get >/dev/null 2>&1; then
|
|
PKGMGR="apt"
|
|
elif command -v brew >/dev/null 2>&1; then
|
|
PKGMGR="brew"
|
|
elif command -v apk >/dev/null 2>&1; then
|
|
PKGMGR="apk"
|
|
else
|
|
echo "bootstrap: no supported package manager (nix, apt, brew, apk)" >&2
|
|
exit 1
|
|
fi
|
|
if [ "$PKGMGR" = "apt" ]; then
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
if [ "$(id -u)" != "0" ]; then
|
|
SUDO="sudo"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# pkg_install <nix-attr> <apt-pkg> <brew-formula> <apk-pkg>
|
|
pkg_install() {
|
|
detect_pkgmgr
|
|
case "$PKGMGR" in
|
|
nix) nix-env -iA "nixpkgs.$1" ;;
|
|
apt) $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y "$2" ;;
|
|
brew) brew install "$3" ;;
|
|
apk) apk add --no-cache "$4" ;;
|
|
esac
|
|
}
|
|
|
|
missing() {
|
|
! command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# verify_sha256 <file> <expected-hash>
|
|
verify_sha256() {
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
actual="$(sha256sum "$1" | cut -d' ' -f1)"
|
|
else
|
|
actual="$(shasum -a 256 "$1" | cut -d' ' -f1)"
|
|
fi
|
|
if [ "$actual" != "$2" ]; then
|
|
echo "bootstrap: sha256 mismatch for $1" >&2
|
|
echo " expected: $2" >&2
|
|
echo " actual: $actual" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# nvm is a bash script; run a command in a bash with nvm loaded.
|
|
# --no-use: otherwise loading nvm here switches to the version .nvmrc
|
|
# names, and fails silently while that version is not installed yet.
|
|
nvm_sh() {
|
|
bash -c ". \"\$HOME/.nvm/nvm.sh\" --no-use && $*"
|
|
}
|
|
|
|
ensure_nvm() {
|
|
[ -s "$HOME/.nvm/nvm.sh" ] && return 0
|
|
# nvm prerequisites; nvm itself requires bash, so install it too
|
|
if missing bash; then pkg_install bash bash bash bash; fi
|
|
if missing curl; then pkg_install curl curl curl curl; fi
|
|
if missing git; then pkg_install git git git git; fi
|
|
tmp="$(mktemp -d)"
|
|
curl -fsSL -o "$tmp/nvm.tar.gz" \
|
|
"https://github.com/nvm-sh/nvm/archive/refs/tags/v${NVM_VERSION}.tar.gz"
|
|
verify_sha256 "$tmp/nvm.tar.gz" "$NVM_SHA256"
|
|
mkdir -p "$HOME/.nvm"
|
|
tar -xzf "$tmp/nvm.tar.gz" -C "$HOME/.nvm" --strip-components=1
|
|
rm -rf "$tmp"
|
|
}
|
|
|
|
ensure_node() {
|
|
if ! missing node; then return 0; fi
|
|
ensure_nvm
|
|
nvm_sh "nvm install $NODE_VERSION"
|
|
}
|
|
|
|
ensure_yarn() {
|
|
if ! missing yarn; then return 0; fi
|
|
if ! missing corepack; then
|
|
corepack enable
|
|
corepack prepare "yarn@$YARN_VERSION" --activate
|
|
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
|
|
nvm_sh "nvm use $NODE_VERSION >/dev/null && corepack enable && \
|
|
corepack prepare yarn@$YARN_VERSION --activate"
|
|
else
|
|
npm install -g "yarn@$YARN_VERSION"
|
|
fi
|
|
}
|
|
|
|
install_js_deps() {
|
|
if missing yarn && [ -s "$HOME/.nvm/nvm.sh" ]; then
|
|
nvm_sh "nvm use $NODE_VERSION >/dev/null && cd \"$ROOT\" && \
|
|
yarn install --frozen-lockfile"
|
|
else
|
|
yarn install --frozen-lockfile
|
|
fi
|
|
}
|
|
|
|
# Unpack protoc's release archive for this platform into bin/protoc, after
|
|
# checking the archive's sha256, unless bin/protoc already holds the pinned
|
|
# version.
|
|
ensure_protoc() {
|
|
dir="$ROOT/bin/protoc"
|
|
if [ "$("$dir/bin/protoc" --version 2>/dev/null)" = \
|
|
"libprotoc $PROTOC_VERSION" ]; then
|
|
return 0
|
|
fi
|
|
case "$(uname -s) $(uname -m)" in
|
|
"Linux x86_64")
|
|
platform="linux-x86_64"
|
|
sha256="c0040ea9aef08fdeb2c74ca609b18d5fdbfc44ea0042fcfbfb38860d35f7dd66"
|
|
;;
|
|
"Linux aarch64" | "Linux arm64")
|
|
platform="linux-aarch_64"
|
|
sha256="15aa988f4a6090636525ec236a8e4b3aab41eef402751bd5bb2df6afd9b7b5a5"
|
|
;;
|
|
"Darwin x86_64")
|
|
platform="osx-x86_64"
|
|
sha256="a49bec10d039e902d3b43e49938c42526f90011467609864fa6386ac4014da58"
|
|
;;
|
|
"Darwin arm64")
|
|
platform="osx-aarch_64"
|
|
sha256="726297dcfed58592fd35620a5a6246ae020c39e88f3fd4cb1827df7bcf3dfcf1"
|
|
;;
|
|
*)
|
|
echo "bootstrap: no protoc archive pinned for $(uname -s) $(uname -m)" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
if missing curl; then pkg_install curl curl curl curl; fi
|
|
if missing unzip; then pkg_install unzip unzip unzip unzip; fi
|
|
tmp="$(mktemp -d)"
|
|
curl -fsSL -o "$tmp/protoc.zip" \
|
|
"https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-${platform}.zip"
|
|
verify_sha256 "$tmp/protoc.zip" "$sha256"
|
|
rm -rf "$dir"
|
|
unzip -q "$tmp/protoc.zip" -d "$dir"
|
|
rm -rf "$tmp"
|
|
}
|
|
|
|
main() {
|
|
cd "$ROOT"
|
|
|
|
# Base tooling (every repo)
|
|
if missing git; then pkg_install git git git git; fi
|
|
if missing make; then pkg_install gnumake make make make; fi
|
|
|
|
# ---- JS / docs repos ----
|
|
# This is a Go repo, but node and yarn are required anyway: prettier
|
|
# formats the Markdown and JSON, and script/fmt-check verifies it.
|
|
# The version is pinned by package.json/yarn.lock: yarn checks every
|
|
# package it fetches against its yarn.lock integrity hash, and
|
|
# --frozen-lockfile fails instead of rewriting a yarn.lock that no
|
|
# longer matches package.json.
|
|
ensure_node
|
|
ensure_yarn
|
|
install_js_deps
|
|
|
|
# ---- Go repos ----
|
|
if missing go; then pkg_install go golang go go; fi
|
|
# No golangci-lint: script/lint runs it in Docker only.
|
|
go mod download
|
|
# gofumpt and protoc-gen-go: bin/tools/go.mod pins them, and
|
|
# script/gofumpt and script/generate build them from there.
|
|
(cd "$ROOT/bin/tools" && go mod download)
|
|
ensure_protoc
|
|
|
|
# ---- Python repos ----
|
|
# if missing python3; then pkg_install python3 python3 python3 python3; fi
|
|
# python3 -m venv .venv
|
|
# ./.venv/bin/pip install -e '.[dev]'
|
|
|
|
echo "bootstrap complete"
|
|
}
|
|
|
|
main "$@"
|