#!/bin/sh # Installs Hobfolk on macOS or Linux: # # curl -fsSL https://hobfolk.dev/install.sh | sh # # It finds the system and the processor, downloads the latest version from https://hobfolk.dev/download, # checks its SHA-256 against the one the server publishes and installs it: # - macOS: Hobfolk.app into /Applications (or ~/Applications when /Applications is not writable); # - Linux: the AppImage into ~/.local/share/hobfolk, the `hobfolk` command in ~/.local/bin and a # menu shortcut. No sudo, nothing outside your home folder. # Run it again to update. HOBFOLK_DOWNLOAD_URL points it at another server (a self-hosted one) and, on # macOS, HOBFOLK_INSTALL_DIR at another folder for Hobfolk.app. set -eu BASE="${HOBFOLK_DOWNLOAD_URL:-https://hobfolk.dev}" BASE="${BASE%/}" say() { printf '%s\n' "$*"; } fail() { printf 'hobfolk: %s\n' "$*" >&2 exit 1 } need() { command -v "$1" >/dev/null 2>&1 || fail "this installer needs '$1'; install it and run again."; } need curl need uname os="$(uname -s)" cpu="$(uname -m)" case "$cpu" in arm64 | aarch64) arch=arm64 ;; x86_64 | amd64) arch=x64 ;; *) fail "unsupported processor: $cpu (Hobfolk runs on x64 and arm64)." ;; esac # Under Rosetta, uname says x86_64 on an Apple Silicon Mac: install the native build. if [ "$os" = Darwin ] && [ "$arch" = x64 ] && [ "$(sysctl -in sysctl.proc_translated 2>/dev/null || echo 0)" = 1 ]; then arch=arm64 fi case "$os" in Darwin) target="mac-$arch-zip" ;; Linux) target="linux-$arch-appimage" ;; *) fail "unsupported system: $os. On Windows, run in PowerShell: irm $BASE/install.ps1 | iex" ;; esac tmp="$(mktemp -d 2>/dev/null || mktemp -d -t hobfolk)" trap 'rm -rf "$tmp"' EXIT INT TERM # The checksum first: it names the file, and a 404 means nothing is published for this system yet. code="$(curl -sSL -o "$tmp/sum" -w '%{http_code}' "$BASE/download/$target.sha256" || true)" case "$code" in 200) ;; 404) fail "there is no Hobfolk build for $os $arch at $BASE yet. See $BASE/download" ;; *) fail "could not reach $BASE (HTTP $code). Check your connection and try again." ;; esac expected="$(cut -d ' ' -f 1 <"$tmp/sum")" file="$(sed -n 's/^[0-9a-f]\{64\} *//p' "$tmp/sum" | head -n 1)" [ -n "$expected" ] && [ -n "$file" ] || fail "the server sent an unexpected checksum file." case "$file" in */* | .*) fail "the server sent an unexpected file name: $file" ;; esac say "Downloading ${file}…" curl -fL --progress-bar -o "$tmp/$file" "$BASE/download/$target" || fail "the download failed; run the command again." if command -v shasum >/dev/null 2>&1; then actual="$(shasum -a 256 "$tmp/$file" | cut -d ' ' -f 1)" elif command -v sha256sum >/dev/null 2>&1; then actual="$(sha256sum "$tmp/$file" | cut -d ' ' -f 1)" else fail "no shasum or sha256sum to check the download with." fi [ "$actual" = "$expected" ] || fail "the download does not match its SHA-256 (expected $expected, got $actual). Nothing was installed." say "SHA-256 checked." if [ "$os" = Darwin ]; then need ditto ditto -x -k "$tmp/$file" "$tmp/app" [ -d "$tmp/app/Hobfolk.app" ] || fail "the archive has no Hobfolk.app." dest="${HOBFOLK_INSTALL_DIR:-/Applications}" if [ -z "${HOBFOLK_INSTALL_DIR:-}" ] && [ ! -w "$dest" ]; then dest="$HOME/Applications" fi if pgrep -xq Hobfolk 2>/dev/null; then say "Hobfolk is open: quit it before opening the new version."; fi updated=no; [ -d "$dest/Hobfolk.app" ] && updated=yes mkdir -p "$dest" rm -rf "$dest/Hobfolk.app" ditto "$tmp/app/Hobfolk.app" "$dest/Hobfolk.app" # Downloaded by curl, not a browser: no quarantine flag to clear, but a copied one would block it. xattr -dr com.apple.quarantine "$dest/Hobfolk.app" 2>/dev/null || true say "" if [ "$updated" = yes ]; then say "Hobfolk is updated in $dest/Hobfolk.app."; else say "Hobfolk is installed in $dest/Hobfolk.app."; fi say "Open it from Launchpad, or run: open \"$dest/Hobfolk.app\"" else data="${XDG_DATA_HOME:-$HOME/.local/share}" bin="$HOME/.local/bin" mkdir -p "$data/hobfolk" "$bin" "$data/applications" "$data/icons/hicolor/256x256/apps" install_path="$data/hobfolk/Hobfolk.AppImage" updated=no; [ -f "$install_path" ] && updated=yes if pgrep -f "$install_path" >/dev/null 2>&1; then say "Hobfolk is open: quit it before opening the new version."; fi mv -f "$tmp/$file" "$install_path" chmod 755 "$install_path" ln -sf "$install_path" "$bin/hobfolk" curl -fsSL -o "$data/icons/hicolor/256x256/apps/hobfolk.png" "$BASE/site/assets/brand/icone-256.png" 2>/dev/null || true cat >"$data/applications/hobfolk.desktop" </dev/null 2>&1 && update-desktop-database "$data/applications" >/dev/null 2>&1 || true say "" if [ "$updated" = yes ]; then say "Hobfolk is updated: run 'hobfolk' or open it from your applications menu."; else say "Hobfolk is installed: run 'hobfolk' or open it from your applications menu."; fi case ":$PATH:" in *":$bin:"*) ;; *) say "Add $bin to your PATH to run 'hobfolk' from any terminal." ;; esac # AppImages need FUSE 2 to mount themselves. if ! { ldconfig -p 2>/dev/null | grep -q 'libfuse\.so\.2'; }; then say "If it does not open, install FUSE 2 (Debian/Ubuntu: sudo apt install libfuse2t64, or libfuse2 on older releases)." fi fi [ "$updated" = yes ] || say "Then sign in with your Hobfolk account, open a folder and ask in one sentence."