#!/bin/sh # Install the Vyrn alpha on Linux or macOS. # # curl -fsSL https://raw.githubusercontent.com/vyrn-lang/vyrn/main/install.sh | sh # # It downloads the archive for this machine from the newest GitHub release, # checks it against that release's SHA256SUMS, and unpacks it under ~/.vyrn. # It refuses to install anything it cannot verify. # # Environment overrides: # VYRN_VERSION install this tag instead of the newest release # VYRN_INSTALL_DIR install here instead of ~/.vyrn # VYRN_REPO owner/name to download from (used by the test harness) set -eu REPO="${VYRN_REPO:-vyrn-lang/vyrn}" DIR="${VYRN_INSTALL_DIR:-$HOME/.vyrn}" API="${VYRN_API:-https://api.github.com}" DL="${VYRN_DOWNLOAD:-https://github.com}" die() { printf 'vyrn install: %s\n' "$*" >&2; exit 1; } say() { printf '%s\n' "$*"; } # --- what to download ------------------------------------------------------- os=$(uname -s) arch=$(uname -m) case "$os/$arch" in Linux/x86_64|Linux/amd64) asset=vyrn-x86_64-linux.tar.gz ;; # `uname -m` says `aarch64` on a Linux kernel and `arm64` on Darwin; both # spellings appear on Linux in the wild (some musl/BusyBox userlands, and # containers started with `--platform linux/arm64`), so accept either. This is # the Docker-on-Apple-Silicon case: the default platform there is linux/arm64, # and before the aarch64-linux release stanza this line fell through to "build # from source" for an ordinary audience. Linux/aarch64|Linux/arm64) asset=vyrn-aarch64-linux.tar.gz ;; Darwin/arm64|Darwin/aarch64) asset=vyrn-aarch64-macos.tar.gz ;; *) die "no published build for $os $arch. The alpha ships Linux x86_64, Linux arm64 and macOS arm64. On anything else, build from source: https://github.com/$REPO#build-from-source" ;; esac # --- how to download -------------------------------------------------------- if command -v curl >/dev/null 2>&1; then fetch() { curl -fsSL "$1"; } # to stdout, nonzero on HTTP error fetch_to(){ curl -fsSL -o "$2" "$1"; } elif command -v wget >/dev/null 2>&1; then fetch() { wget -qO- "$1"; } fetch_to(){ wget -qO "$2" "$1"; } else die "need curl or wget on PATH" fi if command -v sha256sum >/dev/null 2>&1; then sum() { sha256sum "$1" | cut -d' ' -f1; } elif command -v shasum >/dev/null 2>&1; then sum() { shasum -a 256 "$1" | cut -d' ' -f1; } else die "need sha256sum or shasum on PATH to verify the download" fi # --- which release ---------------------------------------------------------- if [ -n "${VYRN_VERSION:-}" ]; then tag="$VYRN_VERSION" else # per_page=1 gives the newest release INCLUDING pre-releases, which # /releases/latest deliberately hides — and every alpha is a pre-release. # One release in the response means one "tag_name", so this stays a sed. # A failed fetch (offline, proxy, GitHub down) and an empty listing are # different situations with different advice; keep them apart. json=$(fetch "$API/repos/$REPO/releases?per_page=1") || die "cannot reach GitHub ($API) to list releases for $REPO. Check your network or proxy settings and try again." tag=$(printf '%s' "$json" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1) [ -n "$tag" ] || die "no release has been published for $REPO yet. Build from source instead: git clone https://github.com/$REPO.git cd vyrn/compiler && cargo build --release -p vyrn-cli" fi base="$DL/$REPO/releases/download/$tag" say "vyrn $tag -> $DIR" # --- download and verify ---------------------------------------------------- tmp=$(mktemp -d "${TMPDIR:-/tmp}/vyrn-install.XXXXXX") trap 'rm -rf "$tmp"' EXIT INT TERM fetch_to "$base/$asset" "$tmp/$asset" || die "cannot download $base/$asset" fetch_to "$base/SHA256SUMS" "$tmp/SHA256SUMS" || die "release $tag has no SHA256SUMS asset; refusing to install unverified bytes" # sha256sum writes " name" in text mode and " *name" in binary mode; # accept both, so a SHA256SUMS produced on any host still verifies here. want=$(awk -v f="$asset" '{ n = $2; sub(/^\*/, "", n); if (n == f) print $1 }' "$tmp/SHA256SUMS") [ -n "$want" ] || die "$asset is not listed in the SHA256SUMS of $tag; refusing to install unverified bytes" got=$(sum "$tmp/$asset") [ "$want" = "$got" ] || { rm -f "$tmp/$asset" die "checksum mismatch for $asset expected $want got $got The download was discarded. Nothing was installed." } say "sha256 ok: $got" # --- unpack ----------------------------------------------------------------- tar xzf "$tmp/$asset" -C "$tmp" stage="$tmp/${asset%.tar.gz}" [ -x "$stage/vyrn" ] || die "archive $asset has no vyrn binary in $(basename "$stage")/" # `vyrn` finds std/ and web/ by walking up from its own path, so the binary # goes in $DIR/bin and the trees stay its siblings one level up. $DIR/cache # (remote imports) is left alone. mkdir -p "$DIR/bin" rm -rf "$DIR/std" "$DIR/web" "$DIR/bin/vyrn" "$DIR/bin/vyrn-lsp" mv "$stage/std" "$stage/web" "$DIR/" mv "$stage/vyrn" "$DIR/bin/vyrn" chmod +x "$DIR/bin/vyrn" # The language server goes BESIDE the driver, which is where the VS Code # extension looks for it (editor/vscode/extension.js): `vyrn-lsp` on PATH, or # next to the `vyrn` that is on PATH. Guarded, so this script still installs an # older archive that predates it. if [ -f "$stage/vyrn-lsp" ]; then mv "$stage/vyrn-lsp" "$DIR/bin/vyrn-lsp" chmod +x "$DIR/bin/vyrn-lsp" fi if [ -f "$stage/VERSION" ]; then mv "$stage/VERSION" "$DIR/VERSION"; fi if [ -f "$stage/README.md" ]; then mv "$stage/README.md" "$DIR/README.md"; fi say "installed $DIR/bin/vyrn" case ":${PATH}:" in *":$DIR/bin:"*) ;; *) say "" say "Add it to your PATH:" say " export PATH=\"$DIR/bin:\$PATH\"" say "(put that line in ~/.profile, ~/.bashrc or ~/.zshrc)" ;; esac say "" say "vyrn run, check, test and build --target wasm need nothing else." say "vyrn build (a native binary) needs clang on PATH."