#!/bin/sh # Clank RC installer. # # curl -fsSL https://clankrc.com/install.sh | sh # curl -fsSL https://clankrc.com/install.sh | sh -s -- -y # and run `clankrc setup -y` # # It downloads the clankrc binary for this Mac, checks its SHA-256, puts it in ~/.clankrc/bin and # adds that to your PATH. Then you run `clankrc setup`, which does the rest and asks before it # installs anything. Never uses sudo. Run it again to upgrade. Contract: docs/cli.md. # # Options: # -y, --yes don't ask; run `clankrc setup -y` at the end # --no-start with -y: pass --no-start to setup (don't start the background service) # --no-modify-path don't touch your shell config; print the line to add # --version X install version X instead of the latest # --uninstall run `clankrc uninstall` (add -y to skip its question) # # Environment: # CLANKRC_DOWNLOAD_URL where releases live (default https://dl.clankrc.com) # CLANKRC_INSTALL_DIR where to install (default ~/.clankrc) # # Everything is in functions and runs from the last line, so a download cut short runs nothing. set -u DOWNLOAD_URL="${CLANKRC_DOWNLOAD_URL:-https://dl.clankrc.com}" INSTALL_DIR="${CLANKRC_INSTALL_DIR:-$HOME/.clankrc}" PATH_MARK="# added by the Clank RC installer" say() { printf '%s\n' "clankrc: $*"; } err() { printf '%s\n' "clankrc: error: $*" >&2 exit 1 } need() { command -v "$1" >/dev/null 2>&1 || err "this needs '$1', which isn't on PATH"; } usage() { cat <<'USAGE' Clank RC installer curl -fsSL https://clankrc.com/install.sh | sh [-s -- OPTIONS] -y, --yes don't ask; run `clankrc setup -y` at the end --no-start with -y: pass --no-start to setup --no-modify-path don't touch your shell config; print the line to add --version X install version X instead of the latest --uninstall run `clankrc uninstall` (add -y to skip its question) USAGE } check_platform() { os=$(uname -s) arch=$(uname -m) [ "$os" = "Darwin" ] || err "Clank RC runs on macOS. This is $os." # Under Rosetta uname says x86_64; ask the hardware. if [ "$arch" = "x86_64" ] && [ "$(sysctl -n sysctl.proc_translated 2>/dev/null)" = "1" ]; then arch=arm64; fi [ "$arch" = "arm64" ] || err "Clank RC needs an Apple silicon Mac (M1 or later). This one is $arch." ver=$(sw_vers -productVersion) major=${ver%%.*} [ "$major" -ge 14 ] 2>/dev/null || err "Clank RC needs macOS 14 (Sonoma) or later. This Mac has $ver." PLATFORM=darwin-arm64 } # https only, except a local test server. case "$DOWNLOAD_URL" in http://127.0.0.1:* | http://localhost:*) PROTO='=http,https' ;; *) PROTO='=https' ;; esac # fetch URL FILE: download with curl, showing the URL. fetch() { say "downloading $1" curl --proto "$PROTO" --tlsv1.2 --fail --location --silent --show-error --retry 2 --output "$2" "$1" || err "couldn't download $1" } # The release to install: sets TARBALL_URL and SHA256. pick_release() { if [ -n "${WANT_VERSION:-}" ]; then name="clankrc-$WANT_VERSION-$PLATFORM.tar.gz" TARBALL_URL="$DOWNLOAD_URL/$name" fetch "$TARBALL_URL.sha256" "$TMP/sha256" SHA256=$(awk '{print $1; exit}' "$TMP/sha256") VERSION=$WANT_VERSION else fetch "$DOWNLOAD_URL/manifest.json" "$TMP/manifest.json" # plutil reads JSON, and every Mac has it. VERSION=$(plutil -extract version raw -o - "$TMP/manifest.json" 2>/dev/null) || err "manifest.json has no version" url=$(plutil -extract "platforms.$PLATFORM.url" raw -o - "$TMP/manifest.json" 2>/dev/null) || err "no $PLATFORM build in manifest.json" SHA256=$(plutil -extract "platforms.$PLATFORM.sha256" raw -o - "$TMP/manifest.json" 2>/dev/null) || err "manifest.json has no sha256 for $PLATFORM" case "$url" in http://* | https://*) TARBALL_URL=$url ;; *) TARBALL_URL="$DOWNLOAD_URL/$url" ;; esac fi case "$SHA256" in [0-9a-f]*) [ ${#SHA256} -eq 64 ] || err "bad sha256 for clankrc $VERSION" ;; *) err "bad sha256 for clankrc $VERSION" ;; esac } download_and_verify() { fetch "$TARBALL_URL" "$TMP/clankrc.tar.gz" got=$(shasum -a 256 "$TMP/clankrc.tar.gz" | awk '{print $1}') [ "$got" = "$SHA256" ] || err "checksum mismatch for $TARBALL_URL (got $got, want $SHA256). Nothing was installed." say "sha256 ok ($SHA256)" mkdir -p "$TMP/x" tar -xzf "$TMP/clankrc.tar.gz" -C "$TMP/x" || err "couldn't unpack the download" SRC="$TMP/x/clankrc-$VERSION-$PLATFORM" [ -x "$SRC/bin/clankrc" ] && [ -d "$SRC/share" ] || err "the download doesn't look like a Clank RC release" "$SRC/bin/clankrc" --version >/dev/null 2>&1 || err "the downloaded clankrc doesn't run on this Mac" } install_files() { mkdir -p "$INSTALL_DIR/bin" || err "can't create $INSTALL_DIR/bin" chmod 700 "$INSTALL_DIR" # Same filesystem as the target, so each mv is an atomic rename. A running daemon keeps its old # binary until `clankrc restart`. mv -f "$SRC/bin/clankrc" "$INSTALL_DIR/bin/clankrc" || err "couldn't install $INSTALL_DIR/bin/clankrc" rm -rf "$INSTALL_DIR/share.old" [ -d "$INSTALL_DIR/share" ] && mv "$INSTALL_DIR/share" "$INSTALL_DIR/share.old" mv "$SRC/share" "$INSTALL_DIR/share" || err "couldn't install $INSTALL_DIR/share" rm -rf "$INSTALL_DIR/share.old" cat >"$INSTALL_DIR/receipt.json" <>"$rc" || err "couldn't write $rc" say "added $bin to PATH in $rc (one line, marked '$PATH_MARK')" } run_uninstall() { bin="$INSTALL_DIR/bin/clankrc" if [ -x "$bin" ]; then if [ "$YES" = 1 ]; then exec "$bin" uninstall -y; fi exec "$bin" uninstall