aboutsummaryrefslogtreecommitdiff
path: root/distribution/install.sh
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-09-01 14:48:45 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-09-01 14:48:45 +0300
commit8a6d697308162874a236c84aac0b0f8c7ac01f83 (patch)
treeed7dc7e8c6f50d66bde721fae78576aede929f66 /distribution/install.sh
parentb54a78aa510b87d1e3b56c619b72eaeb59e4a2a1 (diff)
refactor: separate website presentation from runtime
Diffstat (limited to 'distribution/install.sh')
-rwxr-xr-xdistribution/install.sh146
1 files changed, 146 insertions, 0 deletions
diff --git a/distribution/install.sh b/distribution/install.sh
new file mode 100755
index 00000000..4e3ce40d
--- /dev/null
+++ b/distribution/install.sh
@@ -0,0 +1,146 @@
+#!/bin/sh
+set -eu
+
+BIN="herdr"
+MANIFEST_URL="https://herdr.dev/latest.json"
+INSTALL_DIR="${HERDR_INSTALL_DIR:-$HOME/.local/bin}"
+
+main() {
+ echo ""
+ echo " ,ww"
+ echo " wWWWWWWW_) herdr installer"
+ echo " \`WWWWWW' herdr.dev"
+ echo " II II"
+ echo ""
+
+ # detect platform
+ OS="$(uname -s)"
+ case "$OS" in
+ Linux) os="linux" ;;
+ Darwin) os="macos" ;;
+ *) err "unsupported OS: $OS" ;;
+ esac
+
+ ARCH="$(uname -m)"
+ case "$ARCH" in
+ x86_64|amd64) arch="x86_64" ;;
+ aarch64|arm64) arch="aarch64" ;;
+ *) err "unsupported architecture: $ARCH" ;;
+ esac
+
+ log "detected ${os}/${arch}"
+
+ # check dependencies
+ need curl
+ need awk
+
+ # use the same manifest as `herdr update` so installs and updates agree
+ # on the public latest release.
+ TARGET="${os}-${arch}"
+ log "fetching latest release manifest..."
+ MANIFEST="$(curl -fsSL --retry 3 --connect-timeout 10 --max-time 20 "$MANIFEST_URL")" \
+ || err "can't reach ${MANIFEST_URL}. Please try again later; herdr.dev might be down. Who let the sheeps out? baaa."
+ URL="$(printf '%s\n' "$MANIFEST" | awk -v target="\"${TARGET}\"" '
+ /^[[:space:]]*"assets"[[:space:]]*:/ { in_assets = 1; next }
+ in_assets && /^[[:space:]]*}/ { exit }
+ in_assets && index($0, target) {
+ sub(/^.*:[[:space:]]*"/, "")
+ sub(/".*$/, "")
+ print
+ exit
+ }
+ ')"
+ SHA256="$(printf '%s\n' "$MANIFEST" | awk -v target="\"${TARGET}\"" '
+ /^[[:space:]]*"sha256"[[:space:]]*:/ { in_sha256 = 1; next }
+ in_sha256 && /^[[:space:]]*}/ { exit }
+ in_sha256 && index($0, target) {
+ sub(/^.*:[[:space:]]*"/, "")
+ sub(/".*$/, "")
+ print
+ exit
+ }
+ ')"
+ VERSION="$(printf '%s\n' "$MANIFEST" | awk -F '"' '/^[[:space:]]*"version"[[:space:]]*:/ { print $4; exit }')"
+
+ if [ -z "$URL" ]; then
+ err "release manifest does not include a binary for ${TARGET}"
+ fi
+ if [ "${#SHA256}" -ne 64 ]; then
+ err "release manifest does not include a valid SHA-256 checksum for ${TARGET}"
+ fi
+ if ! printf '%s\n' "$SHA256" | awk '/[^0-9A-Fa-f]/ { exit 1 }'; then
+ err "release manifest does not include a valid SHA-256 checksum for ${TARGET}"
+ fi
+ SHA256="$(printf '%s\n' "$SHA256" | awk '{ print tolower($0) }')"
+
+ if command -v sha256sum >/dev/null 2>&1; then
+ SHA256_TOOL="sha256sum"
+ elif command -v shasum >/dev/null 2>&1; then
+ SHA256_TOOL="shasum"
+ elif command -v openssl >/dev/null 2>&1; then
+ SHA256_TOOL="openssl"
+ else
+ err "SHA-256 verification requires sha256sum, shasum, or openssl"
+ fi
+
+ if [ -n "$VERSION" ]; then
+ log "downloading v${VERSION}..."
+ else
+ log "downloading latest release..."
+ fi
+ TMP="$(mktemp -d)"
+ trap 'rm -rf "$TMP"' EXIT
+
+ if ! curl -fsSL --retry 3 --connect-timeout 10 --max-time 120 "$URL" -o "${TMP}/${BIN}"; then
+ err "download failed from ${URL}"
+ fi
+
+ case "$SHA256_TOOL" in
+ sha256sum) ACTUAL_SHA256="$(sha256sum < "${TMP}/${BIN}" | awk '{ print $1 }')" ;;
+ shasum) ACTUAL_SHA256="$(shasum -a 256 < "${TMP}/${BIN}" | awk '{ print $1 }')" ;;
+ openssl) ACTUAL_SHA256="$(openssl dgst -sha256 < "${TMP}/${BIN}" | awk '{ print $NF }')" ;;
+ esac
+ if [ "$ACTUAL_SHA256" != "$SHA256" ]; then
+ err "downloaded Herdr checksum did not match"
+ fi
+
+ # install
+ mkdir -p "$INSTALL_DIR"
+ mv "${TMP}/${BIN}" "${INSTALL_DIR}/${BIN}"
+ chmod +x "${INSTALL_DIR}/${BIN}"
+
+ log "installed ${BIN} to ${INSTALL_DIR}/${BIN}"
+
+ # check PATH
+ case ":${PATH}:" in
+ *":${INSTALL_DIR}:"*) ;;
+ *)
+ echo ""
+ warn "${INSTALL_DIR} is not in your PATH"
+ echo " add it to your shell config:"
+ echo ""
+ echo " export PATH=\"${INSTALL_DIR}:\$PATH\""
+ echo ""
+ ;;
+ esac
+
+ # verify
+ if command -v "$BIN" >/dev/null 2>&1; then
+ echo ""
+ log "ready. run 'herdr' to get started."
+ fi
+
+ echo ""
+}
+
+log() { printf ' \033[32m>\033[0m %s\n' "$1"; }
+warn() { printf ' \033[33m!\033[0m %s\n' "$1"; }
+err() { printf ' \033[31m✗\033[0m %s\n' "$1" >&2; exit 1; }
+
+need() {
+ if ! command -v "$1" >/dev/null 2>&1; then
+ err "requires '$1' — install it first, or download a binary manually from https://herdr.dev/docs/install/"
+ fi
+}
+
+main "$@"