#!/usr/bin/env bash # Builds "shannoncoat.app" — a menu bar app (no Dock icon, no window) with a # custom icon (icon/AppIcon.icns — see icon/generate-icon.swift) for # Finder/Spotlight. It stays running in the menu bar: click the status item # to switch profiles, or open Manage Profiles… (Cmd+,) to add/remove one. # Launch at Login is a toggle inside the app itself. # # Builds into ./.build (gitignored) rather than installing straight into an # Applications dir — copy/drag the .app from there yourself. It's a fully # native, self-contained bundle — no bundled script, so copying it anywhere # after the build is safe. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SOURCES_DIR="$SCRIPT_DIR/Sources" VERSION_FILE="$SCRIPT_DIR/VERSION" ICON_SRC="$SCRIPT_DIR/icon/AppIcon.icns" OUT_DIR="${1:-$SCRIPT_DIR/.build}" APP="$OUT_DIR/shannoncoat.app" # Read from the repo's VERSION file so the .app and the script it bundles # never report different numbers. VERSION="$(cat "$VERSION_FILE" 2>/dev/null)" [[ -n "$VERSION" ]] || { echo "error: couldn't read $VERSION_FILE" >&2; exit 1; } mkdir -p "$OUT_DIR" "$APP/Contents/MacOS" "$APP/Contents/Resources" [[ -f "$ICON_SRC" ]] || { echo "error: $ICON_SRC missing (see icon/generate-icon.swift)" >&2; exit 1; } cp "$ICON_SRC" "$APP/Contents/Resources/AppIcon.icns" cat >"$APP/Contents/Info.plist" < CFBundleNameshannoncoat CFBundleDisplayNameshannoncoat CFBundleIdentifiercom.local.shannoncoat CFBundleVersion$VERSION CFBundleShortVersionString$VERSION CFBundlePackageTypeAPPL CFBundleExecutablelauncher CFBundleIconFileAppIcon LSUIElement NSHighResolutionCapable PLIST command -v swiftc >/dev/null || { echo "error: swiftc not found (install Xcode Command Line Tools: xcode-select --install)" >&2; exit 1; } # VERSION travels in Resources (not baked into the binary) so the About # panel and the update checker read the same file this script stamped into # Info.plist above. cp "$VERSION_FILE" "$APP/Contents/Resources/VERSION" # COMMIT is the short SHA the About tab appends to the version, so one dev # build is distinguishable from another — left empty for a real release # build, since the version number alone is unambiguous there. A release # build is one of: # - SHANNONCOAT_RELEASE_BUILD set by release.yml, which already knows # for certain whether it's building a tag — trusted outright rather # than re-derived, since `git describe` needs full tag refs that a # CI runner's shallow checkout isn't guaranteed to have fetched. # - a local/manual build with HEAD sitting exactly on a tag (checked # via `git describe`, which is reliable here since a normal # non-shallow local clone has its full tag history). GIT_SHA="" if [[ -n "${SHANNONCOAT_RELEASE_BUILD:-}" ]]; then : # release build — leave GIT_SHA empty elif git -C "$SCRIPT_DIR" rev-parse --git-dir >/dev/null 2>&1 \ && ! git -C "$SCRIPT_DIR" describe --tags --exact-match >/dev/null 2>&1; then GIT_SHA="$(git -C "$SCRIPT_DIR" rev-parse --short HEAD 2>/dev/null || true)" fi printf '%s' "$GIT_SHA" >"$APP/Contents/Resources/COMMIT" swiftc -O "$SOURCES_DIR"/*.swift -o "$APP/Contents/MacOS/launcher" touch "$APP" echo "Built: $APP" echo "Copy it to /Applications (or ~/Applications) to install."