#!/bin/sh # greenmask installer # Usage: # curl -fsSL https://greenmask.io/install.sh | sh # sh install.sh --bin-dir /usr/local/bin --yes set -eu APP="greenmaskio" REPO="greenmask" BIN_DIR="/usr/local/bin" VERSION="latest" ASSUME_YES=0 DEBUG=0 info() { printf "> %s\n" "$*"; } warn() { printf "! %s\n" "$*"; } err() { printf "x %s\n" "$*" >&2; } die() { err "$*"; exit 1; } has() { command -v "$1" >/dev/null 2>&1; } usage() { cat <"$tmp" ) 2>/dev/null && { rm -f "$tmp"; return 0; } return 1 } need_sudo_or_exit() { if ! has sudo; then die "need write access to ${BIN_DIR} or 'sudo' for install" fi if ! sudo -v; then die "sudo failed; cannot install to ${BIN_DIR}" fi } check_bin_in_path() { # remove the trailing / dir="${1%/}" OLDIFS="$IFS" IFS=: for p in $PATH; do [ "${p%/}" = "$dir" ] && return 0; done IFS="$OLDIFS" return 1 } print_path_tips() { dir="$1" warn "Bin directory ${dir} is not in your PATH." printf "\nAdd it to your shell config:\n\n" printf "bash: echo 'export PATH=\"%s:\$PATH\"' >> ~/.bashrc && . ~/.bashrc\n" "$dir" printf "zsh: echo 'export PATH=\"%s:\$PATH\"' >> ~/.zshrc && . ~/.zshrc\n" "$dir" printf "\n" } unpack_tar_to() { archive="$1"; dest="$2"; has tar || die "need 'tar' to extract archives" tar xzf "$archive" -C "$dest" } install_asset() { os="$1"; arch="$2"; base="$3" asset="${REPO}-${os}-${arch}.tar.gz" url="${base}/${asset}" has mktemp || die "need 'mktemp' to create temp directories" tmp="$(mktemp -d)" # clean the tmp directory at the end trap 'rm -rf "$tmp"' EXIT INT TERM info "Downloading: ${url}" fetch "$url" "$tmp/$asset" info "Extracting…" unpack_tar_to "$tmp/$asset" "$tmp" info "Verifying checksum…" # find the executable file bin_path="$(find "$tmp" -type f -name "$REPO*" \( -perm -u+x -o -perm -g+x -o -perm -o+x \) 2>/dev/null | head -n1 || true)" [ -n "$bin_path" ] || die "binary '$REPO' not found in archive" verify_checksum_from_archive "$tmp" "$bin_path" sudo="" if ! is_writable "$BIN_DIR"; then warn "Escalated permissions required for ${BIN_DIR}" need_sudo_or_exit sudo="sudo" fi info "Installing to ${BIN_DIR}…" if has install; then $sudo install -m 0755 "$bin_path" "$BIN_DIR/$REPO" else $sudo cp "$bin_path" "$BIN_DIR/$REPO" $sudo chmod 0755 "$BIN_DIR/$REPO" fi info "Installed: $BIN_DIR/$REPO" # Shadowed binary warning present="$(command -v "$REPO" 2>/dev/null || true)" if [ -n "$present" ] && [ "$present" != "$BIN_DIR/$REPO" ]; then warn "'$REPO' on PATH is '$present' (not '$BIN_DIR/$REPO')" fi if ! check_bin_in_path "$BIN_DIR"; then if has realpath; then print_path_tips "$(realpath "$BIN_DIR")"; else print_path_tips "$BIN_DIR"; fi fi printf "✓ %s %sinstalled\n" "$APP" "$( [ "$VERSION" = "latest" ] && printf '' || printf "%s " "$VERSION")" } main() { # Parse args while [ $# -gt 0 ]; do case "$1" in -b|--bin-dir) BIN_DIR="$2"; shift 2 ;; -v|--version) VERSION="$2"; shift 2 ;; -y|--yes) ASSUME_YES=1;shift;; --debug) DEBUG=1; shift;; -h|--help) usage; exit 0 ;; *) die "unknown option: $1" ;; esac done [ "$DEBUG" -eq 1 ] && set -x # If we're not connected to a TTY (piped/CI), default to non-interactive if [ "$ASSUME_YES" -ne 1 ] && [ ! -t 0 ]; then ASSUME_YES=1 fi os="$(detect_os)" arch="$(detect_arch)" base="$(build_base_url)" printf "Configuration\n" info "Bin directory: ${BIN_DIR}" info "OS/ARCH : ${os}/${arch}" info "Version : ${VERSION}" printf "\n" if [ "$ASSUME_YES" -ne 1 ]; then printf "? Install %s %s to %s? [y/N] " "$APP" "$VERSION" "$BIN_DIR" read -r ans || true case "$ans" in y|Y|yes|YES) ;; *) die "aborted" ;; esac fi install_asset "$os" "$arch" "$base" info "Uninstall: rm -f $BIN_DIR/$REPO" } main "$@"