#!/bin/sh # # hushhh CLI installer. # # curl -fsSL https://hushhh.cc/install.sh | sh # # GENERATED by scripts/build-cli.js — the checksum below is of the exact `hh` # this site is serving right now. # # What it does, so that piping it into a shell is a decision and not a leap: # # - downloads https://hushhh.cc/hh (one POSIX sh file, no dependencies) # - checks it against the SHA-256 baked in here at build time # - writes it to ~/.local/bin/hh (or $HH_PREFIX), makes it executable # - tells you if that directory is not on your PATH # # It asks for no privileges and touches nothing else. `sh install.sh --uninstall` # removes it again. Everything it writes is one file you can delete by hand. set -eu HOST=${HUSHHH_HOST:-https://hushhh.cc} VERSION='b6bf4943' EXPECTED='5a7fe3fa11c9572cf31f8769fcdd9ea9aa7f43589ac89c065b77003286af948d' # ~/.local/bin rather than /usr/local/bin: this needs no sudo, and a tool # installed without privileges is one you can remove without them either. PREFIX=${HH_PREFIX:-$HOME/.local/bin} TARGET="$PREFIX/hh" say() { printf '%s\n' "$*"; } die() { printf 'install: %s\n' "$*" >&2; exit 1; } case ${1:-} in --uninstall) if [ -f "$TARGET" ]; then rm -f "$TARGET" say "Removed $TARGET" else say "Nothing at $TARGET" fi exit 0 ;; -h|--help) sed -n '3,20p' "$0" 2>/dev/null || say "curl -fsSL $HOST/install.sh | sh" exit 0 ;; esac command -v curl >/dev/null 2>&1 || die 'curl is needed and was not found' # The checksum is verified before anything is made executable, and the # download lands in a temporary file rather than on top of whatever is already # installed: a half-finished download over a working `hh` is worse than no # download at all. tmp=$(mktemp "${TMPDIR:-/tmp}/hh-install.XXXXXX") || die 'could not create a temporary file' trap 'rm -f "$tmp"' EXIT INT TERM say "Downloading hh $VERSION from $HOST …" curl -fsSL "$HOST/hh" -o "$tmp" || die "could not download $HOST/hh" # sha256sum on Linux, shasum on macOS. If neither exists the install stops # rather than going ahead unverified — "I could not check this" is a thing to # be told, not a step to skip quietly. if command -v sha256sum >/dev/null 2>&1; then actual=$(sha256sum "$tmp" | cut -d' ' -f1) elif command -v shasum >/dev/null 2>&1; then actual=$(shasum -a 256 "$tmp" | cut -d' ' -f1) else die 'no sha256sum or shasum found, so the download cannot be verified' fi if [ "$actual" != "$EXPECTED" ]; then die "checksum mismatch — expected $EXPECTED, got $actual. Nothing was installed." fi mkdir -p "$PREFIX" || die "could not create $PREFIX" cp "$tmp" "$TARGET" || die "could not write $TARGET" chmod 755 "$TARGET" say "Installed $TARGET" say '' # Saying "installed" and leaving someone with a command not found is the # failure this paragraph exists to prevent. case ":$PATH:" in *":$PREFIX:"*) say "Try: hh help" ;; *) say "$PREFIX is not on your PATH. Add this to your shell profile:" say "" say " export PATH=\"\$PATH:$PREFIX\"" say "" say "Or run it directly: $TARGET help" ;; esac