#!/bin/sh # Installs the latest XTermium release from GitHub, on Linux (x64) or macOS: # # curl -fsSL https://xtermium.com/install.sh | sh # # Linux takes the package your system installs: the .deb where apt is, the .rpm where dnf, yum or # zypper is, else the AppImage as ~/.local/bin/xtermium. XTERMIUM_PACKAGE=deb, rpm or appimage # picks one. macOS takes the universal .dmg into /Applications. Every download is checked against # the sha256 GitHub publishes for it before anything is installed. set -eu repo=xtermium/xtermium say() { printf 'xtermium: %s\n' "$*" >&2; } die() { say "$*"; exit 1; } command -v curl >/dev/null 2>&1 || die "needs curl" release=$(curl -fsL -H 'Accept: application/vnd.github+json' "https://api.github.com/repos/$repo/releases/latest") || die "no public release yet; see https://xtermium.com/#downloads" # The download address and sha256 of the first asset whose address ends in $1 (an awk regex; # write a dot as [.]). Splitting on commas puts one JSON field on a line, pretty-printed or not; # an asset's digest comes before its address. asset() { printf '%s' "$release" | tr ',' '\n' | awk -F'"' -v want="$1" ' $2 == "digest" { sum = $4; sub(/^sha256:/, "", sum) } $2 == "browser_download_url" { if ($4 ~ want "$") { print $4, sum; exit } sum = "" }' } tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT # Downloads the asset matching $1 into $tmp, checks its sha256 and prints its path; says $2 and # stops when the release has no such asset. fetch() { found=$(asset "$1") [ -n "$found" ] || die "$2" url=${found%% *} sum=${found#* } file=$tmp/${url##*/} say "downloading ${url##*/}" curl -fL --progress-bar -o "$file" "$url" if [ "$sum" = "$url" ] || [ -z "$sum" ]; then die "GitHub publishes no sha256 for ${url##*/}; not installing it unchecked" fi if command -v sha256sum >/dev/null 2>&1; then got=$(sha256sum "$file"); else got=$(shasum -a 256 "$file"); fi [ "${got%% *}" = "$sum" ] || die "sha256 mismatch for ${url##*/}; not installing it" say "sha256 checked" printf '%s\n' "$file" } as_root() { if [ "$(id -u)" -eq 0 ]; then "$@" elif command -v sudo >/dev/null 2>&1; then sudo "$@" else die "needs root, or sudo, to install a package" fi } case $(uname -s) in Linux) [ "$(uname -m)" = x86_64 ] || die "builds are x64 only, and this is $(uname -m)" kind=${XTERMIUM_PACKAGE:-} if [ -z "$kind" ]; then if command -v apt-get >/dev/null 2>&1; then kind=deb elif command -v dnf >/dev/null 2>&1 || command -v yum >/dev/null 2>&1 || command -v zypper >/dev/null 2>&1; then kind=rpm else kind=appimage fi fi case $kind in deb) file=$(fetch '_amd64[.]deb' "this release has no .deb") || exit 1 as_root apt-get install -y "$file" ;; rpm) file=$(fetch '[.]x86_64[.]rpm' "this release has no .rpm") || exit 1 if command -v dnf >/dev/null 2>&1; then as_root dnf install -y "$file" elif command -v zypper >/dev/null 2>&1; then as_root zypper --non-interactive install --allow-unsigned-rpm "$file" else as_root yum install -y "$file" fi ;; appimage) file=$(fetch '_amd64[.]AppImage' "this release has no AppImage") || exit 1 mkdir -p "$HOME/.local/bin" cp "$file" "$HOME/.local/bin/xtermium" chmod 755 "$HOME/.local/bin/xtermium" say "installed as ~/.local/bin/xtermium" ;; *) die "XTERMIUM_PACKAGE is deb, rpm or appimage, not $kind" ;; esac ;; Darwin) file=$(fetch '_universal[.]dmg' "the macOS build is coming soon; see https://xtermium.com/#downloads") || exit 1 hdiutil attach -nobrowse -quiet -mountpoint "$tmp/dmg" "$file" app=$(find "$tmp/dmg" -maxdepth 1 -name '*.app' | head -n 1) if [ -z "$app" ]; then hdiutil detach -quiet "$tmp/dmg"; die "no app in ${file##*/}"; fi # /Applications is writable by admins only; anyone else gets their own ~/Applications. dest=/Applications [ -w "$dest" ] || { dest=$HOME/Applications; mkdir -p "$dest"; } rm -rf "$dest/${app##*/}" ditto "$app" "$dest/${app##*/}" hdiutil detach -quiet "$tmp/dmg" say "installed to $dest/${app##*/}" ;; *) die "no build for $(uname -s); see https://xtermium.com/#downloads" ;; esac say "done"