#!/bin/sh # OmpDeck installer (per-user, no root). Also installs omp (prebuilt, to ~/.local/bin) if missing. # # curl -fsSL https://raw.githubusercontent.com/lavinhoque33/omp-deck/main/packaging/install.sh | sh # ./install.sh from an extracted release tarball: install that build # ./install.sh --uninstall remove everything this script installed (omp stays) # # Options: --version install a specific release instead of the latest # --prefix install under instead of ~/.local # --no-omp do not install omp when it is missing # --uninstall remove the installed files set -eu REPO="lavinhoque33/omp-deck" APP="omp-deck" SIZES="16 24 32 48 64 128 256 512" OMP_INSTALL_URL="https://omp.sh/install" prefix="${HOME}/.local" version="" uninstall=0 with_omp=1 say() { printf '%s\n' "$*"; } warn() { printf 'warning: %s\n' "$*" >&2; } die() { printf 'error: %s\n' "$*" >&2; exit 1; } while [ $# -gt 0 ]; do case "$1" in --uninstall) uninstall=1 ;; --no-omp) with_omp=0 ;; --version) [ $# -ge 2 ] || die "--version needs a value"; version=${2#v}; shift ;; --prefix) [ $# -ge 2 ] || die "--prefix needs a value"; prefix=$2; shift ;; -h|--help) sed -n '2,11p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) die "unknown option: $1" ;; esac shift done data_home="${XDG_DATA_HOME:-}" if [ "$prefix" != "${HOME}/.local" ] || [ -z "$data_home" ]; then data_home="$prefix/share" fi bin_dir="$prefix/bin" apps_dir="$data_home/applications" icon_root="$data_home/icons/hicolor" doc_dir="$prefix/share/doc/$APP" refresh_caches() { if command -v update-desktop-database >/dev/null 2>&1; then update-desktop-database "$apps_dir" >/dev/null 2>&1 || true fi if command -v gtk-update-icon-cache >/dev/null 2>&1 && [ -f "$icon_root/index.theme" ]; then gtk-update-icon-cache -q -t -f "$icon_root" >/dev/null 2>&1 || true fi } if [ "$uninstall" -eq 1 ]; then if [ -x "$bin_dir/$APP-gateway" ]; then "$bin_dir/$APP-gateway" uninstall || die "gateway could not drain; no installed files were removed. Finish or stop the listed jobs and retry." fi rm -f "$bin_dir/$APP" "$bin_dir/$APP-host" "$bin_dir/$APP-gateway" "$apps_dir/$APP.desktop" "$icon_root/scalable/apps/$APP.svg" for s in $SIZES; do rm -f "$icon_root/${s}x${s}/apps/$APP.png" done # Remove the icon directories the install created, but only while they are empty # (rmdir refuses to touch a directory that holds another application's files). for s in $SIZES; do rmdir "$icon_root/${s}x${s}/apps" "$icon_root/${s}x${s}" 2>/dev/null || true done rmdir "$icon_root/scalable/apps" "$icon_root/scalable" "$icon_root" 2>/dev/null || true rm -f "$doc_dir/UI-FONTS-OFL.txt" "$doc_dir/JetBrainsMono-OFL.txt" "$doc_dir/Geist-OFL.txt" "$doc_dir/lucide-LICENSE.txt" rmdir "$doc_dir" "$prefix/share/doc" 2>/dev/null || true rmdir "$(dirname "$icon_root")" 2>/dev/null || true refresh_caches say "OmpDeck uninstalled from $prefix." say "Settings in \${XDG_CONFIG_HOME:-~/.config}/omp-deck and data in \${XDG_DATA_HOME:-~/.local/share}/omp-deck were left in place." exit 0 fi [ "$(uname -s)" = "Linux" ] || die "OmpDeck only supports Linux" case "$(uname -m)" in x86_64|amd64) ;; *) die "release builds exist for x86_64 only (this machine: $(uname -m)); build from source instead" ;; esac # Source directory: the extracted tarball this script sits in, else a fresh download. src="" tmp="" binary_stage="" gateway_drained=0 bundle_committed=0 gateway_resume_attempted=0 cleanup() { status=$? if [ "$bundle_committed" -eq 1 ] && [ "$gateway_resume_attempted" -eq 0 ]; then gateway_resume_attempted=1 "$bin_dir/$APP-gateway" resume || warn "background gateway repair failed; run '$bin_dir/$APP-gateway resume' after resolving the reported error" elif [ "$gateway_drained" -eq 1 ] && [ "$bundle_committed" -eq 0 ]; then warn "the gateway remains paused. Re-run this installer to finish the complete binary bundle before resuming it." fi [ -z "$binary_stage" ] || rm -rf "$binary_stage" [ -z "$tmp" ] || rm -rf "$tmp" return "$status" } trap cleanup EXIT trap 'exit 130' INT trap 'exit 143' TERM script_dir="" case "$0" in */*) script_dir=$(cd "$(dirname "$0")" 2>/dev/null && pwd) || script_dir="" ;; # `sh install.sh` leaves $0 without a slash; the tarball payload is in the cwd then. *) if [ -f ./install.sh ]; then script_dir=$(pwd); fi ;; esac if [ -n "$script_dir" ] && [ -x "$script_dir/$APP" ] && [ -f "$script_dir/$APP.desktop" ] && [ -z "$version" ]; then src=$script_dir else command -v tar >/dev/null 2>&1 || die "tar is required" if command -v curl >/dev/null 2>&1; then fetch() { curl -fsSL "$1"; } fetch_to() { curl -fsSL -o "$2" "$1"; } elif command -v wget >/dev/null 2>&1; then fetch() { wget -qO- "$1"; } fetch_to() { wget -qO "$2" "$1"; } else die "curl or wget is required" fi if [ -z "$version" ]; then say "Looking up the latest release..." version=$(fetch "https://api.github.com/repos/$REPO/releases/latest" \ | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v\{0,1\}\([^"]*\)".*/\1/p' | head -n1) || true [ -n "$version" ] || die "could not determine the latest release (see https://github.com/$REPO/releases)" fi name="$APP-$version-x86_64-linux" url="https://github.com/$REPO/releases/download/v$version/$name.tar.gz" tmp=$(mktemp -d) say "Downloading $url" fetch_to "$url" "$tmp/$name.tar.gz" || die "download failed" if fetch_to "$url.sha256" "$tmp/$name.tar.gz.sha256" 2>/dev/null && command -v sha256sum >/dev/null 2>&1; then (cd "$tmp" && sha256sum -c "$name.tar.gz.sha256" >/dev/null) || die "checksum mismatch" else warn "checksum not verified" fi tar -xzf "$tmp/$name.tar.gz" -C "$tmp" src="$tmp/$name" [ -x "$src/$APP" ] || die "unexpected archive layout" fi # Stage the complete bundle before asking the old owner to drain. Atomic renames also work # while an older GUI/host executable is mapped; truncating a running executable does not. for executable in "$APP" "$APP-host" "$APP-gateway"; do [ -x "$src/$executable" ] || die "$executable is missing from the release. For a pre-gateway release, use that release's bundled installer." done mkdir -p "$bin_dir" "$apps_dir" binary_stage=$(mktemp -d "$bin_dir/.omp-deck-install.XXXXXX") for executable in "$APP" "$APP-host" "$APP-gateway"; do install -m 0755 "$src/$executable" "$binary_stage/$executable" done if [ -x "$bin_dir/$APP-gateway" ]; then "$bin_dir/$APP-gateway" drain --purpose update || die "gateway could not drain; no binaries were replaced. Finish or stop the listed jobs and retry." gateway_drained=1 fi for executable in "$APP-host" "$APP-gateway" "$APP"; do mv -f "$binary_stage/$executable" "$bin_dir/$executable" done bundle_committed=1 # The desktop entry needs an absolute Exec so launchers work even when ~/.local/bin is not on PATH. sed -e "s|^Exec=.*|Exec=$bin_dir/$APP %f|" -e "s|^TryExec=.*|TryExec=$bin_dir/$APP|" \ "$src/$APP.desktop" > "$apps_dir/$APP.desktop" chmod 0644 "$apps_dir/$APP.desktop" for s in $SIZES; do if [ -f "$src/icons/$APP-$s.png" ]; then mkdir -p "$icon_root/${s}x${s}/apps" install -m 0644 "$src/icons/$APP-$s.png" "$icon_root/${s}x${s}/apps/$APP.png" fi done if [ -f "$src/icons/$APP.svg" ]; then mkdir -p "$icon_root/scalable/apps" install -m 0644 "$src/icons/$APP.svg" "$icon_root/scalable/apps/$APP.svg" fi # Bundled font licenses; older release tarballs predate licenses/ and are skipped. The UI fonts # share one combined OFL file; the per-font files of older installs (Geist, JetBrains Mono) go. rm -f "$doc_dir/Geist-OFL.txt" "$doc_dir/JetBrainsMono-OFL.txt" for lic in UI-FONTS-OFL.txt lucide-LICENSE.txt; do for cand in "$src/licenses/$lic" "$src/$lic"; do if [ -f "$cand" ]; then mkdir -p "$doc_dir" install -m 0644 "$cand" "$doc_dir/$lic" break fi done done refresh_caches # omp: OmpDeck finds it on PATH or in ~/.local/bin (where omp's --binary installer puts it). if command -v omp >/dev/null 2>&1 || [ -x "$HOME/.local/bin/omp" ]; then : elif [ "$with_omp" -eq 0 ]; then warn "'omp' was not found; OmpDeck needs it. Use OmpDeck's 'Install omp' button or run: curl -fsSL $OMP_INSTALL_URL | sh" else say "omp was not found; installing it with its official installer ($OMP_INSTALL_URL)..." omp_script="" if command -v curl >/dev/null 2>&1; then omp_script=$(curl -fsSL "$OMP_INSTALL_URL") || omp_script="" elif command -v wget >/dev/null 2>&1; then omp_script=$(wget -qO- "$OMP_INSTALL_URL") || omp_script="" fi if [ -n "$omp_script" ] && printf '%s\n' "$omp_script" | sh -s -- --binary; then : else warn "installing omp failed; OmpDeck offers an 'Install omp' button to retry" fi fi # Resume clears a prior maintenance barrier even in Off mode. It only repairs/enables # supervision when the user had already opted into Background. gateway_resume_attempted=1 if ! "$bin_dir/$APP-gateway" resume; then die "OmpDeck files were installed, but background gateway repair failed. Resolve the reported error and run '$bin_dir/$APP-gateway resume'." fi say "Installed OmpDeck to $bin_dir/$APP" command -v tmux >/dev/null 2>&1 || warn "'tmux' was not found; OmpDeck will use its session host." case ":$PATH:" in *":$bin_dir:"*) ;; *) warn "$bin_dir is not on your PATH; add it to launch 'omp-deck' from a shell" ;; esac