#!/bin/bash
set -euo pipefail
# Install Autodarts on Linux or macOS, from the release this repo publishes: the Desktop
# app, or the headless board daemon.
#
# curl -fsSL https://autodarts.sh/sh/install.sh | bash
# curl -fsSL https://autodarts.sh/sh/install.sh | bash -s -- --beta
# curl -fsSL https://autodarts.sh/sh/install.sh | bash -s -- --headless
# curl -fsSL https://autodarts.sh/sh/install.sh | bash -s -- --uninstall
#
# THE FULL PATH, not the bare domain, until the CDN has a rule for the root: autodarts.sh
# fronts the releases bucket, so /sh/install.sh is this object and / is nothing. Every URL
# printed below is one that works today rather than the shorter one we want — a wrong
# uninstall command is worse than a long one. Swap them when the root redirects here.
#
# THE ONLY SCRIPT HERE THAT RUNS ON SOMEONE ELSE'S MACHINE. Everything else in this
# directory builds or publishes the release; this one is served to users and consumes what
# the others wrote, so it assumes nothing about the repo being present. It lives beside them
# anyway because it parses the artifact names and the index that package-{linux,macos}.sh and
# index-downloads.sh define — one change, one directory, reviewed in the same diff as the
# packaging it has to agree with. `task desktop:publish-installer` uploads it to the releases
# bucket as sh/install.sh; it is expected to move to its own repo eventually, the way the old
# desktop's installer lives in get.git as sh/install_autodarts_desktop.sh (which installs 1.x,
# is a .deb, and does need sudo) — but until there is one, the copy under review is here.
#
# THREE TARGETS, ONE SCRIPT, because only the last step differs. *Deciding what to download*
# is a property of the bucket rather than of the OS: one index, one filename grammar, one rule
# mapping a version to a track. What differs is what a release *is* for each target, and
# where it belongs:
#
# Desktop, Linux ~/.local/bin/autodarts-desktop.AppImage one file, plus a .desktop
# entry we write
# Desktop, macOS /Applications/Autodarts Desktop.app a bundle inside a disk image;
# Spotlight indexes it, so
# there is nothing to write
# headless, Linux ~/.local/share/autodarts/ a tarball of the binary and
# its libraries, plus a symlink
# at ~/.local/bin/autodarts
#
# Which of the two a Linux machine gets is decided from the machine when the caller does not
# say — see pick_mode, and the reason it does not ask $DISPLAY.
#
# Windows is deliberately absent and stays absent: its artifact is a Setup.exe, and driving
# that wants PowerShell rather than another branch here. There is no headless build for
# macOS either: the Desktop hosts the same board core in-process.
#
# NO SUDO, ANYWHERE, and that is a requirement rather than a courtesy: the app updates itself
# in place through Velopack, which replaces the very AppImage or .app it was launched from. A
# root-owned copy is precisely what a normal user cannot replace, so an install that asked for
# a password would be an install that could never update itself again.
#
# That costs nothing on either platform. /Applications is drwxrwxr-x root:admin, so an admin
# account writes to it exactly as Finder does when you drag an app out of a DMG — no prompt.
# A standard account cannot, and falls back to ~/Applications, which is not a lesser location
# but the only one where self-update can work for that user. Spotlight indexes both.
#
# WHAT IT WRITES
# Desktop, Linux ~/.local/bin/autodarts-desktop.AppImage the app
# ~/.local/share/autodarts-desktop/appicon.png its icon
# ~/.local/share/applications/…desktop the menu/search entry
# Desktop, macOS /Applications/Autodarts Desktop.app the app, and only that
# headless ~/.local/share/autodarts/ the bundle
# ~/.local/bin/autodarts a relative symlink
# ~/.local/bin/ad the same, shorthand —
# only when nothing else
# already provides `ad`
#
# and for the Desktop it clears one thing it did not write: Velopack's staged-release cache
# (see clear_velopack_cache below for why that has to happen here). Headless has none.
#
# NEITHER writes config. A predecessor's config.toml may be the only copy of a credential its
# owner has never seen, and deciding what happens to it belongs to the daemon's first run,
# where it can be reasoned about — not to an installer.
#
# THE LINUX FILENAME IS UNVERSIONED ON PURPOSE. Velopack replaces the AppImage at its own
# path, keeping the name, so a file installed as ...autodarts-desktop_2.0.0_linux-arm64.AppImage
# would still be called 2.0.0 after updating itself to 2.1.0. One stable name also means the
# .desktop entry keeps pointing at the app across every update. On macOS the bundle name is
# already version-free, so the same rule needs no special handling.
#
# NOTHING HERE UPDATES ANYTHING. This script installs; the Desktop takes over from the moment
# it first runs, checking the same bucket on its own (apps/desktop/updater.h). Re-running it is
# a supported way to reinstall or to switch tracks, not the way to get a new version.
#
# A headless board does NOT update itself, and the installer must not claim it does: a
# supervised daemon swapping its own binary out from under systemd is the thing that shape of
# deployment exists to avoid. Its updates come from its own CLI.
#
# HOW IT FINDS THE DOWNLOAD. Not by composing a URL from a version: the bucket publishes an
# index of what is actually in it, and this reads that.
#
# /downloads/latest.