Files
claude-statusline/install.sh
Taylor Eernisse 90454efe9f fix: install.sh respects CARGO_TARGET_DIR via cargo metadata
The installer hardcoded target/ as the build output directory, but
CARGO_TARGET_DIR (or [build] target-dir in cargo config) can redirect
output anywhere (e.g., /tmp/cargo-target). Now uses cargo metadata
--format-version 1 to get the actual target_directory, falling back
to $SCRIPT_DIR/target if metadata fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 08:45:21 -05:00

154 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# install.sh — Build and install claude-statusline (Rust binary)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
INSTALL_DIR="$HOME/.local/bin"
BINARY_NAME="claude-statusline"
CLAUDE_DIR="$HOME/.claude"
SETTINGS="$CLAUDE_DIR/settings.json"
echo "claude-statusline installer"
echo "==========================="
echo ""
# ── Check toolchain ──────────────────────────────────────────────────
if ! command -v cargo &>/dev/null; then
echo "ERROR: cargo (Rust toolchain) is required but not installed."
echo " Install via: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
exit 1
fi
echo "[ok] cargo found ($(cargo --version))"
if ! command -v jq &>/dev/null; then
echo "ERROR: jq is required for settings.json updates."
echo " macOS: brew install jq"
echo " Ubuntu: sudo apt install jq"
exit 1
fi
echo "[ok] jq found"
# ── Build release binary ─────────────────────────────────────────────
echo ""
echo "Building release binary..."
if ! (cd "$SCRIPT_DIR" && cargo build --release); then
echo ""
echo "ERROR: cargo build failed. Check the output above for details."
echo " Common causes:"
echo " - Missing C compiler: sudo apt install build-essential (Debian/Ubuntu)"
echo " - Missing libc headers: sudo apt install libc6-dev"
exit 1
fi
# Find the binary — respects CARGO_TARGET_DIR, custom target triples, etc.
# Use cargo metadata as the source of truth for the target directory.
TARGET_DIR=$(cd "$SCRIPT_DIR" && cargo metadata --format-version 1 --no-deps 2>/dev/null | jq -r '.target_directory' 2>/dev/null) || true
TARGET_DIR="${TARGET_DIR:-$SCRIPT_DIR/target}"
BINARY="$TARGET_DIR/release/$BINARY_NAME"
if [[ ! -f "$BINARY" ]]; then
# Fall back to searching (handles custom target triples like target/<triple>/release/)
BINARY=$(find "$TARGET_DIR" -name "$BINARY_NAME" -type f -path "*/release/*" ! -name "*.d" 2>/dev/null | head -1)
fi
if [[ -z "${BINARY:-}" || ! -f "$BINARY" ]]; then
echo "ERROR: Build succeeded but binary not found."
echo " Target dir: $TARGET_DIR"
echo " Searched: $TARGET_DIR/*/release/$BINARY_NAME"
echo " Contents: $(ls "$TARGET_DIR/release/" 2>/dev/null || echo '(empty or missing)')"
exit 1
fi
echo "[ok] Built: $(ls -lh "$BINARY" | awk '{print $5}')"
# ── Install binary ───────────────────────────────────────────────────
mkdir -p "$INSTALL_DIR"
cp "$BINARY" "$INSTALL_DIR/$BINARY_NAME"
chmod +x "$INSTALL_DIR/$BINARY_NAME"
BINARY_PATH="$INSTALL_DIR/$BINARY_NAME"
echo "[ok] Installed to $BINARY_PATH"
# Verify it's on PATH
if ! command -v "$BINARY_NAME" &>/dev/null; then
echo "[warn] $INSTALL_DIR is not on your PATH"
echo " Add to your shell config: export PATH=\"$INSTALL_DIR:\$PATH\""
fi
# Smoke test — verify the binary actually runs
if "$BINARY_PATH" --test --color=never >/dev/null 2>&1; then
echo "[ok] Binary smoke test passed"
else
echo "[warn] Binary smoke test failed (exit $?). It may still work inside Claude Code."
echo " Debug: $BINARY_PATH --test --dump-state=json"
fi
# ── Configure Claude Code settings.json ──────────────────────────────
echo ""
mkdir -p "$CLAUDE_DIR"
# The binary runs in a non-TTY context, so force color on.
STATUSLINE_CMD="$BINARY_PATH --color=always"
if [[ -f "$SETTINGS" ]]; then
# Update existing settings.json, preserving all other keys
CURRENT_CMD=$(jq -r '.statusLine.command // empty' "$SETTINGS" 2>/dev/null || true)
if [[ -n "$CURRENT_CMD" ]]; then
echo "[info] Previous statusLine command: $CURRENT_CMD"
fi
TMP="$SETTINGS.tmp.$$"
if jq --arg cmd "$STATUSLINE_CMD" '.statusLine = {"type": "command", "command": $cmd, "padding": 0}' "$SETTINGS" > "$TMP" 2>/dev/null; then
mv "$TMP" "$SETTINGS"
echo "[ok] Updated statusLine in $SETTINGS"
else
rm -f "$TMP"
echo "[warn] Failed to update $SETTINGS (invalid JSON?). Creating backup and writing fresh."
cp "$SETTINGS" "$SETTINGS.bak"
jq -n --arg cmd "$STATUSLINE_CMD" '{"statusLine": {"type": "command", "command": $cmd, "padding": 0}}' > "$SETTINGS"
echo "[ok] Wrote fresh $SETTINGS (backup: $SETTINGS.bak)"
fi
else
# Create minimal settings.json
jq -n --arg cmd "$STATUSLINE_CMD" '{"statusLine": {"type": "command", "command": $cmd, "padding": 0}}' > "$SETTINGS"
echo "[ok] Created $SETTINGS"
fi
# Show what was written so the user can verify
echo ""
echo " statusLine config:"
jq '.statusLine' "$SETTINGS" 2>/dev/null || echo " (could not read settings)"
# ── Symlink config ───────────────────────────────────────────────────
CONFIG_SRC="$SCRIPT_DIR/statusline.json"
CONFIG_DST="$CLAUDE_DIR/statusline.json"
if [[ -f "$CONFIG_SRC" ]]; then
if [[ -L "$CONFIG_DST" ]]; then
EXISTING="$(readlink "$CONFIG_DST")"
if [[ "$EXISTING" == "$CONFIG_SRC" ]]; then
echo "[ok] Config already linked"
else
ln -sf "$CONFIG_SRC" "$CONFIG_DST"
echo "[ok] Config symlink updated (was: $EXISTING)"
fi
elif [[ -f "$CONFIG_DST" ]]; then
echo "[skip] $CONFIG_DST exists as a regular file"
echo " To use the symlink, remove it first: rm $CONFIG_DST"
else
ln -s "$CONFIG_SRC" "$CONFIG_DST"
echo "[ok] Config linked: $CONFIG_DST -> $CONFIG_SRC"
fi
else
echo "[info] No statusline.json in project. To customize, create:"
echo " $CONFIG_SRC"
echo ""
echo " Print defaults: $BINARY_NAME --print-defaults"
echo " Print schema: $BINARY_NAME --config-schema"
fi
# ── Done ─────────────────────────────────────────────────────────────
echo ""
echo "Done. RESTART Claude Code (exit and reopen) to see the status line."
echo ""
echo "Verify: $BINARY_PATH --test --color=always"
echo "Debug: $BINARY_PATH --test --dump-state=json"
echo "Settings: cat $SETTINGS | jq .statusLine"