#!/bin/sh # Served by getjack.dev; resolve the release when the installer runs. set -eu # Read a string at a dotted JSON path using only POSIX awk. Parse the document, # rather than matching a similarly named field belonging to another product. json_string() { awk -v target="$1" ' function token( text) { sub(/^[ \t\r\n]+/, "", source) if (match(source, /^"([^"\\[:cntrl:]]|\\(["\\\/bfnrt]|u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*"/)) { text = substr(source, 1, RLENGTH) } else if (match(source, /^-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?|^(true|false|null)/)) { text = substr(source, 1, RLENGTH) } else { text = substr(source, 1, 1) } source = substr(source, length(text) + 1) return text } function value(path, depth, t, key, end) { if (depth > 32) exit 1 t = token() if (t == "{" || t == "[") { end = (t == "{" ? "}" : "]") sub(/^[ \t\r\n]+/, "", source) if (substr(source, 1, 1) == end) { token(); return } do { if (end == "}") { key = token() if (substr(key, 1, 1) != "\"" || token() != ":") exit 1 key = substr(key, 2, length(key) - 2) } else { key = "[]" } value(path == "" ? key : path "." key, depth + 1) t = token() if (t == end) return if (t != ",") exit 1 } while (1) } if (t !~ /^"/ && t !~ /^(-?[0-9]|true$|false$|null$)/) exit 1 if (path == target) { if (++found != 1 || t !~ /^"/) exit 1 result = substr(t, 2, length(t) - 2) gsub(/\\\//, "/", result) } } { source = source $0 "\n" } END { value("", 0) if (token() != "" || found != 1) exit 1 print result }' "$2" } install_jack() ( umask 077 os=$(uname -s) arch=$(uname -m) case "$os/$arch" in Linux/x86_64) asset=jack-linux-x64 ;; Darwin/arm64) asset=jack-darwin-arm64 ;; *) echo "Unsupported platform: $os/$arch. Jack supports Linux x64 and macOS arm64." >&2; return 1 ;; esac command -v curl >/dev/null 2>&1 || { echo 'Install curl first.' >&2; return 1; } if command -v sha256sum >/dev/null 2>&1; then hash_command=sha256sum elif command -v shasum >/dev/null 2>&1; then hash_command=shasum else echo 'Install sha256sum or shasum first.' >&2 return 1 fi metadata=$(mktemp -d "${TMPDIR:-/tmp}/jack-install.XXXXXX") staging='' trap 'rm -rf "$metadata"; if [ -n "$staging" ]; then rm -rf "$staging"; fi' 0 trap 'exit 1' 1 2 15 origin='https://dl.getjack.dev/runtime' status=$(curl -fsSL --proto '=https' --tlsv1.2 "$origin/latest.json" -o "$metadata/latest.json" -w '%{http_code}') || { [ "$status" = 404 ] || { echo 'Could not fetch the Runtime release pointer.' >&2; return 1; } } if [ "$status" = 404 ]; then curl -fsSL --proto '=https' --tlsv1.2 'https://getjack.dev/version.json' -o "$metadata/version.json" version=$(json_string runtime.latest.latest "$metadata/version.json") || { echo 'Invalid Runtime release metadata.' >&2; return 1; } sums="v$version/SHA256SUMS" else version=$(json_string version "$metadata/latest.json") || { echo 'Invalid Runtime release metadata.' >&2; return 1; } sums=$(json_string sha256sums "$metadata/latest.json") || { echo 'Invalid Runtime release metadata.' >&2; return 1; } fi printf '%s\n' "$version" | awk '/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/ { valid=1 } END { exit !valid }' || { echo 'Invalid Runtime release version.' >&2; return 1; } if [ "$version" = '0.0.0' ]; then echo 'Jack Runtime has no release yet. Please try again after release.' >&2 return 1 fi [ "$sums" = "v$version/SHA256SUMS" ] || { echo 'Invalid release checksum path.' >&2; return 1; } bin="$HOME/.jack/bin" mkdir -p "$HOME/.jack" chmod 700 "$HOME/.jack" mkdir -p "$bin" chmod 700 "$bin" staging=$(mktemp -d "$bin/.install.XXXXXX") base="$origin/v$version" curl -fsSL --proto '=https' --tlsv1.2 "$base/$asset" -o "$staging/$asset" curl -fsSL --proto '=https' --tlsv1.2 "$origin/$sums" -o "$staging/SHA256SUMS" expected=$(awk -v asset="$asset" '$2 == asset { print $1 }' "$staging/SHA256SUMS") case "$expected" in ''|*[!0-9a-fA-F]*) echo 'Missing or invalid release checksum.' >&2; return 1 ;; esac [ "${#expected}" -eq 64 ] || { echo 'Invalid release checksum.' >&2; return 1; } if [ "$hash_command" = sha256sum ]; then actual=$(sha256sum "$staging/$asset") else actual=$(shasum -a 256 "$staging/$asset") fi actual=${actual%% *} [ "$actual" = "$expected" ] || { echo 'Release checksum mismatch; Jack was not installed.' >&2; return 1; } chmod 755 "$staging/$asset" printf '{"method":"script"}\n' > "$staging/install.json" mv -f "$staging/$asset" "$bin/jack" mv -f "$staging/install.json" "$HOME/.jack/install.json" echo "Installed Jack Runtime $version to $bin/jack." echo 'Add this line to your shell profile, then open a new terminal:' echo 'export PATH="$HOME/.jack/bin:$PATH"' ) install_jack