#!/bin/sh # Install moxzi. # # curl -fsSL https://moxzi.ai/install.sh | sh # # What it does, and the one thing that makes it different from most install scripts: it # VERIFIES what it downloaded. This project's entire claim is that you can check the bytes # rather than trust them, so an installer that piped an unverified tarball into your PATH # would be arguing against the product. Every artifact is checked against the release's # SHA256SUMS before anything is unpacked, and the install is aborted on a mismatch. # # Releases are served by moxzi's own site, which is a canister. That is not novelty for its # own sake: it means the toolchain is distributed by the same infrastructure it compiles for, # with no GitHub account, no release API, and no private-repository problem in the way. The # origin below is rewritten at deploy time, so a preview canister and the public site run # this identical script. # # Environment: # MOXZI_VERSION version to install (default: whatever $RELEASE_BASE/latest says) # MOXZI_PREFIX install prefix (default: $HOME/.local) # MOXZI_RELEASE_BASE where releases live (default: the site this script came from) # MOXZI_BASE_URL the exact directory holding the tarball and SHA256SUMS; overrides # the version lookup entirely. Point it at a local dist/ to test a # build, or at a GitHub release's download directory. # # Layout, which is not arbitrary: the binaries look for their wasm files beside themselves # OR at ../lib/moxzi/, so installing FHS-style puts `moxzi` on your PATH while the compiler # and linker stay findable with no environment set at all. # # $MOXZI_PREFIX/bin/moxzi, moxzid # $MOXZI_PREFIX/lib/moxzi/compiler.wasm, linker.wasm, LICENSE, NOTICE, … set -eu # Rewritten by site/bake.py at deploy time — see RELEASE_BASE_MARKER there. Editing the URL # by hand is fine; changing the SHAPE of this line will make the bake fail loudly rather than # silently ship an installer pointing at the wrong origin. DEFAULT_RELEASE_BASE="https://moxzi.ai/releases" RELEASE_BASE="${MOXZI_RELEASE_BASE:-$DEFAULT_RELEASE_BASE}" PREFIX="${MOXZI_PREFIX:-$HOME/.local}" say() { printf '%s\n' "$*"; } die() { printf 'error: %s\n' "$*" >&2; exit 1; } need() { command -v "$1" >/dev/null 2>&1 || die "this installer needs $1"; } need uname need tar need mkdir if command -v curl >/dev/null 2>&1; then fetch() { curl -fsSL "$1" -o "$2"; } fetchs() { curl -fsSL "$1"; } elif command -v wget >/dev/null 2>&1; then fetch() { wget -qO "$2" "$1"; } fetchs() { wget -qO- "$1"; } else die "this installer needs curl or wget" fi # --- which build ------------------------------------------------------------------------ os=$(uname -s) arch=$(uname -m) case "$os" in Darwin) case "$arch" in arm64|aarch64) target=aarch64-apple-darwin ;; x86_64) target=x86_64-apple-darwin ;; *) die "unsupported macOS architecture: $arch" ;; esac ;; Linux) case "$arch" in x86_64|amd64) target=x86_64-unknown-linux-gnu ;; aarch64|arm64) target=aarch64-unknown-linux-gnu ;; *) die "unsupported Linux architecture: $arch" ;; esac ;; *) die "unsupported OS: $os (moxzi ships macOS and Linux builds; on Windows use WSL)" ;; esac # `latest` is a one-line text file holding the current version. A plain file rather than an # API call: it is one GET, it needs no JSON parsing, and it is served by the same canister as # everything else — so there is no second system to be down. version="${MOXZI_VERSION:-}" if [ -z "$version" ] && [ -z "${MOXZI_BASE_URL:-}" ]; then version=$(fetchs "$RELEASE_BASE/latest" 2>/dev/null | tr -d ' \t\r\n') [ -n "$version" ] || die "could not read $RELEASE_BASE/latest — set MOXZI_VERSION" fi version="${version#v}" base="${MOXZI_BASE_URL:-$RELEASE_BASE/v$version}" tarball="moxzi-$version-$target.tar.gz" # --- download and VERIFY ---------------------------------------------------------------- tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT EXIT INT TERM say "moxzi $version ($target)" say " downloading $tarball" fetch "$base/$tarball" "$tmp/$tarball" || die "could not download $base/$tarball" if fetch "$base/SHA256SUMS" "$tmp/SHA256SUMS" 2>/dev/null; then if command -v shasum >/dev/null 2>&1; then sum=$(shasum -a 256 "$tmp/$tarball" | cut -d' ' -f1) elif command -v sha256sum >/dev/null 2>&1; then sum=$(sha256sum "$tmp/$tarball" | cut -d' ' -f1) else sum=""; fi if [ -n "$sum" ]; then want=$(grep " $tarball\$\|\*$tarball\$\| $tarball\$" "$tmp/SHA256SUMS" 2>/dev/null \ | head -1 | cut -d' ' -f1) if [ -z "$want" ]; then die "SHA256SUMS does not list $tarball — refusing to install an unlisted artifact" elif [ "$sum" != "$want" ]; then die "checksum MISMATCH for $tarball expected $want got $sum Refusing to install. Report this — a release artifact should never fail this check." fi say " sha256 verified against SHA256SUMS" else say " ! no sha256 tool found; skipping verification (install shasum or sha256sum)" fi else die "could not download SHA256SUMS — refusing to install unverified binaries. Set MOXZI_BASE_URL if you are installing from somewhere else." fi # --- unpack and place ------------------------------------------------------------------- tar -xzf "$tmp/$tarball" -C "$tmp" src="$tmp/moxzi-$version-$target" [ -d "$src" ] || src=$(find "$tmp" -maxdepth 1 -type d -name 'moxzi-*' | head -1) [ -d "$src" ] || die "the tarball did not contain the expected directory" mkdir -p "$PREFIX/bin" "$PREFIX/lib/moxzi" for b in moxzi moxzid; do [ -f "$src/$b" ] || die "the tarball is missing $b" cp "$src/$b" "$PREFIX/bin/$b" chmod +x "$PREFIX/bin/$b" done for f in compiler.wasm linker.wasm LICENSE NOTICE CHANGELOG.md README.md PROVENANCE.md THIRD-PARTY.md; do [ -f "$src/$f" ] && cp "$src/$f" "$PREFIX/lib/moxzi/$f" done # --- confirm it actually works ---------------------------------------------------------- # `info` is the right check because it resolves and hashes the wasm files: if the layout is # wrong, this is where it says so, not on the user's first real build. if "$PREFIX/bin/moxzi" info >/dev/null 2>&1; then say " installed to $PREFIX/bin (compiler and linker in $PREFIX/lib/moxzi)" else say " ! installed, but 'moxzi info' did not succeed — run it to see why:" say " $PREFIX/bin/moxzi info" fi case ":$PATH:" in *":$PREFIX/bin:"*) say ""; say "Ready: moxzi info" ;; *) say "" say "Add $PREFIX/bin to your PATH, then run 'moxzi info':" say "" say " export PATH=\"$PREFIX/bin:\$PATH\"" say "" say "(add that to ~/.zshrc or ~/.bashrc to make it permanent)" ;; esac