Add comprehensive system enhancements and shell configurations
Following the μέτρον principle of durable, thoughtful solutions: Shell Configuration: - Add refined .zshrc with modular architecture - Include .p10k.zsh for Powerlevel10k prompt - Add .zprofile for login shell configuration - Update aliases with new dotfiles management tools System Management Tools: - safe-update.sh: System updates with rollback protection - detect-drift.sh: Configuration drift detection - system-health.sh: Comprehensive health monitoring - generate-lockfile.sh: Version tracking for reproducibility Documentation: - ARCHITECTURE.md: Philosophy and design rationale - USAGE.md: Practical guide and troubleshooting Other Updates: - Update symlinks.sh to manage all config files - Add .vimrc configuration - Create Brewfile.lock for version pinning These enhancements provide visibility, safety, and maintainability while following the prime directive of prioritizing durability. 🖖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
92b0ead991
commit
1f543d195b
Executable
+275
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/env bash
|
||||
# Configuration drift detection - compare actual system state to dotfiles
|
||||
# Follows the μέτρον principle: measure what is, against what should be
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DOTFILES_DIR="$HOME/dotfiles"
|
||||
DRIFT_REPORT_DIR="$HOME/.drift-reports"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
REPORT_FILE="$DRIFT_REPORT_DIR/drift-$TIMESTAMP.txt"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${BLUE}Configuration Drift Detection${NC}"
|
||||
echo "===================================="
|
||||
|
||||
# Create report directory
|
||||
mkdir -p "$DRIFT_REPORT_DIR"
|
||||
|
||||
# Initialize report
|
||||
cat > "$REPORT_FILE" << EOF
|
||||
Configuration Drift Report
|
||||
Generated: $(date)
|
||||
System: $(sw_vers -productVersion)
|
||||
|
||||
EOF
|
||||
|
||||
# Function to detect package drift
|
||||
detect_package_drift() {
|
||||
echo -e "${YELLOW}🔍 Analyzing package drift...${NC}"
|
||||
|
||||
local brewfile="$DOTFILES_DIR/Brewfile"
|
||||
local lockfile="$DOTFILES_DIR/Brewfile.lock"
|
||||
local drift_found=false
|
||||
|
||||
echo "=== PACKAGE DRIFT ANALYSIS ===" >> "$REPORT_FILE"
|
||||
|
||||
if [[ ! -f "$brewfile" ]]; then
|
||||
echo "❌ Brewfile not found at $brewfile" | tee -a "$REPORT_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for packages in Brewfile but not installed
|
||||
echo "Packages defined but not installed:" >> "$REPORT_FILE"
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^brew\ \"([^\"]+)\" ]]; then
|
||||
package="${BASH_REMATCH[1]}"
|
||||
if ! brew list --formula | grep -q "^$package$"; then
|
||||
echo " - $package (formula)" | tee -a "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
elif [[ "$line" =~ ^cask\ \"([^\"]+)\" ]]; then
|
||||
package="${BASH_REMATCH[1]}"
|
||||
if ! brew list --cask | grep -q "^$package$"; then
|
||||
echo " - $package (cask)" | tee -a "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
fi
|
||||
done < "$brewfile"
|
||||
|
||||
# Check for installed packages not in Brewfile
|
||||
echo "" >> "$REPORT_FILE"
|
||||
echo "Packages installed but not in Brewfile:" >> "$REPORT_FILE"
|
||||
|
||||
# Check formulae
|
||||
while IFS= read -r package; do
|
||||
if ! grep -q "brew \"$package\"" "$brewfile" 2>/dev/null; then
|
||||
echo " - $package (formula)" | tee -a "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
done < <(brew list --formula)
|
||||
|
||||
# Check casks
|
||||
while IFS= read -r package; do
|
||||
if ! grep -q "cask \"$package\"" "$brewfile" 2>/dev/null; then
|
||||
echo " - $package (cask)" | tee -a "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
done < <(brew list --cask)
|
||||
|
||||
# Version drift (if lockfile exists)
|
||||
if [[ -f "$lockfile" ]]; then
|
||||
echo "" >> "$REPORT_FILE"
|
||||
echo "Version drift from lockfile:" >> "$REPORT_FILE"
|
||||
|
||||
# Compare current versions to locked versions
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^([^[:space:]]+)[[:space:]]+(.+)$ ]]; then
|
||||
package="${BASH_REMATCH[1]}"
|
||||
locked_version="${BASH_REMATCH[2]}"
|
||||
|
||||
# Get current version
|
||||
current_version=$(brew list --versions "$package" 2>/dev/null | head -1 | cut -d' ' -f2- || echo "not installed")
|
||||
|
||||
if [[ "$current_version" != "$locked_version" && "$current_version" != "not installed" ]]; then
|
||||
echo " - $package: locked($locked_version) vs current($current_version)" | tee -a "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
fi
|
||||
done < <(grep -v '^#' "$lockfile" 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
if [[ "$drift_found" == "false" ]]; then
|
||||
echo -e "${GREEN}✅ No package drift detected${NC}"
|
||||
echo "No package drift detected" >> "$REPORT_FILE"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Package drift detected - see report${NC}"
|
||||
fi
|
||||
|
||||
echo "" >> "$REPORT_FILE"
|
||||
}
|
||||
|
||||
# Function to detect configuration file drift
|
||||
detect_config_drift() {
|
||||
echo -e "${YELLOW}🔍 Analyzing configuration drift...${NC}"
|
||||
|
||||
echo "=== CONFIGURATION FILE DRIFT ===" >> "$REPORT_FILE"
|
||||
|
||||
local config_files=(
|
||||
".zshrc:$HOME/.zshrc:$DOTFILES_DIR/shell/.zshrc"
|
||||
".gitconfig:$HOME/.gitconfig:$DOTFILES_DIR/.gitconfig"
|
||||
".vimrc:$HOME/.vimrc:$DOTFILES_DIR/.vimrc"
|
||||
)
|
||||
|
||||
local drift_found=false
|
||||
|
||||
for config_spec in "${config_files[@]}"; do
|
||||
IFS=':' read -r name home_path dotfiles_path <<< "$config_spec"
|
||||
|
||||
if [[ -f "$home_path" && -f "$dotfiles_path" ]]; then
|
||||
if ! diff -q "$home_path" "$dotfiles_path" >/dev/null 2>&1; then
|
||||
echo "Configuration drift detected: $name" | tee -a "$REPORT_FILE"
|
||||
echo " Home: $home_path" >> "$REPORT_FILE"
|
||||
echo " Dotfiles: $dotfiles_path" >> "$REPORT_FILE"
|
||||
echo " Run: diff \"$home_path\" \"$dotfiles_path\"" >> "$REPORT_FILE"
|
||||
echo "" >> "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
elif [[ -f "$home_path" && ! -f "$dotfiles_path" ]]; then
|
||||
echo "File exists in home but not in dotfiles: $name" | tee -a "$REPORT_FILE"
|
||||
drift_found=true
|
||||
elif [[ ! -f "$home_path" && -f "$dotfiles_path" ]]; then
|
||||
echo "File exists in dotfiles but not deployed: $name" | tee -a "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$drift_found" == "false" ]]; then
|
||||
echo -e "${GREEN}✅ No configuration drift detected${NC}"
|
||||
echo "No configuration drift detected" >> "$REPORT_FILE"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Configuration drift detected - see report${NC}"
|
||||
fi
|
||||
|
||||
echo "" >> "$REPORT_FILE"
|
||||
}
|
||||
|
||||
# Function to detect system settings drift
|
||||
detect_system_drift() {
|
||||
echo -e "${YELLOW}🔍 Analyzing system settings drift...${NC}"
|
||||
|
||||
echo "=== SYSTEM SETTINGS DRIFT ===" >> "$REPORT_FILE"
|
||||
|
||||
local defaults_script="$DOTFILES_DIR/scripts/set-macos-defaults.sh"
|
||||
|
||||
if [[ ! -f "$defaults_script" ]]; then
|
||||
echo "No macOS defaults script found" >> "$REPORT_FILE"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Extract settings from defaults script and check current values
|
||||
local drift_found=false
|
||||
|
||||
# Look for defaults write commands and check current values
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ defaults\ write\ ([^[:space:]]+)\ ([^[:space:]]+)\ (.+) ]]; then
|
||||
domain="${BASH_REMATCH[1]}"
|
||||
key="${BASH_REMATCH[2]}"
|
||||
expected_value="${BASH_REMATCH[3]}"
|
||||
|
||||
# Get current value
|
||||
current_value=$(defaults read "$domain" "$key" 2>/dev/null || echo "not set")
|
||||
|
||||
# Simple comparison (could be enhanced for complex types)
|
||||
if [[ "$current_value" != "$expected_value" ]]; then
|
||||
echo "Setting drift: $domain $key" >> "$REPORT_FILE"
|
||||
echo " Expected: $expected_value" >> "$REPORT_FILE"
|
||||
echo " Current: $current_value" >> "$REPORT_FILE"
|
||||
echo "" >> "$REPORT_FILE"
|
||||
drift_found=true
|
||||
fi
|
||||
fi
|
||||
done < <(grep "defaults write" "$defaults_script" 2>/dev/null || true)
|
||||
|
||||
if [[ "$drift_found" == "false" ]]; then
|
||||
echo -e "${GREEN}✅ No system settings drift detected${NC}"
|
||||
echo "No system settings drift detected" >> "$REPORT_FILE"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ System settings drift detected - see report${NC}"
|
||||
fi
|
||||
|
||||
echo "" >> "$REPORT_FILE"
|
||||
}
|
||||
|
||||
# Function to generate drift summary
|
||||
generate_summary() {
|
||||
echo -e "${BLUE}📊 Generating drift summary...${NC}"
|
||||
|
||||
echo "=== DRIFT SUMMARY ===" >> "$REPORT_FILE"
|
||||
echo "Report generated: $(date)" >> "$REPORT_FILE"
|
||||
echo "Next recommended actions:" >> "$REPORT_FILE"
|
||||
|
||||
if grep -q "drift detected" "$REPORT_FILE"; then
|
||||
echo "1. Review specific drift items above" >> "$REPORT_FILE"
|
||||
echo "2. Update dotfiles or system as appropriate" >> "$REPORT_FILE"
|
||||
echo "3. Run: ~/dotfiles/scripts/generate-lockfile.sh (for package versions)" >> "$REPORT_FILE"
|
||||
echo "4. Consider running: ~/dotfiles/engage (to re-sync configurations)" >> "$REPORT_FILE"
|
||||
else
|
||||
echo "✅ System is in sync with dotfiles configuration" >> "$REPORT_FILE"
|
||||
fi
|
||||
|
||||
echo "" >> "$REPORT_FILE"
|
||||
echo "To fix drift automatically, consider:" >> "$REPORT_FILE"
|
||||
echo "- Package drift: brew bundle --file=$DOTFILES_DIR/Brewfile" >> "$REPORT_FILE"
|
||||
echo "- Config drift: re-run relevant sections of ~/dotfiles/engage" >> "$REPORT_FILE"
|
||||
echo "- System drift: ~/dotfiles/scripts/set-macos-defaults.sh" >> "$REPORT_FILE"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
detect_package_drift
|
||||
detect_config_drift
|
||||
detect_system_drift
|
||||
generate_summary
|
||||
|
||||
echo -e "${BLUE}📋 Full report saved to: $REPORT_FILE${NC}"
|
||||
|
||||
# Show summary
|
||||
if grep -q "drift detected" "$REPORT_FILE"; then
|
||||
echo -e "${YELLOW}⚠️ Configuration drift detected${NC}"
|
||||
echo "Run: cat $REPORT_FILE | less"
|
||||
echo "Or: ~/dotfiles/scripts/detect-drift.sh --fix (future feature)"
|
||||
|
||||
# Clean old reports (keep last 10)
|
||||
find "$DRIFT_REPORT_DIR" -name "drift-*.txt" | sort -r | tail -n +11 | xargs rm -f 2>/dev/null || true
|
||||
|
||||
return 1
|
||||
else
|
||||
echo -e "${GREEN}✅ System configuration is consistent with dotfiles${NC}"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Command line options
|
||||
case "${1:-}" in
|
||||
--quiet|-q)
|
||||
main >/dev/null
|
||||
;;
|
||||
--report|-r)
|
||||
if [[ -f "$REPORT_FILE" ]]; then
|
||||
cat "$REPORT_FILE"
|
||||
else
|
||||
main
|
||||
cat "$REPORT_FILE"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
main
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user