|
#!/bin/bash |
|
|
|
# <xbar.title>Nix Darwin Manager</xbar.title> |
|
# <xbar.version>v1.1</xbar.version> |
|
# <xbar.author>Jon Shaffer</xbar.author> |
|
# <xbar.author.github>jonshaffer</xbar.author.github> |
|
# <xbar.desc>Manage nix-darwin configuration</xbar.desc> |
|
# <xbar.dependencies>nix,nix-darwin</xbar.dependencies> |
|
|
|
# ============================================================================ |
|
# CONFIGURATION |
|
# ============================================================================ |
|
|
|
NIX_DARWIN_PATH=$(realpath /etc/nix-darwin) |
|
CONFIGURATION=$(hostname -s) |
|
TIMESTAMP=$(date +"%Y%m%d_%H%M%S") |
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
|
|
|
# Optional: auto-update all flake inputs before a normal Rebuild (default: false) |
|
AUTO_UPDATE_ON_REBUILD=${AUTO_UPDATE_ON_REBUILD:-false} |
|
|
|
# Log retention settings |
|
LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-30} |
|
MAX_LOG_FILES=${MAX_LOG_FILES:-100} |
|
|
|
# Ensure .logs directory exists with restrictive permissions |
|
mkdir -p "${SCRIPT_DIR}/.logs" |
|
chmod 700 "${SCRIPT_DIR}/.logs" 2>/dev/null || true |
|
|
|
LOG_FILE="${SCRIPT_DIR}/.logs/nix-darwin-${TIMESTAMP}.log" |
|
REBUILD_FLAG="${SCRIPT_DIR}/.logs/.nix-darwin-rebuilding" |
|
REBUILD_PID_FILE="${SCRIPT_DIR}/.logs/.rebuild.pid" |
|
|
|
# Prefer SwiftBar's per-plugin cache directory when available |
|
STORE_SIZE_DIR="${SWIFTBAR_PLUGIN_CACHE_PATH:-${SCRIPT_DIR}/.logs}" |
|
mkdir -p "${STORE_SIZE_DIR}" |
|
STORE_SIZE_CACHE="${STORE_SIZE_DIR}/.nix-store-size-cache" |
|
STORE_SIZE_LOCK="${STORE_SIZE_DIR}/.nix-store-size.lock" |
|
CACHE_TTL=3600 # 1 hour in seconds |
|
|
|
# Error status cache for performance |
|
ERROR_STATUS_CACHE="${SCRIPT_DIR}/.logs/.last-error-status" |
|
|
|
# ---------------------------------------------------------------------------- |
|
# Updates checking (flake inputs + Homebrew) |
|
# ---------------------------------------------------------------------------- |
|
UPDATES_TTL=${UPDATES_TTL:-21600} # 6 hours |
|
UPDATES_DIR="${SWIFTBAR_PLUGIN_CACHE_PATH:-${SCRIPT_DIR}/.logs}" |
|
# Flake inputs updates cache |
|
FLAKE_UPDATES_CACHE="${UPDATES_DIR}/.flake-updates.json" |
|
FLAKE_UPDATES_LOCK="${UPDATES_DIR}/.flake-updates.lock" |
|
# Homebrew updates cache |
|
BREW_UPDATES_CACHE="${UPDATES_DIR}/.brew-updates.json" |
|
BREW_UPDATES_LOCK="${UPDATES_DIR}/.brew-updates.lock" |
|
|
|
# ============================================================================ |
|
# LOAD SHARED UTILITIES |
|
# ============================================================================ |
|
|
|
# Source common utility functions |
|
source "$(dirname "${BASH_SOURCE[0]}")/../lib/common.sh" |
|
|
|
# ============================================================================ |
|
# DEPENDENCY CHECKING |
|
# ============================================================================ |
|
|
|
check_dependencies() { |
|
local missing_deps=() |
|
|
|
for cmd in nix git; do |
|
if ! command -v "$cmd" >/dev/null 2>&1; then |
|
missing_deps+=("$cmd") |
|
fi |
|
done |
|
|
|
if [[ ${#missing_deps[@]} -gt 0 ]]; then |
|
echo "⚠️" |
|
echo "---" |
|
echo "Missing dependencies: ${missing_deps[*]} | color=#ff0000" |
|
echo "---" |
|
echo "Please install missing dependencies to use this plugin" |
|
exit 0 |
|
fi |
|
} |
|
|
|
# ============================================================================ |
|
# CORE FUNCTIONS |
|
# ============================================================================ |
|
|
|
# Returns success if flake directory and lockfile are writable by current user |
|
flake_writable() { |
|
local p="$NIX_DARWIN_PATH" |
|
if [[ ! -d "$p" ]]; then |
|
return 1 |
|
fi |
|
if [[ ! -w "$p" ]]; then |
|
return 1 |
|
fi |
|
if [[ -e "$p/flake.lock" && ! -w "$p/flake.lock" ]]; then |
|
return 1 |
|
fi |
|
return 0 |
|
} |
|
|
|
# Detached, locked, atomic cache updater for /nix/store size |
|
update_store_size_cache_detached() { |
|
# Prevent concurrent updates |
|
if [[ -e "${STORE_SIZE_LOCK}" ]]; then |
|
return |
|
fi |
|
: > "${STORE_SIZE_LOCK}" |
|
nohup nice -n 19 bash -c ' |
|
set -euo pipefail |
|
cache="$1" |
|
lock="$2" |
|
tmp="${cache}.tmp" |
|
cleanup() { /bin/rm -f "$tmp" "$lock"; } |
|
trap cleanup EXIT |
|
if [[ -d /nix/store ]]; then |
|
/usr/bin/du -sh /nix/store 2>/dev/null | /usr/bin/cut -f1 > "$tmp" || true |
|
else |
|
echo "-" > "$tmp" |
|
fi |
|
if [[ -s "$tmp" ]]; then |
|
/bin/mv -f "$tmp" "$cache" |
|
fi |
|
' _ "${STORE_SIZE_CACHE}" "${STORE_SIZE_LOCK}" >/dev/null 2>&1 & disown |
|
} |
|
|
|
get_store_size() { |
|
if [[ -f "$STORE_SIZE_CACHE" ]]; then |
|
local now mtime cache_age cached_size |
|
now=$(date +%s) |
|
# Try GNU stat first, fallback to BSD stat |
|
mtime=$(stat -c "%Y" "$STORE_SIZE_CACHE" 2>/dev/null || stat -f "%m" "$STORE_SIZE_CACHE" 2>/dev/null) |
|
mtime=${mtime:-$now} |
|
cache_age=$(( now - mtime )) |
|
cached_size=$(cat "$STORE_SIZE_CACHE" 2>/dev/null) |
|
|
|
if [[ $cache_age -gt $CACHE_TTL ]]; then |
|
# Refresh cache asynchronously, return old value immediately |
|
update_store_size_cache_detached |
|
fi |
|
if [[ -n "$cached_size" ]]; then |
|
echo "$cached_size" |
|
else |
|
echo "Calculating..." |
|
fi |
|
else |
|
# No cache exists - kick off detached calc and show placeholder |
|
update_store_size_cache_detached |
|
echo "Calculating..." |
|
fi |
|
} |
|
|
|
# Check rebuild status from log with caching for performance |
|
check_rebuild_status() { |
|
local log_file="$1" |
|
|
|
# Only recheck if log is newer than cache |
|
if [[ -f "$log_file" ]] && [[ "$log_file" -nt "$ERROR_STATUS_CACHE" ]]; then |
|
if grep -q "error:\|Rebuild failed" "$log_file" 2>/dev/null; then |
|
echo "error" > "$ERROR_STATUS_CACHE" |
|
else |
|
echo "success" > "$ERROR_STATUS_CACHE" |
|
fi |
|
fi |
|
|
|
cat "$ERROR_STATUS_CACHE" 2>/dev/null || echo "unknown" |
|
} |
|
|
|
# Get last error from log |
|
get_last_error() { |
|
local log_file="$1" |
|
if [[ -f "$log_file" ]]; then |
|
grep -E "error:|failed" "$log_file" 2>/dev/null | tail -1 | cut -c1-80 |
|
fi |
|
} |
|
|
|
# Commit helper for flake changes inside $NIX_DARWIN_PATH |
|
commit_flake() { |
|
# Only attempt commit if this is a git repo |
|
if git -C "$NIX_DARWIN_PATH" rev-parse --show-toplevel >/dev/null 2>&1; then |
|
local files=( |
|
flake.nix |
|
flake.lock |
|
configuration.nix |
|
home.nix |
|
) |
|
if [[ -d "$NIX_DARWIN_PATH/overlays" ]]; then |
|
# Add all overlay .nix files relative to repo root |
|
while IFS= read -r f; do |
|
files+=("${f#"$NIX_DARWIN_PATH/"}") |
|
done < <(find "$NIX_DARWIN_PATH/overlays" -type f -name '*.nix' 2>/dev/null) |
|
fi |
|
# Use sudo if the flake is not writable by current user |
|
local git_cmd=(git -C "$NIX_DARWIN_PATH") |
|
if ! flake_writable; then |
|
git_cmd=(sudo "${git_cmd[@]}") |
|
fi |
|
"${git_cmd[@]}" add "${files[@]}" 2>/dev/null || true |
|
if ! "${git_cmd[@]}" diff --cached --quiet; then |
|
local msg="chore(nix-darwin): auto-update/auto-save ($(date +'%Y-%m-%dT%H:%M:%S%z'))" |
|
"${git_cmd[@]}" commit -m "$msg" --no-verify || true |
|
fi |
|
fi |
|
} |
|
|
|
# Run a command and only keep a log file if it has output |
|
run_and_maybe_log() { |
|
local tmp_log="${LOG_FILE}.tmp" |
|
"$@" >"$tmp_log" 2>&1 |
|
local exit_code=$? |
|
if [[ -s "$tmp_log" ]]; then |
|
mv "$tmp_log" "$LOG_FILE" |
|
else |
|
rm -f "$tmp_log" |
|
fi |
|
return $exit_code |
|
} |
|
|
|
# ============================================================================ |
|
# ACTION HANDLERS |
|
# ============================================================================ |
|
|
|
if [[ "$1" == "open-config" ]]; then |
|
run_and_maybe_log code "$NIX_DARWIN_PATH" |
|
exit 0 |
|
|
|
elif [[ "$1" == "rebuild" ]]; then |
|
# Create rebuild flag file |
|
touch "$REBUILD_FLAG" |
|
|
|
# Commit any pending local changes before rebuild |
|
commit_flake |
|
|
|
if [[ "$AUTO_UPDATE_ON_REBUILD" == "true" ]]; then |
|
echo "Updating all flake inputs before rebuild..." | tee -a "$LOG_FILE" |
|
if flake_writable; then |
|
(cd "$NIX_DARWIN_PATH" && nix flake update) 2>&1 | tee -a "$LOG_FILE" || true |
|
else |
|
echo "No write access to flake; using sudo for update" | tee -a "$LOG_FILE" |
|
(cd "$NIX_DARWIN_PATH" && sudo -H nix flake update) 2>&1 | tee -a "$LOG_FILE" || true |
|
fi |
|
commit_flake |
|
fi |
|
|
|
echo "Starting nix-darwin rebuild at $(date)" | tee "$LOG_FILE" |
|
echo "🔄 Building system configuration... (output will stream below)" |
|
echo "======================================================" |
|
|
|
# Stream output to both terminal and log file in real-time |
|
sudo -H nix run nix-darwin/master#darwin-rebuild -- switch --flake "path:$NIX_DARWIN_PATH#$CONFIGURATION" --show-trace 2>&1 | tee -a "$LOG_FILE" & |
|
|
|
# Store PID for potential cancellation |
|
REBUILD_PID=$! |
|
echo "$REBUILD_PID" > "$REBUILD_PID_FILE" |
|
|
|
# Wait for rebuild to complete |
|
wait "$REBUILD_PID" |
|
EXIT_CODE=$? |
|
|
|
# Cleanup |
|
rm -f "$REBUILD_PID_FILE" |
|
rm -f "$REBUILD_FLAG" |
|
|
|
echo "======================================================" |
|
if [[ $EXIT_CODE -eq 0 ]]; then |
|
echo "Rebuild completed successfully at $(date)" | tee -a "$LOG_FILE" |
|
# Update store size cache in background after successful rebuild |
|
update_store_size_cache_detached |
|
# Clear error status cache |
|
echo "success" > "$ERROR_STATUS_CACHE" |
|
notify "Nix Darwin Manager" "Rebuild completed successfully" "Glass" |
|
echo "✅ Rebuild completed successfully!" |
|
else |
|
echo "Rebuild failed at $(date)" | tee -a "$LOG_FILE" |
|
echo "error" > "$ERROR_STATUS_CACHE" |
|
notify "Nix Darwin Manager" "Rebuild failed - check logs" "Basso" |
|
echo "❌ Rebuild failed! Check logs for details." |
|
fi |
|
|
|
elif [[ "$1" == "cancel-rebuild" ]]; then |
|
if [[ -f "$REBUILD_PID_FILE" ]]; then |
|
REBUILD_PID=$(cat "$REBUILD_PID_FILE" 2>/dev/null) |
|
if is_process_running "$REBUILD_PID"; then |
|
echo "Cancelling rebuild (PID: $REBUILD_PID)..." |
|
sudo kill -TERM "$REBUILD_PID" 2>/dev/null || true |
|
sleep 1 |
|
# Force kill if still running |
|
if is_process_running "$REBUILD_PID"; then |
|
sudo kill -9 "$REBUILD_PID" 2>/dev/null || true |
|
fi |
|
rm -f "$REBUILD_PID_FILE" |
|
rm -f "$REBUILD_FLAG" |
|
notify "Nix Darwin Manager" "Rebuild cancelled" |
|
echo "Rebuild cancelled" >> "$LOG_FILE" |
|
fi |
|
fi |
|
exit 0 |
|
|
|
elif [[ "$1" == "update-rebuild" ]]; then |
|
# Update all flake inputs, then rebuild |
|
touch "$REBUILD_FLAG" |
|
|
|
echo "Starting flake update (all inputs) at $(date)" | tee "$LOG_FILE" |
|
echo "🔄 Updating all flake inputs..." | tee -a "$LOG_FILE" |
|
|
|
if flake_writable; then |
|
(cd "$NIX_DARWIN_PATH" && nix flake update) 2>&1 | tee -a "$LOG_FILE" |
|
else |
|
echo "No write access to flake; using sudo for update" | tee -a "$LOG_FILE" |
|
(cd "$NIX_DARWIN_PATH" && sudo -H nix flake update) 2>&1 | tee -a "$LOG_FILE" |
|
fi |
|
UPDATE_EXIT=${PIPESTATUS[0]} |
|
|
|
# Commit updated lockfile/config |
|
commit_flake |
|
|
|
echo "======================================================" | tee -a "$LOG_FILE" |
|
echo "🔄 Rebuilding system..." | tee -a "$LOG_FILE" |
|
sudo -H nix run nix-darwin/master#darwin-rebuild -- switch --impure --flake "path:$NIX_DARWIN_PATH#$CONFIGURATION" --show-trace 2>&1 | tee -a "$LOG_FILE" |
|
REBUILD_EXIT=${PIPESTATUS[0]} |
|
rm -f "$REBUILD_FLAG" |
|
|
|
echo "======================================================" | tee -a "$LOG_FILE" |
|
if [[ $REBUILD_EXIT -eq 0 ]]; then |
|
echo "success" > "$ERROR_STATUS_CACHE" |
|
if [[ $UPDATE_EXIT -eq 0 ]]; then |
|
notify "Nix Darwin Manager" "Update + rebuild completed" "Glass" |
|
echo "✅ Update + rebuild completed!" | tee -a "$LOG_FILE" |
|
else |
|
notify "Nix Darwin Manager" "Update failed, rebuild completed" |
|
echo "⚠️ Update failed, rebuild completed" | tee -a "$LOG_FILE" |
|
fi |
|
else |
|
echo "error" > "$ERROR_STATUS_CACHE" |
|
notify "Nix Darwin Manager" "Update + rebuild failed - check logs" "Basso" |
|
echo "❌ Update + rebuild failed!" | tee -a "$LOG_FILE" |
|
fi |
|
|
|
elif [[ "$1" == "collect-garbage" ]]; then |
|
DAYS=${2:-7} # Default to 7 days if not specified |
|
|
|
# Validate input |
|
if [[ "$DAYS" != "all" ]] && ! [[ "$DAYS" =~ ^[0-9]+$ ]]; then |
|
notify "Nix Darwin Manager" "Invalid days value: $DAYS" "Basso" |
|
exit 1 |
|
fi |
|
|
|
# Confirm destructive operation for "all" |
|
if [[ "$DAYS" == "all" ]]; then |
|
if ! confirm "This will delete ALL old nix store paths. Continue?" "Delete All"; then |
|
echo "Garbage collection cancelled" |
|
exit 0 |
|
fi |
|
fi |
|
|
|
echo "Starting nix garbage collection (${DAYS} days) at $(date)" | tee "$LOG_FILE" |
|
echo "🗑️ Cleaning up old nix store paths..." |
|
echo "======================================================" |
|
|
|
# Get store size before cleanup |
|
BEFORE_SIZE=$(/usr/bin/du -sh /nix/store 2>/dev/null | /usr/bin/cut -f1) |
|
echo "Store size before cleanup: $BEFORE_SIZE" |
|
|
|
# Run garbage collection |
|
if [[ "$DAYS" == "all" ]]; then |
|
sudo nix-collect-garbage -d 2>&1 | tee -a "$LOG_FILE" |
|
else |
|
sudo nix-collect-garbage --delete-older-than "${DAYS}d" 2>&1 | tee -a "$LOG_FILE" |
|
fi |
|
EXIT_CODE=${PIPESTATUS[0]} |
|
|
|
# Get store size after cleanup and update cache |
|
AFTER_SIZE=$(/usr/bin/du -sh /nix/store 2>/dev/null | /usr/bin/cut -f1) |
|
echo "$AFTER_SIZE" > "$STORE_SIZE_CACHE" |
|
|
|
echo "======================================================" |
|
if [[ $EXIT_CODE -eq 0 ]]; then |
|
echo "Garbage collection completed successfully at $(date)" | tee -a "$LOG_FILE" |
|
echo "Store size after cleanup: $AFTER_SIZE" |
|
notify "Nix Darwin Manager" "Cleaned up nix store: $BEFORE_SIZE → $AFTER_SIZE" "Glass" |
|
echo "✅ Garbage collection completed! $BEFORE_SIZE → $AFTER_SIZE" |
|
else |
|
echo "Garbage collection failed at $(date)" | tee -a "$LOG_FILE" |
|
notify "Nix Darwin Manager" "Garbage collection failed - check logs" "Basso" |
|
echo "❌ Garbage collection failed! Check logs for details." |
|
fi |
|
|
|
elif [[ "$1" == "show-logs" ]]; then |
|
LATEST_LOG=$(ls -t "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null | head -1) |
|
if [[ -n "$LATEST_LOG" ]]; then |
|
echo "=== Latest Nix Darwin Log: $(basename "$LATEST_LOG") ===" |
|
tail -50 "$LATEST_LOG" |
|
else |
|
echo "No nix-darwin logs found" |
|
fi |
|
exit 0 |
|
|
|
elif [[ "$1" == "open-latest-log" ]]; then |
|
LATEST_LOG=$(ls -t "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null | head -1) |
|
if [[ -n "$LATEST_LOG" ]]; then |
|
code "$LATEST_LOG" |
|
else |
|
notify "Nix Darwin Manager" "No nix-darwin logs found" |
|
fi |
|
exit 0 |
|
|
|
elif [[ "$1" == "clear-logs" ]]; then |
|
LOG_COUNT=$(ls -1 "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null | wc -l | tr -d ' ') |
|
|
|
if [[ "$LOG_COUNT" -gt 0 ]]; then |
|
if confirm "Delete all $LOG_COUNT log file(s)?" "Delete"; then |
|
rm -f "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null || true |
|
rm -f "$ERROR_STATUS_CACHE" 2>/dev/null || true |
|
notify "Nix Darwin Manager" "Cleared $LOG_COUNT nix-darwin log(s)" "Glass" |
|
fi |
|
else |
|
notify "Nix Darwin Manager" "No nix-darwin logs to clear" |
|
fi |
|
exit 0 |
|
fi |
|
|
|
# ============================================================================ |
|
# AUTO-CLEANUP OLD LOGS ON LOAD |
|
# ============================================================================ |
|
|
|
cleanup_old_logs "${SCRIPT_DIR}/.logs" "$LOG_RETENTION_DAYS" "$MAX_LOG_FILES" "nix-darwin-*.log" |
|
|
|
# ============================================================================ |
|
# DEPENDENCY CHECK |
|
# ============================================================================ |
|
|
|
check_dependencies |
|
|
|
# ============================================================================ |
|
# MENU DISPLAY |
|
# ============================================================================ |
|
|
|
# Check if nix-darwin config exists |
|
if [[ -d "$NIX_DARWIN_PATH" ]]; then |
|
CONFIG_STATUS="🟢" |
|
CONFIG_TEXT="Config Found" |
|
else |
|
CONFIG_STATUS="🔴" |
|
CONFIG_TEXT="No Config" |
|
fi |
|
|
|
# Check if we can run nix commands and current status |
|
if command -v nix >/dev/null 2>&1; then |
|
# Check if rebuild is currently in progress |
|
if [[ -f "$REBUILD_FLAG" ]]; then |
|
# Try to get current stage from log |
|
LATEST_LOG=$(ls -t "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null | head -1) |
|
CURRENT_STAGE=$(tail -1 "$LATEST_LOG" 2>/dev/null | grep -oE "(building|setting up|reloading|configuring)" || echo "processing") |
|
NIX_ICON="⏳" |
|
NIX_TEXT="Building ($CURRENT_STAGE)" |
|
else |
|
# Check latest log for errors with cached status |
|
LATEST_LOG=$(ls -t "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null | head -1) |
|
STATUS=$(check_rebuild_status "$LATEST_LOG") |
|
|
|
if [[ "$STATUS" == "error" ]]; then |
|
NIX_ICON="🕸️" |
|
NIX_TEXT="Last build failed" |
|
else |
|
NIX_ICON="❄️" |
|
NIX_TEXT="Ready" |
|
fi |
|
fi |
|
else |
|
NIX_ICON="➖" |
|
NIX_TEXT="Nix not found" |
|
fi |
|
|
|
# Display menu bar icon and status |
|
echo "$NIX_ICON" |
|
echo "---" |
|
echo "$CONFIG_STATUS $CONFIG_TEXT" |
|
if [[ -n "$NIX_TEXT" ]]; then |
|
echo "Status: $NIX_TEXT | color=#666666" |
|
fi |
|
|
|
# Show last error if rebuild failed |
|
if [[ "$STATUS" == "error" ]] && [[ -n "$LATEST_LOG" ]]; then |
|
LAST_ERROR=$(get_last_error "$LATEST_LOG") |
|
if [[ -n "$LAST_ERROR" ]]; then |
|
echo "---" |
|
echo "Last Error: | color=#ff0000" |
|
echo "--${LAST_ERROR} | color=#ff0000 font=Monaco" |
|
fi |
|
fi |
|
|
|
echo "---" |
|
echo "Open Config in VS Code | bash='$0' param1=open-config terminal=false refresh=true" |
|
|
|
# Show cancel option if rebuild in progress |
|
if [[ -f "$REBUILD_FLAG" ]]; then |
|
echo "Cancel Rebuild | bash='$0' param1=cancel-rebuild terminal=false refresh=true color=#ff0000" |
|
else |
|
echo "Rebuild System | bash='$0' param1=rebuild terminal=false refresh=true" |
|
fi |
|
|
|
echo "Update + Rebuild | bash='$0' param1=update-rebuild terminal=false refresh=true" |
|
echo "Collect Garbage (7 days) | bash='$0' param1=collect-garbage terminal=true refresh=true" |
|
echo "Garbage Collection Options" |
|
echo "--Quick (3 days) | bash='$0' param1=collect-garbage param2=3 terminal=true refresh=true" |
|
echo "--Standard (7 days) | bash='$0' param1=collect-garbage param2=7 terminal=true refresh=true" |
|
echo "--Conservative (30 days) | bash='$0' param1=collect-garbage param2=30 terminal=true refresh=true" |
|
echo "--Nuclear (all old) ⚠️ | bash='$0' param1=collect-garbage param2=all terminal=true refresh=true color=#ff6b35" |
|
echo "Show Recent Logs | bash='$0' param1=show-logs terminal=true" |
|
echo "Open Latest Log | bash='$0' param1=open-latest-log terminal=false refresh=true" |
|
echo "---" |
|
echo "Config Path: $NIX_DARWIN_PATH | color=#666666" |
|
|
|
# Display store size with visual warning for large sizes |
|
STORE_SIZE=$(get_store_size) |
|
if [[ -z "$STORE_SIZE" || "$STORE_SIZE" == "Calculating..." ]]; then |
|
echo "Store Size: Calculating... | color=#666666" |
|
elif [[ "$STORE_SIZE" == "-" ]]; then |
|
echo "Store Size: Nix not installed | color=#666666" |
|
elif [[ "$STORE_SIZE" =~ ^[0-9.]+G$ ]] && (( $(echo "${STORE_SIZE%G} > 20" | bc -l 2>/dev/null || echo "0") )); then |
|
echo "Store Size: $STORE_SIZE ⚠️ | color=#ff6b35" |
|
else |
|
echo "Store Size: $STORE_SIZE | color=#666666" |
|
fi |
|
|
|
LATEST_LOG=$(ls -t "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null | head -1) |
|
if [[ -n "$LATEST_LOG" ]]; then |
|
# Try GNU stat, fallback to BSD stat for timestamp display |
|
LAST_MOD=$(stat -c "%y" "$LATEST_LOG" 2>/dev/null || stat -f "%Sm" -t "%Y-%m-%d %H:%M" "$LATEST_LOG" 2>/dev/null) |
|
LAST_MOD=$(echo "$LAST_MOD" | cut -d'.' -f1 | sed 's/ /T/' | cut -d'T' -f1-2 | tr 'T' ' ') |
|
echo "Last Log: $LAST_MOD | color=#666666" |
|
LOG_COUNT=$(ls -1 "${SCRIPT_DIR}"/.logs/nix-darwin-*.log 2>/dev/null | wc -l | tr -d ' ') |
|
# Calculate total log file size |
|
LOG_BYTES=$(find "${SCRIPT_DIR}/.logs" -type f -name 'nix-darwin-*.log' -exec stat -c "%s" {} + 2>/dev/null | awk '{s+=$1} END {print s+0}') |
|
if [[ -z "$LOG_BYTES" || "$LOG_BYTES" == "0" ]]; then |
|
# Fallback to BSD stat |
|
LOG_BYTES=$(find "${SCRIPT_DIR}/.logs" -type f -name 'nix-darwin-*.log' -exec stat -f "%z" {} + 2>/dev/null | awk '{s+=$1} END {print s+0}') |
|
fi |
|
LOG_SIZE=$(human_readable_size "$LOG_BYTES") |
|
echo "Log Count: ${LOG_COUNT} files • ${LOG_SIZE} | color=#666666" |
|
echo "Clear Logs | bash='$0' param1=clear-logs terminal=false refresh=true" |
|
fi |