check / check (push) Canceled after 0s
The dotfiles, REPO_POLICIES.md and the standard scripts are fetched whole from sneak/prompts e3f79c4, with pixa's own entries kept after them. Check builds pass a new CACHEBUST build argument instead of --no-cache, and every Dockerfile stage declares it first, so every RUN step still runs while Go's build cache is kept. Lint runs golangci-lint v2.14.0, and the test phase runs on the Debian Go image. Of the two new lint findings, one is fixed and one (gosec G703 on the fixed config file locations) is suppressed. The agent guidance moves unchanged from CLAUDE.md to AGENTS.md. Deviation: the workflow keeps its docker-smoke step while issue 203 waits on the owner. Model: opus-5-5
225 lines
7.1 KiB
Bash
Executable File
225 lines
7.1 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, or go). The installed node is used only when its major version
|
|
# is the pinned one; otherwise (node missing, or another major) the
|
|
# pinned version is installed via nvm (installing nvm itself first,
|
|
# from a hash-verified release archive, never curl | sh), and yarn and
|
|
# the packages are installed under it. The linter is never installed on
|
|
# the host: golangci-lint runs only in the lint phase of the Dockerfile
|
|
# (see script/lint).
|
|
#
|
|
# script/bootstrap git, make, Go, and Node, Yarn and the
|
|
# prettier in yarn.lock for script/fmt and
|
|
# script/fmt-check: all the host needs, as
|
|
# the checks compile pixa in Docker
|
|
# script/bootstrap --cgo git, make, Go, and a C compiler and the
|
|
# CGO image libraries (pkg-config, vips
|
|
# with its JPEG XL support, libheif) for
|
|
# the govips bindings instead of Node: to
|
|
# compile pixa, in the Dockerfile's test
|
|
# phase and build stage, which format
|
|
# nothing
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
# Pinned versions, 2026-07-06
|
|
NODE_VERSION="22.17.0"
|
|
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"
|
|
|
|
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
|
|
# This runs before the first install only. A fresh image, such
|
|
# as a CI runner's, has no package lists, and apt-get install
|
|
# finds no package without them.
|
|
$SUDO apt-get update
|
|
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
|
|
nvm_sh() {
|
|
bash -c ". \"\$HOME/.nvm/nvm.sh\" && $*"
|
|
}
|
|
|
|
ensure_nvm() {
|
|
[ -s "$HOME/.nvm/nvm.sh" ] && return 0
|
|
# nvm prerequisites; nvm itself requires bash
|
|
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"
|
|
}
|
|
|
|
# True when the node on PATH has the pinned major version. Only the
|
|
# major is compared, as REPO_POLICIES.md asks. Another major is not
|
|
# used: the pinned yarn 1 prints a deprecation warning under node 24.
|
|
# script/fmt and script/fmt-check carry this function unchanged, to run
|
|
# the yarn installed here.
|
|
node_is_pinned_major() {
|
|
if ! command -v node >/dev/null 2>&1; then return 1; fi
|
|
installed="$(node --version)"
|
|
installed="${installed#v}"
|
|
[ "${installed%%.*}" = "${NODE_VERSION%%.*}" ]
|
|
}
|
|
|
|
ensure_node() {
|
|
if node_is_pinned_major; then
|
|
echo "bootstrap: using node $(node --version)"
|
|
return 0
|
|
fi
|
|
ensure_nvm
|
|
nvm_sh "nvm install $NODE_VERSION"
|
|
nvm_sh "nvm use $NODE_VERSION >/dev/null && \
|
|
echo \"bootstrap: using node \$(node --version)\""
|
|
}
|
|
|
|
ensure_yarn() {
|
|
if ! node_is_pinned_major; then
|
|
nvm_sh "nvm use $NODE_VERSION >/dev/null && corepack enable && \
|
|
corepack prepare yarn@$YARN_VERSION --activate"
|
|
return 0
|
|
fi
|
|
if ! missing yarn; then return 0; fi
|
|
if ! missing corepack; then
|
|
corepack enable
|
|
corepack prepare "yarn@$YARN_VERSION" --activate
|
|
else
|
|
npm install -g "yarn@$YARN_VERSION"
|
|
fi
|
|
}
|
|
|
|
install_js_deps() {
|
|
if node_is_pinned_major; then
|
|
yarn install --frozen-lockfile
|
|
else
|
|
nvm_sh "nvm use $NODE_VERSION >/dev/null && cd \"$ROOT\" && \
|
|
yarn install --frozen-lockfile"
|
|
fi
|
|
}
|
|
|
|
# CGO dependencies for govips (image processing)
|
|
ensure_cgo_deps() {
|
|
# cgo compiles with gcc on Linux; build-base and build-essential
|
|
# also bring the C library headers.
|
|
if missing gcc; then
|
|
pkg_install gcc build-essential gcc build-base
|
|
fi
|
|
if missing pkg-config; then
|
|
pkg_install pkg-config pkg-config pkg-config pkgconfig
|
|
fi
|
|
if ! pkg-config --exists vips; then
|
|
pkg_install vips libvips-dev vips vips-dev
|
|
fi
|
|
# libvips' JPEG XL loader and saver are in the nix and brew vips
|
|
# packages, and in apt's from Debian 12 and Ubuntu 24.04 on, but in
|
|
# the package vips-jxl on Alpine. detect_pkgmgr is called only where
|
|
# apk exists, as on apt it updates the package lists.
|
|
if ! missing apk; then
|
|
detect_pkgmgr
|
|
fi
|
|
if [ "$PKGMGR" = "apk" ] && ! apk info -e vips-jxl >/dev/null; then
|
|
apk add --no-cache vips-jxl
|
|
fi
|
|
if ! pkg-config --exists libheif; then
|
|
pkg_install libheif libheif-dev libheif libheif-dev
|
|
fi
|
|
}
|
|
|
|
usage() {
|
|
echo "usage: script/bootstrap [--cgo]" >&2
|
|
exit 2
|
|
}
|
|
|
|
main() {
|
|
case "$*" in
|
|
"" | --cgo) ;;
|
|
*) usage ;;
|
|
esac
|
|
cd "$ROOT"
|
|
|
|
# Base tooling
|
|
if missing git; then pkg_install git git git git; fi
|
|
if missing make; then pkg_install gnumake make make make; fi
|
|
|
|
# Go toolchain
|
|
if missing go; then pkg_install go golang go go; fi
|
|
|
|
# CGO image libraries where pixa is compiled; elsewhere Node, Yarn
|
|
# and prettier
|
|
if [ "$*" = "--cgo" ]; then
|
|
ensure_cgo_deps
|
|
else
|
|
ensure_node
|
|
ensure_yarn
|
|
install_js_deps
|
|
fi
|
|
|
|
go mod download
|
|
|
|
echo "bootstrap complete"
|
|
}
|
|
|
|
main "$@"
|