#!/bin/sh # Installs optimi-report, the CLI behind `optimi-report scan`, from a GitHub # release. It needs no Go toolchain. # # curl -fsSL https://github.com/optimi-ai/optimi-releases/releases/latest/download/install.sh | sh # # The source repository is private, so releases are published to the public # optimi-ai/optimi-releases, which holds release assets only. Each release # carries this script too, and the website serves a copy of it. # # It downloads the archive for this machine and the release's checksums.txt, # compares the archive's sha256 with the one listed there, and installs # nothing unless they match. It does not use sudo, does not edit a shell # profile and sends nothing anywhere. # # Settings are environment variables, set on the `sh` side of the pipe # (`curl ... | OPTIMI_VERSION=v0.1.0 sh`): # # OPTIMI_VERSION Release tag to install, such as v0.1.0. Default: the latest release. # OPTIMI_INSTALL_DIR Directory the binary goes in. Default: ~/.local/bin. # OPTIMI_REPO GitHub repository to download from. Default: optimi-ai/optimi-releases. # OPTIMI_BASE_URL The releases URL itself, for a mirror. Default: https://github.com/$OPTIMI_REPO/releases. # # The archive and checksum file names are set in .goreleaser.yaml: change # them there and here together. set -eu binary=optimi-report # The one place the releases repository's owner and name are set. default_repo=optimi-ai/optimi-releases fail() { echo "install.sh: $*" >&2 exit 1 } # The whole script is one function, called on the last line, so a download # cut off part way runs nothing. main() { repo=${OPTIMI_REPO:-$default_repo} base=${OPTIMI_BASE_URL:-https://github.com/$repo/releases} version=${OPTIMI_VERSION:-latest} dir=${OPTIMI_INSTALL_DIR:-$HOME/.local/bin} case $(uname -s) in Darwin) os=darwin ;; Linux) os=linux ;; *) fail "unsupported operating system $(uname -s): releases are built for macOS and Linux" ;; esac case $(uname -m) in x86_64 | amd64) arch=amd64 ;; arm64 | aarch64) arch=arm64 ;; *) fail "unsupported architecture $(uname -m): releases are built for amd64 and arm64" ;; esac for tool in curl tar awk mktemp; do command -v "$tool" >/dev/null 2>&1 || fail "$tool is required and was not found" done if command -v sha256sum >/dev/null 2>&1; then hasher=sha256sum elif command -v shasum >/dev/null 2>&1; then hasher=shasum else fail "neither sha256sum nor shasum was found, so the download cannot be verified; nothing was installed" fi if [ "$version" = latest ]; then url=$base/latest/download else url=$base/download/$version fi archive=${binary}_${os}_${arch}.tar.gz tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT curl -fsSL -o "$tmp/$archive" "$url/$archive" || fail "could not download $url/$archive" curl -fsSL -o "$tmp/checksums.txt" "$url/checksums.txt" || fail "could not download $url/checksums.txt" want=$(awk -v name="$archive" '$2 == name { print $1 }' "$tmp/checksums.txt") [ -n "$want" ] || fail "checksums.txt has no entry for $archive; nothing was installed" if [ "$hasher" = sha256sum ]; then got=$(sha256sum "$tmp/$archive") else got=$(shasum -a 256 "$tmp/$archive") fi got=${got%% *} [ "$got" = "$want" ] || fail "checksum mismatch for $archive (expected $want, got $got); nothing was installed" tar -xzf "$tmp/$archive" -C "$tmp" "$binary" || fail "could not unpack $archive; nothing was installed" chmod 755 "$tmp/$binary" mkdir -p "$dir" mv -f "$tmp/$binary" "$dir/$binary" if [ "$version" = latest ]; then echo "Installed $binary (latest release, sha256 verified) to $dir/$binary" else echo "Installed $binary $version (sha256 verified) to $dir/$binary" fi case ":$PATH:" in *":$dir:"*) echo "Next: $binary scan" ;; *) echo "Next: $dir/$binary scan" echo "$dir is not on your PATH. To run it as $binary, add this to your shell profile:" echo " export PATH=\"$dir:\$PATH\"" ;; esac } main "$@"