Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ git clone https://github.com/splunk/token-meter.git
The installer stages a stable per-user runtime, starts the local server and
native companion, and configures automatic startup.

For a browser-dashboard-only installation without the macOS menu-bar or Linux
tray companion, use `./token-meter/scripts/install --backend-only`. This mode
does not require the Swift toolchain or Linux GTK/AppIndicator packages, and it
is preserved by automatic updates.

### Windows

> **Beta:** The Windows extension is still in beta.
Expand All @@ -40,6 +45,11 @@ The bootstrap uses WinGet from Microsoft App Installer to install missing Git an
It then stages the beta extension without administrator access. From an
existing checkout, rerun `.\scripts\install-windows.cmd`.

For a browser-dashboard-only installation without the Windows notification-area companion,
add `-BackendOnly` to the downloaded bootstrap invocation
(`& $p -BackendOnly`) or run `.\scripts\install-windows.cmd -BackendOnly` from
an existing checkout. Automatic updates preserve this mode.

### Open Token Meter

Open [http://127.0.0.1:8722](http://127.0.0.1:8722), start a normal agent run,
Expand Down
9 changes: 7 additions & 2 deletions scripts/bootstrap-windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
param(
[string]$SourceRoot = "",
[string]$InstallRoot = "",
[switch]$NoOpenDashboard
[switch]$NoOpenDashboard,
[switch]$BackendOnly
)

$ErrorActionPreference = "Stop"
Expand Down Expand Up @@ -231,7 +232,11 @@ Write-Host "Managed source: $SourceRoot"
$PreviousSourceOverride = $env:TOKEN_METER_SOURCE_ROOT
try {
$env:TOKEN_METER_SOURCE_ROOT = $SourceRoot
& $Wrapper -InstallRoot $InstallRoot
$InstallerArguments = @("-InstallRoot", $InstallRoot)
if ($BackendOnly) {
$InstallerArguments += "-BackendOnly"
}
& $Wrapper @InstallerArguments
if ($LASTEXITCODE -ne 0) {
Fail "the Token Meter runtime installer failed."
}
Expand Down
64 changes: 53 additions & 11 deletions scripts/install
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@
set -euo pipefail

SOURCE_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BACKEND_ONLY=0

usage() {
cat <<EOF
Usage: $0 [--backend-only]

Options:
--backend-only Install and start only the local server; skip the native companion.
-h, --help Show this help.
EOF
}

for argument in "$@"; do
case "$argument" in
--backend-only)
BACKEND_ONLY=1
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $argument" >&2
usage >&2
exit 2
;;
esac
done

PLATFORM="$(uname -s)"
if [[ "$PLATFORM" == "Linux" ]]; then
exec "$SOURCE_ROOT/scripts/install-linux" "$@"
Expand All @@ -26,7 +55,10 @@ fail() {
exit 1
}

required_commands=(git python3 curl swiftc launchctl ditto)
required_commands=(git python3 curl launchctl ditto)
if (( ! BACKEND_ONLY )); then
required_commands+=(swiftc)
fi
for command_name in "${required_commands[@]}"; do
if ! command -v "$command_name" >/dev/null 2>&1; then
if [[ "$command_name" == "swiftc" ]]; then
Expand Down Expand Up @@ -172,7 +204,11 @@ else
echo "Local Git delivery history will remain partial until a readable repository is observed."
fi

"$INSTALL_ROOT/scripts/install-launch-agent" server-only
if (( BACKEND_ONLY )); then
"$INSTALL_ROOT/scripts/install-launch-agent" backend-only
else
"$INSTALL_ROOT/scripts/install-launch-agent" server-only
fi

health_json=""
readiness_deadline=$((SECONDS + READINESS_TIMEOUT_SECONDS))
Expand Down Expand Up @@ -212,22 +248,28 @@ if not matches:
f"(page_path={page or 'unknown'}).")
' "$INSTALL_ROOT"

"$INSTALL_ROOT/scripts/install-launch-agent" menubar-only
if (( BACKEND_ONLY )); then
printf '%s\n' "backend-only" > "$INSTALL_ROOT/INSTALL_MODE"
else
"$INSTALL_ROOT/scripts/install-launch-agent" menubar-only

if ! menubar_launch_state="$(launchctl print "gui/$UID/$MENUBAR_LABEL" 2>&1)"; then
fail "the menu bar LaunchAgent was not registered."
fi
[[ "$menubar_launch_state" == *"$INSTALL_ROOT/scripts/run-menubar"* ]] \
|| fail "a different Token Meter installation owns the menu bar LaunchAgent."
if ! menubar_launch_state="$(launchctl print "gui/$UID/$MENUBAR_LABEL" 2>&1)"; then
fail "the menu bar LaunchAgent was not registered."
fi
[[ "$menubar_launch_state" == *"$INSTALL_ROOT/scripts/run-menubar"* ]] \
|| fail "a different Token Meter installation owns the menu bar LaunchAgent."

