From aee5bb10993a0445c1c3943ee16c7c512765dff5 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Tue, 3 Mar 2026 13:19:01 -0800 Subject: [PATCH] refactor install.sh to match update.sh --- install/install.sh | 125 ++++++++++++++++++++++----------------------- install/update.sh | 114 ----------------------------------------- 2 files changed, 61 insertions(+), 178 deletions(-) delete mode 100755 install/update.sh diff --git a/install/install.sh b/install/install.sh index 0e60819..1d9c42e 100644 --- a/install/install.sh +++ b/install/install.sh @@ -3,115 +3,112 @@ set -euo pipefail ## # toes installer -# Usage: curl -sSL https://toes.dev/install | bash -# Must be run as the 'toes' user. +# Usage: curl -fsSL https://toes.dev/install | sh +# +# Installs or updates toes on a Raspberry Pi. +# Must be run as the 'toes' user with passwordless sudo. -DEST=~/toes REPO="https://git.nose.space/defunkt/toes" +DEST=~/toes +APPS_DIR=~/apps +DATA_DIR=~/data + +BUNDLED_APPS="clock code cron env git metrics" + +# ── Helpers ────────────────────────────────────────────── quiet() { "$@" > /dev/null 2>&1; } +info() { echo ">> $1"; } + +fail() { echo "ERROR: $1" >&2; exit 1; } + +# ── Preflight ──────────────────────────────────────────── + echo "" -echo " ╔══════════════════════════════════╗" -echo " ║ 🐾 toes - personal web appliance ║" -echo " ╚══════════════════════════════════╝" +echo " toes - personal web appliance" echo "" -# Must be running as toes -if [ "$(whoami)" != "toes" ]; then - echo "ERROR: This script must be run as the 'toes' user." - echo "Create the user during Raspberry Pi OS setup." - exit 1 -fi +[ "$(whoami)" = "toes" ] || fail "Must be run as the 'toes' user." +sudo -n true 2>/dev/null || fail "Requires passwordless sudo." -# Must have passwordless sudo (can't prompt when piped from curl) -if ! sudo -n true 2>/dev/null; then - echo "ERROR: This script requires passwordless sudo." - echo "On Raspberry Pi OS, the default user has this already." - exit 1 -fi +# ── System packages ────────────────────────────────────── -# -- System packages -- - -echo ">> Updating system packages" +info "Updating system packages" quiet sudo apt-get update quiet sudo apt-get install -y git libcap2-bin avahi-utils fish unzip -echo ">> Setting fish as default shell" if [ "$(getent passwd toes | cut -d: -f7)" != "/usr/bin/fish" ]; then + info "Setting fish as default shell" quiet sudo chsh -s /usr/bin/fish toes fi -# -- Bun -- +# ── Bun ────────────────────────────────────────────────── -BUN_REAL="$HOME/.bun/bin/bun" -BUN_SYMLINK="/usr/local/bin/bun" +BUN="$HOME/.bun/bin/bun" -if [ ! -x "$BUN_REAL" ]; then - echo ">> Installing bun" +if [ ! -x "$BUN" ]; then + info "Installing bun" curl -fsSL https://bun.sh/install | bash > /dev/null 2>&1 - if [ ! -x "$BUN_REAL" ]; then - echo "ERROR: bun installation failed" - exit 1 - fi + [ -x "$BUN" ] || fail "bun installation failed." fi -if [ ! -x "$BUN_SYMLINK" ]; then - sudo ln -sf "$BUN_REAL" "$BUN_SYMLINK" +if [ ! -x /usr/local/bin/bun ]; then + sudo ln -sf "$BUN" /usr/local/bin/bun fi -echo ">> Setting CAP_NET_BIND_SERVICE on bun" -sudo setcap 'cap_net_bind_service=+ep' "$BUN_REAL" +sudo setcap 'cap_net_bind_service=+ep' "$BUN" -# -- Clone -- +# ── Clone or pull ──────────────────────────────────────── -if [ ! -d "$DEST" ]; then - echo ">> Cloning toes" - git clone "$REPO" "$DEST" +if [ -d "$DEST/.git" ]; then + info "Pulling latest toes" + git -C "$DEST" fetch origin main + git -C "$DEST" reset --hard origin/main else - echo ">> Updating toes" - cd "$DEST" && git pull origin main + info "Cloning toes" + git clone "$REPO" "$DEST" fi -# -- Directories -- +# ── Directories ────────────────────────────────────────── -mkdir -p ~/data ~/apps +mkdir -p "$APPS_DIR" "$DATA_DIR" -# -- Dependencies & build -- +# ── Dependencies & build ───────────────────────────────── -echo ">> Installing dependencies" -cd "$DEST" && bun install +info "Installing dependencies" +cd "$DEST" && quiet bun install -echo ">> Building client" -cd "$DEST" && bun run build +info "Building" +cd "$DEST" && quiet bun run build -# -- Bundled apps -- +# ── Bundled apps ───────────────────────────────────────── -echo ">> Installing bundled apps" -BUNDLED_APPS="clock code cron env git metrics" +info "Installing bundled apps" for app in $BUNDLED_APPS; do - if [ -d "$DEST/apps/$app" ]; then - echo " $app" - cp -r "$DEST/apps/$app" ~/apps/ - if [ -f ~/apps/"$app"/package.json ]; then - quiet bun install --frozen-lockfile --cwd ~/apps/"$app" - fi + [ -d "$DEST/apps/$app" ] || continue + echo " $app" + cp -r "$DEST/apps/$app" "$APPS_DIR/" + if [ -f "$APPS_DIR/$app/package.json" ]; then + quiet bun install --frozen-lockfile --cwd "$APPS_DIR/$app" || quiet bun install --cwd "$APPS_DIR/$app" fi done -# -- Systemd -- +# ── Systemd ────────────────────────────────────────────── -echo ">> Installing toes service" -sudo install -m 644 -o root -g root "$DEST/scripts/toes.service" /etc/systemd/system/toes.service +info "Installing toes service" +sudo install -m 644 "$DEST/scripts/toes.service" /etc/systemd/system/toes.service sudo systemctl daemon-reload sudo systemctl enable toes -echo ">> Starting toes" +info "Restarting toes" sudo systemctl restart toes -# -- Done -- +# ── Done ───────────────────────────────────────────────── + +VERSION=$(cd "$DEST" && git describe --tags --always 2>/dev/null || echo "unknown") echo "" -echo " toes is installed and running!" -echo " Visit: http://$(hostname).local" +echo " toes $VERSION is running!" +echo " http://$(hostname).local" echo "" diff --git a/install/update.sh b/install/update.sh deleted file mode 100755 index 1d1d5af..0000000 --- a/install/update.sh +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -## -# toes install / update -# Usage: curl -fsSL https://toes.dev/update | sh -# -# Installs or updates toes on a Raspberry Pi. -# Must be run as the 'toes' user with passwordless sudo. - -REPO="https://git.nose.space/defunkt/toes" -DEST=~/toes -APPS_DIR=~/apps -DATA_DIR=~/data - -BUNDLED_APPS="clock code cron env git metrics" - -# ── Helpers ────────────────────────────────────────────── - -quiet() { "$@" > /dev/null 2>&1; } - -info() { echo ">> $1"; } - -fail() { echo "ERROR: $1" >&2; exit 1; } - -# ── Preflight ──────────────────────────────────────────── - -echo "" -echo " toes - personal web appliance" -echo "" - -[ "$(whoami)" = "toes" ] || fail "Must be run as the 'toes' user." -sudo -n true 2>/dev/null || fail "Requires passwordless sudo." - -# ── System packages ────────────────────────────────────── - -info "Updating system packages" -quiet sudo apt-get update -quiet sudo apt-get install -y git libcap2-bin avahi-utils fish unzip - -if [ "$(getent passwd toes | cut -d: -f7)" != "/usr/bin/fish" ]; then - info "Setting fish as default shell" - quiet sudo chsh -s /usr/bin/fish toes -fi - -# ── Bun ────────────────────────────────────────────────── - -BUN="$HOME/.bun/bin/bun" - -if [ ! -x "$BUN" ]; then - info "Installing bun" - curl -fsSL https://bun.sh/install | bash > /dev/null 2>&1 - [ -x "$BUN" ] || fail "bun installation failed." -fi - -if [ ! -x /usr/local/bin/bun ]; then - sudo ln -sf "$BUN" /usr/local/bin/bun -fi - -sudo setcap 'cap_net_bind_service=+ep' "$BUN" - -# ── Clone or pull ──────────────────────────────────────── - -if [ -d "$DEST/.git" ]; then - info "Pulling latest toes" - git -C "$DEST" fetch origin main - git -C "$DEST" reset --hard origin/main -else - info "Cloning toes" - git clone "$REPO" "$DEST" -fi - -# ── Directories ────────────────────────────────────────── - -mkdir -p "$APPS_DIR" "$DATA_DIR" - -# ── Dependencies & build ───────────────────────────────── - -info "Installing dependencies" -cd "$DEST" && quiet bun install - -info "Building" -cd "$DEST" && quiet bun run build - -# ── Bundled apps ───────────────────────────────────────── - -info "Installing bundled apps" -for app in $BUNDLED_APPS; do - [ -d "$DEST/apps/$app" ] || continue - echo " $app" - cp -r "$DEST/apps/$app" "$APPS_DIR/" - if [ -f "$APPS_DIR/$app/package.json" ]; then - quiet bun install --frozen-lockfile --cwd "$APPS_DIR/$app" || quiet bun install --cwd "$APPS_DIR/$app" - fi -done - -# ── Systemd ────────────────────────────────────────────── - -info "Installing toes service" -sudo install -m 644 "$DEST/scripts/toes.service" /etc/systemd/system/toes.service -sudo systemctl daemon-reload -sudo systemctl enable toes - -info "Restarting toes" -sudo systemctl restart toes - -# ── Done ───────────────────────────────────────────────── - -VERSION=$(cd "$DEST" && git describe --tags --always 2>/dev/null || echo "unknown") - -echo "" -echo " toes $VERSION is running!" -echo " http://$(hostname).local" -echo ""