Notcurses-Native.git | scripts/ci/ | build-rakudo.sh edit
#!/usr/bin/env bash
# Source-build Rakudo via rakubrew. Used by verify lanes where
# Raku/setup-raku@v1 has no prebuilt for our target arch:
#
# * macOS x86_64 (Intel/Rosetta — setup-raku gives arm64 Rakudo
# on the macos-14 runner; we want x86_64 Rakudo under Rosetta).
# * Linux glibc aarch64 (no aarch64 prebuilt in setup-raku).
# * Linux musl x86_64 + aarch64 (Alpine's `apk add rakudo` is
# too old to accept `Callable` in NativeCall's `is native(...)`
# trait, which Notcurses::Native uses for lazy lib-path
# resolution — apk's Rakudo fails to precompile our deps).
# * Windows arm64 (no ARM64 prebuilt in setup-raku).
#
# Honours:
# $RAKUDO_VERSION — defaults to 2026.03. Pin in workflow env
# for cache-key stability.
# $RAKUBREW_HOME — defaults to $HOME/.rakubrew. actions/cache
# can persist this directory between runs so
# subsequent CI runs hit the ~10–20 min build.
#
# After the script completes, `raku` is accessible at
# `$RAKUBREW_HOME/shims/raku`. The calling workflow step is
# expected to:
# 1. Append `$RAKUBREW_HOME/shims` to $GITHUB_PATH.
# 2. Run `scripts/ci/install-zef.sh` to install zef fresh.
#
# zef is NOT installed by this script — it lives in
# `versions/moar-*/install/share/perl6/site/`, which is the same
# directory zef tracks "already installed" module state in.
# Caching that state turns `zef install` into a no-op on cache
# hit (Build.rakumod never runs). Cleaner to keep site/ out of
# the cache and pay 30s/run to install zef fresh.
#
# Idempotent — short-circuits if the target Rakudo is already
# built (cache hit OR previous failed-step rerun).
set -euxo pipefail
RAKUDO_VERSION="${RAKUDO_VERSION:-2026.03}"
export RAKUBREW_HOME="${RAKUBREW_HOME:-$HOME/.rakubrew}"
SHIM_DIR="$RAKUBREW_HOME/shims"
# Cache hit / already-installed short-circuit. Verify by asking
# the shim what version it reports — if it's our target, we're done.
if [[ -x "$SHIM_DIR/raku" ]] \
&& "$SHIM_DIR/raku" --version 2>/dev/null | grep -q "$RAKUDO_VERSION"; then
echo "✅ Rakudo $RAKUDO_VERSION already installed at $RAKUBREW_HOME"
"$SHIM_DIR/raku" --version
exit 0
fi
mkdir -p "$RAKUBREW_HOME"
# Bootstrap rakubrew itself. The installer respects $RAKUBREW_HOME
# (exported above). install-on-perl.sh needs perl + curl, both
# universally available on every CI runner we use.
if [[ ! -x "$RAKUBREW_HOME/bin/rakubrew" ]]; then
curl -fsSL --retry 5 --retry-delay 10 https://rakubrew.org/install-on-perl.sh | sh
fi
# Switch to shim mode. rakubrew refuses to `build` if it's still
# in its default 'env' mode and no shell hook has been installed
# (the build command short-circuits with "The shell hook required
# to run rakubrew in either 'env' mode or with the 'shell' command
# seems not to be installed"). We have no interactive ~/.bashrc to
# source in CI, so shim mode — which drops dispatch wrappers into
# $RAKUBREW_HOME/shims/ as if it were a normal PATH dir — is the
# correct choice. Idempotent: re-running on a shim-mode rakubrew
# is a no-op.
"$RAKUBREW_HOME/bin/rakubrew" mode shim
# Build Rakudo with MoarVM backend. The first run takes ~10-20 min
# (NQP + MoarVM + Rakudo all from source); subsequent CI runs hit
# the actions/cache restore and skip this entirely.
"$RAKUBREW_HOME/bin/rakubrew" build "moar-$RAKUDO_VERSION"
# Activate the new version — `switch` sets the active version that
# the shims dispatch to.
"$RAKUBREW_HOME/bin/rakubrew" switch "moar-$RAKUDO_VERSION"
# Defensive — `build` already runs rehash internally per its
# "Updating shims" output, but explicit rehash makes sure the
# shim list is current even if rakubrew's logic changes.
"$RAKUBREW_HOME/bin/rakubrew" rehash
# Smoke check. zef is installed by install-zef.sh in the workflow
# after the cache save — it intentionally isn't part of this
# script (see header).
"$SHIM_DIR/raku" --version