curl -fsS --max-time 5 "$MENUBAR_URL" \
| python3 -c 'import json, sys; json.load(sys.stdin)' \
|| fail "the menu bar endpoint did not return valid JSON."
curl -fsS --max-time 5 "$MENUBAR_URL" \
| python3 -c 'import json, sys; json.load(sys.stdin)' \
|| fail "the menu bar endpoint did not return valid JSON."
printf '%s\n' "full" > "$INSTALL_ROOT/INSTALL_MODE"
fi

echo
echo "Token Meter installation complete."
echo "Dashboard: $DASHBOARD_URL"
echo "Starts automatically after you log in."
(( BACKEND_ONLY )) && echo "Backend-only installation: native companion skipped."
echo "Runtime: $INSTALL_ROOT"
[[ -n "$commit" ]] && echo "Installed commit: $commit"
echo "Uninstall: $INSTALL_ROOT/scripts/uninstall-launch-agent"
26 changes: 17 additions & 9 deletions scripts/install-launch-agent
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ SERVER_PROGRAM="$ROOT/meter.py"
MENUBAR_PROGRAM="$ROOT/scripts/run-menubar"

case "$MODE" in
all|server-only|menubar-only) ;;
all|server-only|menubar-only|backend-only) ;;
*)
echo "Usage: $0 [all|server-only|menubar-only]" >&2
echo "Usage: $0 [all|server-only|menubar-only|backend-only]" >&2
exit 2
;;
esac
Expand All @@ -28,7 +28,7 @@ if [[ ! -f "$SERVER_PROGRAM" ]]; then
echo "Missing server: $SERVER_PROGRAM" >&2
exit 1
fi
if [[ ! -x "$MENUBAR_PROGRAM" ]]; then
if [[ "$MODE" != "backend-only" && ! -x "$MENUBAR_PROGRAM" ]]; then
echo "Missing executable menu bar runner: $MENUBAR_PROGRAM" >&2
echo "Run: chmod +x $MENUBAR_PROGRAM" >&2
exit 1
Expand Down Expand Up @@ -76,7 +76,8 @@ then
exit 1
fi

if ! cat > "$MENUBAR_PLIST" <<PLIST
if [[ "$MODE" != "backend-only" ]]; then
if ! cat > "$MENUBAR_PLIST" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
Expand Down Expand Up @@ -106,11 +107,12 @@ if ! cat > "$MENUBAR_PLIST" <<PLIST
</dict>
</plist>
PLIST
then
echo "Token Meter could not write $MENUBAR_PLIST." >&2
echo "If a coding agent is running this installer, approve its request for that" >&2
echo "exact user LaunchAgent file, then retry." >&2
exit 1
then
echo "Token Meter could not write $MENUBAR_PLIST." >&2
echo "If a coding agent is running this installer, approve its request for that" >&2
echo "exact user LaunchAgent file, then retry." >&2
exit 1
fi
fi

bootstrap_service() {
Expand Down Expand Up @@ -163,6 +165,12 @@ start_menubar() {
}

case "$MODE" in
backend-only)
launchctl bootout "gui/$UID/$MENUBAR_LABEL" >/dev/null 2>&1 || true
rm -f "$MENUBAR_PLIST"
launchctl bootout "gui/$UID/$SERVER_LABEL" >/dev/null 2>&1 || true
start_server
;;
server-only)
launchctl bootout "gui/$UID/$MENUBAR_LABEL" >/dev/null 2>&1 || true
launchctl bootout "gui/$UID/$SERVER_LABEL" >/dev/null 2>&1 || true
Expand Down
65 changes: 52 additions & 13 deletions scripts/install-linux
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,35 @@
set -euo pipefail

SOURCE_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
BACKEND_ONLY=0

usage() {
cat <<EOF
Usage: $0 [--backend-only]

Options:
--backend-only Install and start only the local server; skip the native companion.
-h, --help Show this help.
EOF
}

for argument in "$@"; do
case "$argument" in
--backend-only)
BACKEND_ONLY=1
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $argument" >&2
usage >&2
exit 2
;;
esac
done

PLATFORM="$(uname -s)"
if [[ "$PLATFORM" != "Linux" ]]; then
echo "Token Meter Linux installation failed: this installer requires Linux." >&2
Expand Down Expand Up @@ -34,7 +63,7 @@ RUNTIME_MANIFEST="$SOURCE_ROOT/runtime-manifest.txt"
PYTHONPATH="$SOURCE_ROOT" python3 -m token_meter.packaging manifest "$RUNTIME_MANIFEST" \
|| fail "the runtime packaging manifest is invalid or incomplete."

