Commit a65354fb1fab
Changed files (1)
tools
tools/nix-store-analyzer.sh
@@ -22,31 +22,31 @@ NC='\033[0m' # No Color
# Configuration
TARGET="${1:-}"
-MIN_SIZE_MB=100 # Only show packages larger than this
-TOP_N=30 # Show top N largest packages
+MIN_SIZE_MB=100 # Only show packages larger than this
+TOP_N=30 # Show top N largest packages
# Determine if remote or local
if [ -n "$TARGET" ]; then
- SSH_PREFIX="ssh $TARGET"
- HOSTNAME="$TARGET"
+ SSH_PREFIX="ssh $TARGET"
+ HOSTNAME="$TARGET"
else
- SSH_PREFIX=""
- HOSTNAME="$(hostname)"
+ SSH_PREFIX=""
+ HOSTNAME="$(hostname)"
fi
# Helper function to run command (local or remote)
run_cmd() {
- if [ -n "$SSH_PREFIX" ]; then
- # For remote: use bash explicitly to avoid zsh glob issues
- $SSH_PREFIX "bash -c $(printf '%q' "$@")"
- else
- bash -c "$@"
- fi
+ if [ -n "$SSH_PREFIX" ]; then
+ # For remote: use bash explicitly to avoid zsh glob issues
+ $SSH_PREFIX "bash -c $(printf '%q' "$@")"
+ else
+ bash -c "$@"
+ fi
}
# Helper to format sizes
human_size() {
- numfmt --to=iec-i --suffix=B "$1" 2>/dev/null || echo "$1"
+ numfmt --to=iec-i --suffix=B "$1" 2>/dev/null || echo "$1"
}
echo -e "${BOLD}=== Nix Store Analysis for ${CYAN}${HOSTNAME}${NC}${BOLD} ===${NC}"
@@ -70,13 +70,13 @@ echo ""
# Try to list generations (needs root/sudo)
GEN_COUNT=$(run_cmd 'sudo nix-env --list-generations --profile /nix/var/nix/profiles/system 2>/dev/null | wc -l' || echo "0")
if [ "$GEN_COUNT" -gt 0 ]; then
- echo -e "System generations: ${YELLOW}${GEN_COUNT}${NC}"
- echo ""
- run_cmd 'sudo nix-env --list-generations --profile /nix/var/nix/profiles/system 2>/dev/null | tail -5'
+ echo -e "System generations: ${YELLOW}${GEN_COUNT}${NC}"
+ echo ""
+ run_cmd 'sudo nix-env --list-generations --profile /nix/var/nix/profiles/system 2>/dev/null | tail -5'
else
- # Fallback: count boot entries
- BOOT_COUNT=$(run_cmd 'ls -1 /nix/var/nix/profiles/system-*-link 2>/dev/null | wc -l' || echo "0")
- echo -e "System profile links: ${YELLOW}${BOOT_COUNT}${NC} (may need sudo for full generation list)"
+ # Fallback: count boot entries
+ BOOT_COUNT=$(run_cmd 'ls -1 /nix/var/nix/profiles/system-*-link 2>/dev/null | wc -l' || echo "0")
+ echo -e "System profile links: ${YELLOW}${BOOT_COUNT}${NC} (may need sudo for full generation list)"
fi
echo ""
@@ -161,7 +161,7 @@ echo ""
# Check for multiple versions of same tool (excluding .drv files)
echo -e "${YELLOW}Multiple versions of common tools:${NC}"
echo "(Multiple versions are normal - different tools depend on different Go versions)"
-run_cmd 'find /nix/store -maxdepth 1 -type d \( -name "*-helix-*" -o -name "*-difftastic-*" -o -name "*-emacs-[0-9]*" -o -name "*-go-1.*" \) 2>/dev/null |
+run_cmd 'find /nix/store -maxdepth 1 -type d \( -name "*-difftastic-*" -o -name "*-emacs-[0-9]*" -o -name "*-go-1.*" \) 2>/dev/null |
sed "s|/nix/store/[a-z0-9]\{32\}-||" |
sed "s/-x86_64.*//" |
sort -u |
@@ -240,13 +240,13 @@ echo ""
echo -e "${YELLOW}Old channels (>1 year):${NC}"
CUTOFF_DATE=$(date -d "1 year ago" +%s 2>/dev/null || date -v-1y +%s 2>/dev/null || echo "0")
run_cmd "find /nix/var/nix/profiles/per-user/ -name 'channels*' -type l 2>/dev/null" | while read -r link; do
- if [ -n "$link" ]; then
- LINK_DATE=$(run_cmd "stat -c %Y '$link' 2>/dev/null || stat -f %m '$link' 2>/dev/null || echo 0")
- if [ "$LINK_DATE" -lt "$CUTOFF_DATE" ] && [ "$LINK_DATE" -gt 0 ]; then
- AGE=$(run_cmd "stat -c %y '$link' 2>/dev/null | cut -d' ' -f1 || stat -f '%Sm' -t '%Y-%m-%d' '$link' 2>/dev/null")
- echo -e " ${RED}${AGE}: $link${NC}"
- fi
- fi
+ if [ -n "$link" ]; then
+ LINK_DATE=$(run_cmd "stat -c %Y '$link' 2>/dev/null || stat -f %m '$link' 2>/dev/null || echo 0")
+ if [ "$LINK_DATE" -lt "$CUTOFF_DATE" ] && [ "$LINK_DATE" -gt 0 ]; then
+ AGE=$(run_cmd "stat -c %y '$link' 2>/dev/null | cut -d' ' -f1 || stat -f '%Sm' -t '%Y-%m-%d' '$link' 2>/dev/null")
+ echo -e " ${RED}${AGE}: $link${NC}"
+ fi
+ fi
done || echo " None found"
echo ""
@@ -256,15 +256,15 @@ echo "---"
# Check common locations for old symlinks
SUSPICIOUS_PATHS=(
- "/home/*/tmp/system"
- "/home/*/.cache/direnv"
- "/home/*/result"
- "/tmp/nix-build-*"
+ "/home/*/tmp/system"
+ "/home/*/.cache/direnv"
+ "/home/*/result"
+ "/tmp/nix-build-*"
)
for pattern in "${SUSPICIOUS_PATHS[@]}"; do
- echo -e "${YELLOW}Checking: ${pattern}${NC}"
- run_cmd "find $(dirname $pattern 2>/dev/null) -maxdepth 2 -name '$(basename $pattern)' -type l 2>/dev/null | while read -r link; do
+ echo -e "${YELLOW}Checking: ${pattern}${NC}"
+ run_cmd "find $(dirname $pattern 2>/dev/null) -maxdepth 2 -name '$(basename $pattern)' -type l 2>/dev/null | while read -r link; do
if [ -n \"\$link\" ]; then
target=\$(readlink \"\$link\" 2>/dev/null || echo '(broken)')
age=\$(stat -c %y \"\$link\" 2>/dev/null | cut -d' ' -f1 || stat -f '%Sm' -t '%Y-%m-%d' \"\$link\" 2>/dev/null || echo 'unknown')
@@ -292,23 +292,23 @@ echo "---"
# Find old Go versions and trace their roots
echo -e "${YELLOW}Tracing old Go versions:${NC}"
run_cmd 'shopt -s nullglob; ls -d /nix/store/*-go-1.1[0-9]* 2>/dev/null; true' | while read -r pkg; do
- if [ -n "$pkg" ]; then
- name=$(basename "$pkg")
- size=$(run_cmd "du -sh '$pkg' 2>/dev/null | cut -f1" || echo "?")
- echo -e " ${CYAN}${name}${NC} (${size})"
+ if [ -n "$pkg" ]; then
+ name=$(basename "$pkg")
+ size=$(run_cmd "du -sh '$pkg' 2>/dev/null | cut -f1" || echo "?")
+ echo -e " ${CYAN}${name}${NC} (${size})"
- # Find roots
- roots=$(run_cmd "nix-store --query --roots '$pkg' 2>/dev/null | grep -v '^{'" || echo "")
- if [ -n "$roots" ]; then
- echo "$roots" | while IFS=' ' read -r root arrow target; do
- if [ -n "$root" ] && [ "$root" != "{" ]; then
- echo -e " ${RED}└─ $root${NC}"
- fi
- done
- else
- echo -e " ${GREEN}└─ No roots (can be GC'd)${NC}"
- fi
- fi
+ # Find roots
+ roots=$(run_cmd "nix-store --query --roots '$pkg' 2>/dev/null | grep -v '^{'" || echo "")
+ if [ -n "$roots" ]; then
+ echo "$roots" | while IFS=' ' read -r root arrow target; do
+ if [ -n "$root" ] && [ "$root" != "{" ]; then
+ echo -e " ${RED}└─ $root${NC}"
+ fi
+ done
+ else
+ echo -e " ${GREEN}└─ No roots (can be GC'd)${NC}"
+ fi
+ fi
done
echo ""
@@ -319,37 +319,37 @@ echo "Scanning common development directories for 'result' links..."
echo ""
DEV_DIRS=(
- "/home/*/src"
- "/home/*/projects"
- "/home/*/code"
- "/home/*/work"
- "/home/*/dev"
+ "/home/*/src"
+ "/home/*/projects"
+ "/home/*/code"
+ "/home/*/work"
+ "/home/*/dev"
)
RESULT_COUNT=0
RESULT_SIZE=0
for dir_pattern in "${DEV_DIRS[@]}"; do
- run_cmd "find $(dirname $dir_pattern 2>/dev/null)/* -maxdepth 3 -name 'result' -o -name 'result-*' 2>/dev/null" | while read -r link; do
- if [ -L "$link" ]; then
- target=$(run_cmd "readlink '$link' 2>/dev/null" || echo "(broken)")
- age=$(run_cmd "stat -c %y '$link' 2>/dev/null | cut -d' ' -f1" || echo "unknown")
- size=$(run_cmd "du -sh '$link' 2>/dev/null | cut -f1" || echo "?")
+ run_cmd "find $(dirname $dir_pattern 2>/dev/null)/* -maxdepth 3 -name 'result' -o -name 'result-*' 2>/dev/null" | while read -r link; do
+ if [ -L "$link" ]; then
+ target=$(run_cmd "readlink '$link' 2>/dev/null" || echo "(broken)")
+ age=$(run_cmd "stat -c %y '$link' 2>/dev/null | cut -d' ' -f1" || echo "unknown")
+ size=$(run_cmd "du -sh '$link' 2>/dev/null | cut -f1" || echo "?")
- if [[ "$target" == /nix/store/* ]]; then
- echo -e " ${YELLOW}$age${NC} [$size]: $link"
- RESULT_COUNT=$((RESULT_COUNT + 1))
- fi
- fi
- done
+ if [[ "$target" == /nix/store/* ]]; then
+ echo -e " ${YELLOW}$age${NC} [$size]: $link"
+ RESULT_COUNT=$((RESULT_COUNT + 1))
+ fi
+ fi
+ done
done
if [ "$RESULT_COUNT" -eq 0 ]; then
- echo -e " ${GREEN}✓ No result symlinks found${NC}"
+ echo -e " ${GREEN}✓ No result symlinks found${NC}"
else
- echo ""
- echo -e "${YELLOW}Found $RESULT_COUNT result symlink(s)${NC}"
- echo "These prevent garbage collection. Remove with: rm result*"
+ echo ""
+ echo -e "${YELLOW}Found $RESULT_COUNT result symlink(s)${NC}"
+ echo "These prevent garbage collection. Remove with: rm result*"
fi
echo ""
@@ -378,13 +378,13 @@ done
"' || echo "")
if [ -n "$BROKEN_LINKS" ]; then
- echo "$BROKEN_LINKS" | while IFS=: read -r prefix link target; do
- if [ "$prefix" = "BROKEN" ]; then
- echo -e " ${RED}✗${NC} $link -> $target"
- fi
- done
+ echo "$BROKEN_LINKS" | while IFS=: read -r prefix link target; do
+ if [ "$prefix" = "BROKEN" ]; then
+ echo -e " ${RED}✗${NC} $link -> $target"
+ fi
+ done
else
- echo -e " ${GREEN}✓ No broken symlinks found in GC roots${NC}"
+ echo -e " ${GREEN}✓ No broken symlinks found in GC roots${NC}"
fi
echo ""
@@ -395,32 +395,32 @@ echo "---"
HM_PROFILE_DIRS=$(run_cmd "find /nix/var/nix/profiles/per-user -name 'home-manager*' -type l 2>/dev/null | sed 's/-[0-9]*-link$//' | sort -u" || echo "")
if [ -n "$HM_PROFILE_DIRS" ]; then
- echo "$HM_PROFILE_DIRS" | while read -r profile_base; do
- user=$(basename $(dirname "$profile_base"))
- gen_count=$(run_cmd "ls -1 ${profile_base}-*-link 2>/dev/null | wc -l" || echo "0")
+ echo "$HM_PROFILE_DIRS" | while read -r profile_base; do
+ user=$(basename $(dirname "$profile_base"))
+ gen_count=$(run_cmd "ls -1 ${profile_base}-*-link 2>/dev/null | wc -l" || echo "0")
- if [ "$gen_count" -gt 0 ]; then
- echo -e "${YELLOW}User $user:${NC} $gen_count generation(s)"
+ if [ "$gen_count" -gt 0 ]; then
+ echo -e "${YELLOW}User $user:${NC} $gen_count generation(s)"
- # Show oldest and newest
- oldest=$(run_cmd "ls -lt ${profile_base}-*-link 2>/dev/null | tail -1" || echo "")
- newest=$(run_cmd "ls -lt ${profile_base}-*-link 2>/dev/null | head -1" || echo "")
+ # Show oldest and newest
+ oldest=$(run_cmd "ls -lt ${profile_base}-*-link 2>/dev/null | tail -1" || echo "")
+ newest=$(run_cmd "ls -lt ${profile_base}-*-link 2>/dev/null | head -1" || echo "")
- if [ -n "$oldest" ]; then
- oldest_date=$(echo "$oldest" | awk '{print $6, $7, $8}')
- echo " Oldest: $oldest_date"
- fi
- fi
- done
+ if [ -n "$oldest" ]; then
+ oldest_date=$(echo "$oldest" | awk '{print $6, $7, $8}')
+ echo " Oldest: $oldest_date"
+ fi
+ fi
+ done
else
- # Check alternative location
- HM_STATE=$(run_cmd "find /home -path '*/.local/state/nix/profiles/home-manager*' -type l 2>/dev/null | head -1" || echo "")
- if [ -n "$HM_STATE" ]; then
- gen_count=$(run_cmd "ls -1 $(dirname $HM_STATE)/home-manager-*-link 2>/dev/null | wc -l" || echo "0")
- echo -e "${YELLOW}Found $gen_count home-manager generation(s)${NC}"
- else
- echo " No home-manager generations found"
- fi
+ # Check alternative location
+ HM_STATE=$(run_cmd "find /home -path '*/.local/state/nix/profiles/home-manager*' -type l 2>/dev/null | head -1" || echo "")
+ if [ -n "$HM_STATE" ]; then
+ gen_count=$(run_cmd "ls -1 $(dirname $HM_STATE)/home-manager-*-link 2>/dev/null | wc -l" || echo "0")
+ echo -e "${YELLOW}Found $gen_count home-manager generation(s)${NC}"
+ else
+ echo " No home-manager generations found"
+ fi
fi
echo ""
@@ -438,8 +438,8 @@ STORE_SIZE_HUMAN=$(run_cmd "timeout 30 du -sh /nix/store 2>/dev/null | cut -f1"
STORE_SIZE_HUMAN=${STORE_SIZE_HUMAN:-unknown}
# If bytes calculation failed/timed out, estimate from human-readable size
if [ "$STORE_SIZE_BYTES" = "0" ] && [ "$STORE_SIZE_HUMAN" != "unknown" ]; then
- # Convert human-readable (e.g., "6.9G") to bytes estimate
- STORE_SIZE_BYTES=$(echo "$STORE_SIZE_HUMAN" | awk '{
+ # Convert human-readable (e.g., "6.9G") to bytes estimate
+ STORE_SIZE_BYTES=$(echo "$STORE_SIZE_HUMAN" | awk '{
val=$1; unit=substr($0, length($0));
if (unit=="T") print int(val * 1024 * 1024 * 1024 * 1024);
else if (unit=="G") print int(val * 1024 * 1024 * 1024);
@@ -453,24 +453,24 @@ SAMPLE_SIZE=100
SINGLE_LINK_COUNT=$(run_cmd "find /nix/store -type f 2>/dev/null | head -$SAMPLE_SIZE | xargs stat -c %h 2>/dev/null | grep -c '^1$'" || echo "0")
# Trim whitespace and newlines
SINGLE_LINK_COUNT=$(echo "$SINGLE_LINK_COUNT" | tr -d '\n\r ' | head -c 10)
-SINGLE_LINK_COUNT=${SINGLE_LINK_COUNT:-0} # Default to 0 if empty
+SINGLE_LINK_COUNT=${SINGLE_LINK_COUNT:-0} # Default to 0 if empty
if [ "$SINGLE_LINK_COUNT" -gt 50 ] 2>/dev/null; then
- OPTIMIZATION_POTENTIAL="High"
- echo -e " ${YELLOW}⚠ Optimization status: Not optimized${NC}"
- echo " Store size: $STORE_SIZE_HUMAN"
- echo " Sample check: $SINGLE_LINK_COUNT/$SAMPLE_SIZE files have single links"
- echo ""
- echo -e " ${CYAN}Run 'nix-store --optimize' to deduplicate identical files${NC}"
- echo " Potential savings: 5-20% of store size (~$(echo "$STORE_SIZE_BYTES * 0.10 / 1024 / 1024 / 1024" | bc 2>/dev/null || echo "?")GB estimated)"
+ OPTIMIZATION_POTENTIAL="High"
+ echo -e " ${YELLOW}⚠ Optimization status: Not optimized${NC}"
+ echo " Store size: $STORE_SIZE_HUMAN"
+ echo " Sample check: $SINGLE_LINK_COUNT/$SAMPLE_SIZE files have single links"
+ echo ""
+ echo -e " ${CYAN}Run 'nix-store --optimize' to deduplicate identical files${NC}"
+ echo " Potential savings: 5-20% of store size (~$(echo "$STORE_SIZE_BYTES * 0.10 / 1024 / 1024 / 1024" | bc 2>/dev/null || echo "?")GB estimated)"
elif [ "$SINGLE_LINK_COUNT" -gt 20 ] 2>/dev/null; then
- echo -e " ${YELLOW}Optimization status: Partially optimized${NC}"
- echo " Store size: $STORE_SIZE_HUMAN"
- echo " Some optimization possible"
+ echo -e " ${YELLOW}Optimization status: Partially optimized${NC}"
+ echo " Store size: $STORE_SIZE_HUMAN"
+ echo " Some optimization possible"
else
- echo -e " ${GREEN}✓ Optimization status: Well optimized${NC}"
- echo " Store size: $STORE_SIZE_HUMAN"
- echo " Most files are already deduplicated"
+ echo -e " ${GREEN}✓ Optimization status: Well optimized${NC}"
+ echo " Store size: $STORE_SIZE_HUMAN"
+ echo " Most files are already deduplicated"
fi
echo ""
@@ -485,10 +485,10 @@ echo "Database size: $DB_SIZE"
# Warn if database is >1GB
if [ "$DB_SIZE_BYTES" -gt 1073741824 ] 2>/dev/null; then
- echo -e "${YELLOW}⚠ Database is large (>1GB)${NC}"
- echo " Consider running: nix-store --verify --check-contents"
+ echo -e "${YELLOW}⚠ Database is large (>1GB)${NC}"
+ echo " Consider running: nix-store --verify --check-contents"
else
- echo -e "${GREEN}✓ Database size is healthy${NC}"
+ echo -e "${GREEN}✓ Database size is healthy${NC}"
fi
echo ""
@@ -497,20 +497,20 @@ echo -e "${BOLD}${BLUE}13. Nix Cache Size${NC}"
echo "---"
CACHE_LOCATIONS=(
- "/home/*/.cache/nix"
- "/root/.cache/nix"
+ "/home/*/.cache/nix"
+ "/root/.cache/nix"
)
TOTAL_CACHE_SIZE=0
for cache_pattern in "${CACHE_LOCATIONS[@]}"; do
- # Find nix cache directories - use || true to avoid pipefail issues
- run_cmd "shopt -s nullglob; find $(dirname $cache_pattern 2>/dev/null)/* -maxdepth 2 -type d -name nix 2>/dev/null; true" | while read -r cache_dir; do
- if [ -n "$cache_dir" ] && [ -d "$cache_dir" ]; then
- size=$(run_cmd "du -sh '$cache_dir' 2>/dev/null | cut -f1" || echo "0")
- user=$(echo "$cache_dir" | cut -d'/' -f3)
- echo " $user: $size ($cache_dir)"
- fi
- done
+ # Find nix cache directories - use || true to avoid pipefail issues
+ run_cmd "shopt -s nullglob; find $(dirname $cache_pattern 2>/dev/null)/* -maxdepth 2 -type d -name nix 2>/dev/null; true" | while read -r cache_dir; do
+ if [ -n "$cache_dir" ] && [ -d "$cache_dir" ]; then
+ size=$(run_cmd "du -sh '$cache_dir' 2>/dev/null | cut -f1" || echo "0")
+ user=$(echo "$cache_dir" | cut -d'/' -f3)
+ echo " $user: $size ($cache_dir)"
+ fi
+ done
done
echo ""
@@ -524,34 +524,34 @@ HAS_NIX_DU=0
command -v nix-du >/dev/null 2>&1 && HAS_NIX_DU=1 || true
if [ "$HAS_NIX_DU" -eq 1 ]; then
- echo "Using nix-du for detailed analysis (packages >50MB)..."
- echo ""
+ echo "Using nix-du for detailed analysis (packages >50MB)..."
+ echo ""
- # Use nix-du with size filter to make it faster, extract text summary
- run_cmd "timeout 60 nix-du -s=50M 2>/dev/null" | head -100 || echo " (nix-du timed out or unavailable)"
+ # Use nix-du with size filter to make it faster, extract text summary
+ run_cmd "timeout 60 nix-du -s=50M 2>/dev/null" | head -100 || echo " (nix-du timed out or unavailable)"
- echo ""
- echo "For full visualization: nix-du | dot -Tsvg > /tmp/store-analysis.svg"
- echo ""
- echo "Basic estimation for comparison:"
- echo ""
+ echo ""
+ echo "For full visualization: nix-du | dot -Tsvg > /tmp/store-analysis.svg"
+ echo ""
+ echo "Basic estimation for comparison:"
+ echo ""
fi
# Always show basic estimation too
if [ "$HAS_NIX_DU" -eq 0 ]; then
- echo "nix-du not found (install with: nix-shell -p nix-du)"
- echo ""
+ echo "nix-du not found (install with: nix-shell -p nix-du)"
+ echo ""
fi
# Basic estimation: total store - current system closure
# Reuse STORE_SIZE_BYTES from section 11 to avoid slow du command
CURRENT_CLOSURE=$(run_cmd "timeout 30 nix path-info -rS /run/current-system 2>/dev/null | tail -1 | awk '{print \$2}'" || true)
CURRENT_CLOSURE=${CURRENT_CLOSURE:-0}
-STORE_SIZE=${STORE_SIZE_BYTES:-0} # Already calculated in section 11, default to 0 if empty
+STORE_SIZE=${STORE_SIZE_BYTES:-0} # Already calculated in section 11, default to 0 if empty
# If STORE_SIZE is still 0, recalculate from section 11's human-readable value
if [ "$STORE_SIZE" = "0" ] && [ -n "$STORE_SIZE_HUMAN" ] && [ "$STORE_SIZE_HUMAN" != "unknown" ]; then
- # Convert human-readable (e.g., "117G") to bytes estimate
- STORE_SIZE=$(echo "$STORE_SIZE_HUMAN" | sed 's/G$//' | awk '{print int($1 * 1024 * 1024 * 1024)}')
+ # Convert human-readable (e.g., "117G") to bytes estimate
+ STORE_SIZE=$(echo "$STORE_SIZE_HUMAN" | sed 's/G$//' | awk '{print int($1 * 1024 * 1024 * 1024)}')
fi
# Clean values
@@ -561,21 +561,21 @@ STORE_SIZE=${STORE_SIZE:-0}
CURRENT_CLOSURE=${CURRENT_CLOSURE:-0}
if [ "$STORE_SIZE" -gt 0 ] 2>/dev/null && [ "$CURRENT_CLOSURE" -gt 0 ] 2>/dev/null; then
- RECLAIMABLE=$((STORE_SIZE - CURRENT_CLOSURE))
- RECLAIMABLE_GB=$(awk "BEGIN {printf \"%.1f\", $RECLAIMABLE / 1024 / 1024 / 1024}")
- STORE_GB=$(awk "BEGIN {printf \"%.1f\", $STORE_SIZE / 1024 / 1024 / 1024}")
- CLOSURE_GB=$(awk "BEGIN {printf \"%.1f\", $CURRENT_CLOSURE / 1024 / 1024 / 1024}")
+ RECLAIMABLE=$((STORE_SIZE - CURRENT_CLOSURE))
+ RECLAIMABLE_GB=$(awk "BEGIN {printf \"%.1f\", $RECLAIMABLE / 1024 / 1024 / 1024}")
+ STORE_GB=$(awk "BEGIN {printf \"%.1f\", $STORE_SIZE / 1024 / 1024 / 1024}")
+ CLOSURE_GB=$(awk "BEGIN {printf \"%.1f\", $CURRENT_CLOSURE / 1024 / 1024 / 1024}")
- echo -e " Store size: ${YELLOW}${STORE_GB}GB${NC}"
- echo -e " Current system: ${CYAN}${CLOSURE_GB}GB${NC}"
- echo -e " Potentially reclaimable: ${GREEN}~${RECLAIMABLE_GB}GB${NC}"
- echo ""
- echo " Note: This is a rough estimate. Running GC may reclaim less."
- if [ "$HAS_NIX_DU" -eq 0 ]; then
- echo " Install nix-du for accurate analysis: nix-shell -p nix-du"
- fi
+ echo -e " Store size: ${YELLOW}${STORE_GB}GB${NC}"
+ echo -e " Current system: ${CYAN}${CLOSURE_GB}GB${NC}"
+ echo -e " Potentially reclaimable: ${GREEN}~${RECLAIMABLE_GB}GB${NC}"
+ echo ""
+ echo " Note: This is a rough estimate. Running GC may reclaim less."
+ if [ "$HAS_NIX_DU" -eq 0 ]; then
+ echo " Install nix-du for accurate analysis: nix-shell -p nix-du"
+ fi
else
- echo " Unable to calculate (missing nix path-info)"
+ echo " Unable to calculate (missing nix path-info)"
fi
echo ""
@@ -585,7 +585,7 @@ echo "---"
CLEANUP_SCRIPT="/tmp/nix-cleanup-${HOSTNAME//[^a-zA-Z0-9]/_}.sh"
-cat > "$CLEANUP_SCRIPT" << 'EOF'
+cat >"$CLEANUP_SCRIPT" <<'EOF'
#!/usr/bin/env bash
# Auto-generated Nix cleanup script
set -euo pipefail
@@ -604,8 +604,8 @@ EOF
# Add cleanup for old channels
OLD_CHANNELS=$(run_cmd "find /nix/var/nix/profiles/per-user/ -name 'channels*' -type l -mtime +365 2>/dev/null" || echo "")
if [ -n "$OLD_CHANNELS" ]; then
- echo -e "${YELLOW}▸ Found old channel links (>1 year)${NC}"
- cat >> "$CLEANUP_SCRIPT" << EOF
+ echo -e "${YELLOW}▸ Found old channel links (>1 year)${NC}"
+ cat >>"$CLEANUP_SCRIPT" <<EOF
# Remove old channels (>1 year)
echo "Removing old channels..."
$(echo "$OLD_CHANNELS" | while read -r link; do echo "rm -f '$link'"; done)
@@ -617,8 +617,8 @@ fi
# Add cleanup for old tmp/system links
OLD_SYSTEM=$(run_cmd "find /home/*/tmp -name 'system' -type l -mtime +30 2>/dev/null" || echo "")
if [ -n "$OLD_SYSTEM" ]; then
- echo -e "${YELLOW}▸ Found old system symlinks in ~/tmp${NC}"
- cat >> "$CLEANUP_SCRIPT" << EOF
+ echo -e "${YELLOW}▸ Found old system symlinks in ~/tmp${NC}"
+ cat >>"$CLEANUP_SCRIPT" <<EOF
# Remove old system symlinks
echo "Removing old system symlinks..."
$(echo "$OLD_SYSTEM" | while read -r link; do echo "rm -f '$link'"; done)
@@ -630,8 +630,8 @@ fi
# Add cleanup for direnv cache
DIRENV_CACHE=$(run_cmd "shopt -s nullglob; find /home/*/.cache/direnv -type d -maxdepth 1 2>/dev/null | head -1; true" || echo "")
if [ -n "$DIRENV_CACHE" ]; then
- echo -e "${YELLOW}▸ Found direnv cache${NC}"
- cat >> "$CLEANUP_SCRIPT" << EOF
+ echo -e "${YELLOW}▸ Found direnv cache${NC}"
+ cat >>"$CLEANUP_SCRIPT" <<EOF
# Clean direnv cache
echo "Cleaning direnv cache..."
rm -rf /home/*/.cache/direnv
@@ -643,8 +643,8 @@ fi
# Add cleanup for old profiles
OLD_PROFILES=$(run_cmd "shopt -s nullglob; find /nix/var/nix/profiles/per-user/*/profile-* -type l -mtime +90 2>/dev/null; true" || echo "")
if [ -n "$OLD_PROFILES" ]; then
- echo -e "${YELLOW}▸ Found old profile links (>90 days)${NC}"
- cat >> "$CLEANUP_SCRIPT" << EOF
+ echo -e "${YELLOW}▸ Found old profile links (>90 days)${NC}"
+ cat >>"$CLEANUP_SCRIPT" <<EOF
# Remove old profile generations
echo "Removing old profile generations..."
$(echo "$OLD_PROFILES" | while read -r link; do echo "rm -f '$link'"; done)
@@ -656,8 +656,8 @@ fi
# Add cleanup for result symlinks
RESULT_LINKS=$(run_cmd "shopt -s nullglob; find /home/*/src /home/*/projects /home/*/code /home/*/work /home/*/dev -maxdepth 3 -name 'result' -o -name 'result-*' 2>/dev/null | head -20; true" || echo "")
if [ -n "$RESULT_LINKS" ]; then
- echo -e "${YELLOW}▸ Found result symlinks in development directories${NC}"
- cat >> "$CLEANUP_SCRIPT" << EOF
+ echo -e "${YELLOW}▸ Found result symlinks in development directories${NC}"
+ cat >>"$CLEANUP_SCRIPT" <<EOF
# Remove result symlinks
echo "Removing result symlinks..."
$(echo "$RESULT_LINKS" | while read -r link; do echo "rm -f '$link'"; done)
@@ -669,8 +669,8 @@ fi
# Add cleanup for broken symlinks
BROKEN_LINKS=$(run_cmd "find /nix/var/nix/gcroots /home -type l 2>/dev/null | while read link; do test -e \"\$link\" || echo \"\$link\"; done | head -10" || echo "")
if [ -n "$BROKEN_LINKS" ]; then
- echo -e "${YELLOW}▸ Found broken symlinks${NC}"
- cat >> "$CLEANUP_SCRIPT" << EOF
+ echo -e "${YELLOW}▸ Found broken symlinks${NC}"
+ cat >>"$CLEANUP_SCRIPT" <<EOF
# Remove broken symlinks
echo "Removing broken symlinks..."
$(echo "$BROKEN_LINKS" | while read -r link; do echo "rm -f '$link'"; done)
@@ -680,7 +680,7 @@ EOF
fi
# Always add GC commands
-cat >> "$CLEANUP_SCRIPT" << 'EOF'
+cat >>"$CLEANUP_SCRIPT" <<'EOF'
# Run garbage collection
if [ "$CLEANED" -eq 1 ]; then
echo ""
@@ -716,10 +716,10 @@ echo -e "${GREEN}✓ Generated cleanup script: ${CLEANUP_SCRIPT}${NC}"
echo ""
echo "Review and run with:"
if [ -n "$TARGET" ]; then
- echo -e " ${CYAN}scp $CLEANUP_SCRIPT $TARGET:/tmp/${NC}"
- echo -e " ${CYAN}ssh $TARGET 'sudo bash /tmp/$(basename $CLEANUP_SCRIPT)'${NC}"
+ echo -e " ${CYAN}scp $CLEANUP_SCRIPT $TARGET:/tmp/${NC}"
+ echo -e " ${CYAN}ssh $TARGET 'sudo bash /tmp/$(basename $CLEANUP_SCRIPT)'${NC}"
else
- echo -e " ${CYAN}sudo $CLEANUP_SCRIPT${NC}"
+ echo -e " ${CYAN}sudo $CLEANUP_SCRIPT${NC}"
fi
echo ""
@@ -728,7 +728,7 @@ echo -e "${BOLD}${BLUE}16. Summary${NC}"
echo "---"
DISK_PCT=$(run_cmd "df / | tail -1 | awk '{print \$5}'" | tr -d '%')
-DISK_PCT=${DISK_PCT:-0} # Default to 0 if empty
+DISK_PCT=${DISK_PCT:-0} # Default to 0 if empty
STORE_SIZE=$(run_cmd "du -sh /nix/store 2>/dev/null | cut -f1" || echo "unknown")
echo -e "Hostname: ${CYAN}${HOSTNAME}${NC}"
@@ -738,11 +738,11 @@ echo -e "Generations: ${YELLOW}${GEN_COUNT}${NC}"
echo ""
if [ "$DISK_PCT" -gt 80 ] 2>/dev/null; then
- echo -e "${RED}⚠ WARNING: Disk usage is high (>${DISK_PCT}%)${NC}"
+ echo -e "${RED}⚠ WARNING: Disk usage is high (>${DISK_PCT}%)${NC}"
elif [ "$DISK_PCT" -gt 70 ] 2>/dev/null; then
- echo -e "${YELLOW}⚠ NOTICE: Disk usage is elevated (${DISK_PCT}%)${NC}"
+ echo -e "${YELLOW}⚠ NOTICE: Disk usage is elevated (${DISK_PCT}%)${NC}"
else
- echo -e "${GREEN}✓ Disk usage is healthy (${DISK_PCT}%)${NC}"
+ echo -e "${GREEN}✓ Disk usage is healthy (${DISK_PCT}%)${NC}"
fi
echo ""