#!/bin/sh # Installs rack for the current user: curl -fsSL https://rack.monothread.dev/install | sh # Running it again updates to the latest release. RACK_RELEASES points it at another release host. set -eu releases=${RACK_RELEASES:-https://rack.monothread.dev} share=${XDG_DATA_HOME:-$HOME/.local/share} apps=$share/rack/app bin=$HOME/.local/bin say() { printf 'rack: %s\n' "$*"; } fail() { printf 'rack: %s\n' "$*" >&2; exit 1; } platform() { [ "$(uname -s)" = Linux ] || fail "rack runs on Linux only for now" case "$(uname -m)" in x86_64 | amd64) echo linux-x86_64 ;; *) fail "rack is built for x86_64 only for now, this machine is $(uname -m)" ;; esac } require() { for tool in "$@"; do command -v "$tool" >/dev/null 2>&1 || fail "$tool is required" done } has_library() { ldconfig -p 2>/dev/null | grep -qF "$1" && return 0 for dir in /usr/lib /usr/lib64 /usr/lib/x86_64-linux-gnu /usr/local/lib; do [ -e "$dir/$1" ] && return 0 done return 1 } has_webkit() { has_library libwebkit2gtk-4.1.so.0; } # Canonical's libappindicator shows no icon; rack runs without it, only the tray icon needs it. has_appindicator() { has_library libayatana-appindicator3.so.1; } package_manager() { for manager in pacman apt-get dnf zypper; do command -v "$manager" >/dev/null 2>&1 && echo "$manager" && return 0 done return 0 } webkit_package() { case "$1" in pacman) echo webkit2gtk-4.1 ;; apt-get) echo libwebkit2gtk-4.1-0 ;; dnf) echo webkit2gtk4.1 ;; zypper) echo libwebkit2gtk-4_1-0 ;; esac } appindicator_package() { case "$1" in pacman) echo libayatana-appindicator ;; apt-get) echo libayatana-appindicator3-1 ;; dnf) echo libayatana-appindicator-gtk3 ;; zypper) echo libayatana-appindicator3-1 ;; esac } install_command() { case "$1" in pacman) echo "sudo pacman -S --needed --noconfirm $2" ;; apt-get) echo "sudo apt-get install -y $2" ;; dnf) echo "sudo dnf install -y $2" ;; zypper) echo "sudo zypper install -y $2" ;; esac } install_packages() { command=$(install_command "$1" "$2") say "installing $2 with $1, sudo may ask for your password" if (: /dev/null; then sh -c "$command" "$share/applications/rack.desktop" </dev/null } running_version() { health | sed -n 's/.*"version" *: *"\([^"]*\)".*/\1/p' } # Keeps the new version, the one before it, and whatever version a running daemon still uses. prune() { previous=$(ls -1 "$apps" | grep -vx -e current -e "$1" | sort -V | tail -n 1) ls -1 "$apps" | grep -vx -e current -e "$1" -e "${previous:-current}" -e "${2:-current}" | while read -r old; do rm -rf "${apps:?}/$old" done } report_running() { health=$(health) || return 0 running=$(printf '%s' "$health" | sed -n 's/.*"version" *: *"\([^"]*\)".*/\1/p') pid=$(printf '%s' "$health" | sed -n 's/.*"pid" *: *\([0-9]*\).*/\1/p') [ "$running" = "$1" ] && return 0 say "a rack ${running:-older} daemon is still running; stop it with \"kill $pid\" to use $1 (its terminals end)" } main() { target=$(platform) require curl tar sha256sum sed ensure_libraries work=$(mktemp -d) trap 'rm -rf "$work"' EXIT curl -fsSL "$releases/latest-$target.json" -o "$work/latest.json" || fail "could not reach $releases" version=$(field version "$work/latest.json") url=$(field url "$work/latest.json") sha256=$(field sha256 "$work/latest.json") [ -n "$version" ] && [ -n "$url" ] && [ -n "$sha256" ] || fail "$releases/latest-$target.json is not a rack release" if [ "$(readlink "$apps/current" 2>/dev/null)" = "$version" ] && [ -x "$apps/$version/rack" ]; then say "rack $version is already installed" report_running "$version" exit 0 fi say "downloading rack $version" curl -fsSL "$url" -o "$work/rack.tar.gz" || fail "could not download $url" [ "$(sha256sum "$work/rack.tar.gz" | cut -d ' ' -f 1)" = "$sha256" ] || fail "the download does not match its checksum, nothing was changed" tar -xzf "$work/rack.tar.gz" -C "$work" [ -x "$work/rack-$version/rack" ] && [ -x "$work/rack-$version/rack-shell" ] || fail "the release archive is incomplete, nothing was changed" mkdir -p "$apps" "$bin" rm -rf "${apps:?}/$version" mv "$work/rack-$version" "$apps/$version" ln -sfn "$version" "$apps/current.next" mv -Tf "$apps/current.next" "$apps/current" ln -sfn "$apps/current/rack" "$bin/rack" write_launcher prune "$version" "$(running_version)" say "rack $version installed: open it from your app launcher, or run $apps/current/rack-shell" say "to remove it later: curl -fsSL ${releases}/uninstall | sh" case ":$PATH:" in *":$bin:"*) ;; *) say "add $bin to your PATH to use the rack command" ;; esac report_running "$version" } main