if ! "$SOURCE_ROOT/scripts/run-menubar" --check; then
if (( ! BACKEND_ONLY )) && ! "$SOURCE_ROOT/scripts/run-menubar" --check; then
fail "the Linux tray dependencies are missing. Install the GTK/AppIndicator packages shown above, then retry."
fi
if ! systemctl --user show-environment >/dev/null 2>&1; then
Expand Down Expand Up @@ -152,7 +181,11 @@ else
echo "Local Git delivery history will remain partial until a readable repository is observed."
fi

"$INSTALL_ROOT/scripts/install-systemd-user" server-only
if (( BACKEND_ONLY )); then
"$INSTALL_ROOT/scripts/install-systemd-user" backend-only
else
"$INSTALL_ROOT/scripts/install-systemd-user" server-only
fi

health_json=""
readiness_deadline=$((SECONDS + READINESS_TIMEOUT_SECONDS))
Expand Down Expand Up @@ -190,22 +223,28 @@ if not matches:
f"(page_path={page or 'unknown'}).")
' "$INSTALL_ROOT"

"$INSTALL_ROOT/scripts/install-systemd-user" menubar-only

systemctl --user is-active --quiet token-meter-tray.service \
|| { journalctl --user -u token-meter-tray.service -n 30 --no-pager >&2 || true; fail "token-meter-tray.service is not running."; }
tray_fragment="$(systemctl --user show token-meter-tray.service -p FragmentPath --value)"
[[ "$tray_fragment" == "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/token-meter-tray.service" ]] \
|| fail "a different unit owns token-meter-tray.service."

curl -fsS --max-time 5 "$MENUBAR_URL" \
| python3 -c 'import json, sys; json.load(sys.stdin)' \
|| fail "the menu bar endpoint did not return valid JSON."
if (( BACKEND_ONLY )); then
printf '%s\n' "backend-only" > "$INSTALL_ROOT/INSTALL_MODE"
else
"$INSTALL_ROOT/scripts/install-systemd-user" menubar-only

systemctl --user is-active --quiet token-meter-tray.service \
|| { journalctl --user -u token-meter-tray.service -n 30 --no-pager >&2 || true; fail "token-meter-tray.service is not running."; }
tray_fragment="$(systemctl --user show token-meter-tray.service -p FragmentPath --value)"
[[ "$tray_fragment" == "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/token-meter-tray.service" ]] \
|| fail "a different unit owns token-meter-tray.service."

curl -fsS --max-time 5 "$MENUBAR_URL" \
| python3 -c 'import json, sys; json.load(sys.stdin)' \
|| fail "the menu bar endpoint did not return valid JSON."
printf '%s\n' "full" > "$INSTALL_ROOT/INSTALL_MODE"
fi

echo
echo "Token Meter installation complete."
echo "Dashboard: $DASHBOARD_URL"
echo "Starts automatically after you log in."
(( BACKEND_ONLY )) && echo "Backend-only installation: native companion skipped."
echo "Runtime: $INSTALL_ROOT"
[[ -n "$commit" ]] && echo "Installed commit: $commit"
echo "Uninstall: $INSTALL_ROOT/scripts/uninstall-systemd-user"
14 changes: 11 additions & 3 deletions scripts/install-systemd-user
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ PYTHON_BIN="$(command -v python3 || true)"
UNIT_ROOT="${ROOT// /\x20}"

case "$MODE" in
all|server-only|menubar-only) ;;
all|server-only|menubar-only|backend-only) ;;
*)
echo "Usage: $0 [all|server-only|menubar-only]" >&2
echo "Usage: $0 [all|server-only|menubar-only|backend-only]" >&2
exit 2
;;
esac
Expand All @@ -38,7 +38,8 @@ RestartSec=5
WantedBy=default.target
UNIT

tee "$TRAY_UNIT" >/dev/null <<UNIT
if [[ "$MODE" != "backend-only" ]]; then
tee "$TRAY_UNIT" >/dev/null <<UNIT
[Unit]
Description=Token Meter desktop tray
After=token-meter-server.service
Expand All @@ -55,6 +56,7 @@ RestartSec=5
[Install]
WantedBy=default.target
UNIT
fi

start_server() {
systemctl --user daemon-reload
Expand All @@ -71,6 +73,12 @@ start_tray() {
}

case "$MODE" in
backend-only)
systemctl --user disable --now token-meter-tray.service >/dev/null 2>&1 || true
rm -f "$TRAY_UNIT"
systemctl --user disable --now token-meter-server.service >/dev/null 2>&1 || true
start_server
;;
server-only)
systemctl --user disable --now token-meter-tray.service >/dev/null 2>&1 || true
systemctl --user disable --now token-meter-server.service >/dev/null 2>&1 || true
Expand Down
Loading