1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-16 21:39:11 +00:00

Parallelize metric collection, enhance Touch ID script reliability with improved cleanup and backup, and add debug logging tests.

This commit is contained in:
Tw93
2025-12-12 14:11:37 +08:00
parent ddce2a197d
commit 42634fbf3d
5 changed files with 148 additions and 35 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -58,6 +58,10 @@ show_status() {
# Enable Touch ID for sudo # Enable Touch ID for sudo
enable_touchid() { enable_touchid() {
# Cleanup trap
local temp_file=""
trap '[[ -n "$temp_file" ]] && rm -f "$temp_file"' EXIT
# First check if system supports Touch ID # First check if system supports Touch ID
if ! supports_touchid; then if ! supports_touchid; then
log_warning "This Mac may not support Touch ID" log_warning "This Mac may not support Touch ID"
@@ -75,14 +79,15 @@ enable_touchid() {
return 0 return 0
fi fi
# Create backup and apply changes # Create backup only if it doesn't exist to preserve original state
if [[ ! -f "${PAM_SUDO_FILE}.mole-backup" ]]; then
if ! sudo cp "$PAM_SUDO_FILE" "${PAM_SUDO_FILE}.mole-backup" 2> /dev/null; then if ! sudo cp "$PAM_SUDO_FILE" "${PAM_SUDO_FILE}.mole-backup" 2> /dev/null; then
log_error "Failed to create backup" log_error "Failed to create backup"
return 1 return 1
fi fi
fi
# Create temp file with the modification # Create temp file
local temp_file
temp_file=$(mktemp) temp_file=$(mktemp)
# Insert pam_tid.so after the first comment block # Insert pam_tid.so after the first comment block
@@ -96,13 +101,18 @@ enable_touchid() {
{ print } { print }
' "$PAM_SUDO_FILE" > "$temp_file" ' "$PAM_SUDO_FILE" > "$temp_file"
# Verify content change
if cmp -s "$PAM_SUDO_FILE" "$temp_file"; then
log_error "Failed to modify configuration"
return 1
fi
# Apply the changes # Apply the changes
if sudo mv "$temp_file" "$PAM_SUDO_FILE" 2> /dev/null; then if sudo mv "$temp_file" "$PAM_SUDO_FILE" 2> /dev/null; then
echo -e "${GREEN}${ICON_SUCCESS} Touch ID enabled${NC} ${GRAY}- try: sudo ls${NC}" echo -e "${GREEN}${ICON_SUCCESS} Touch ID enabled${NC} ${GRAY}- try: sudo ls${NC}"
echo "" echo ""
return 0 return 0
else else
rm -f "$temp_file" 2> /dev/null || true
log_error "Failed to enable Touch ID" log_error "Failed to enable Touch ID"
return 1 return 1
fi fi
@@ -110,19 +120,24 @@ enable_touchid() {
# Disable Touch ID for sudo # Disable Touch ID for sudo
disable_touchid() { disable_touchid() {
# Cleanup trap
local temp_file=""
trap '[[ -n "$temp_file" ]] && rm -f "$temp_file"' EXIT
if ! is_touchid_configured; then if ! is_touchid_configured; then
echo -e "${YELLOW}Touch ID is not currently enabled${NC}" echo -e "${YELLOW}Touch ID is not currently enabled${NC}"
return 0 return 0
fi fi
# Create backup and remove configuration # Create backup only if it doesn't exist
if [[ ! -f "${PAM_SUDO_FILE}.mole-backup" ]]; then
if ! sudo cp "$PAM_SUDO_FILE" "${PAM_SUDO_FILE}.mole-backup" 2> /dev/null; then if ! sudo cp "$PAM_SUDO_FILE" "${PAM_SUDO_FILE}.mole-backup" 2> /dev/null; then
log_error "Failed to create backup" log_error "Failed to create backup"
return 1 return 1
fi fi
fi
# Remove pam_tid.so line # Remove pam_tid.so line
local temp_file
temp_file=$(mktemp) temp_file=$(mktemp)
grep -v "pam_tid.so" "$PAM_SUDO_FILE" > "$temp_file" grep -v "pam_tid.so" "$PAM_SUDO_FILE" > "$temp_file"
@@ -131,7 +146,6 @@ disable_touchid() {
echo "" echo ""
return 0 return 0
else else
rm -f "$temp_file" 2> /dev/null || true
log_error "Failed to disable Touch ID" log_error "Failed to disable Touch ID"
return 1 return 1
fi fi

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"os/exec" "os/exec"
"sync"
"time" "time"
"github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/disk"
@@ -155,34 +156,67 @@ func NewCollector() *Collector {
func (c *Collector) Collect() (MetricsSnapshot, error) { func (c *Collector) Collect() (MetricsSnapshot, error) {
now := time.Now() now := time.Now()
// Start host info collection early (it's fast but good to parallelize if possible,
// but it returns a struct needed for result, so we can just run it here or in parallel)
// host.Info is usually cached by gopsutil but let's just call it.
hostInfo, _ := host.Info() hostInfo, _ := host.Info()
cpuStats, cpuErr := collectCPU() var (
memStats, memErr := collectMemory() wg sync.WaitGroup
diskStats, diskErr := collectDisks() errMu sync.Mutex
hwInfo := collectHardware(memStats.Total, diskStats) mergeErr error
diskIO := c.collectDiskIO(now)
netStats, netErr := c.collectNetwork(now)
proxyStats := collectProxy()
batteryStats, _ := collectBatteries()
thermalStats := collectThermal()
sensorStats, _ := collectSensors()
gpuStats, gpuErr := c.collectGPU(now)
btStats := c.collectBluetooth(now)
topProcs := collectTopProcesses()
var mergeErr error cpuStats CPUStatus
for _, e := range []error{cpuErr, memErr, diskErr, netErr, gpuErr} { memStats MemoryStatus
if e != nil { diskStats []DiskStatus
diskIO DiskIOStatus
netStats []NetworkStatus
proxyStats ProxyStatus
batteryStats []BatteryStatus
thermalStats ThermalStatus
sensorStats []SensorReading
gpuStats []GPUStatus
btStats []BluetoothDevice
topProcs []ProcessInfo
)
// Helper to launch concurrent collection
collect := func(fn func() error) {
wg.Add(1)
go func() {
defer wg.Done()
if err := fn(); err != nil {
errMu.Lock()
if mergeErr == nil { if mergeErr == nil {
mergeErr = e mergeErr = err
} else { } else {
mergeErr = fmt.Errorf("%v; %w", mergeErr, e) mergeErr = fmt.Errorf("%v; %w", mergeErr, err)
} }
errMu.Unlock()
} }
}()
} }
// Calculate health score // Launch all independent collection tasks
collect(func() (err error) { cpuStats, err = collectCPU(); return })
collect(func() (err error) { memStats, err = collectMemory(); return })
collect(func() (err error) { diskStats, err = collectDisks(); return })
collect(func() (err error) { diskIO = c.collectDiskIO(now); return nil })
collect(func() (err error) { netStats, err = c.collectNetwork(now); return })
collect(func() (err error) { proxyStats = collectProxy(); return nil })
collect(func() (err error) { batteryStats, _ = collectBatteries(); return nil })
collect(func() (err error) { thermalStats = collectThermal(); return nil })
collect(func() (err error) { sensorStats, _ = collectSensors(); return nil })
collect(func() (err error) { gpuStats, err = c.collectGPU(now); return })
collect(func() (err error) { btStats = c.collectBluetooth(now); return nil })
collect(func() (err error) { topProcs = collectTopProcesses(); return nil })
// Wait for all to complete
wg.Wait()
// Dependent tasks (must run after others)
hwInfo := collectHardware(memStats.Total, diskStats)
score, scoreMsg := calculateHealthScore(cpuStats, memStats, diskStats, diskIO, thermalStats) score, scoreMsg := calculateHealthScore(cpuStats, memStats, diskStats, diskIO, thermalStats)
return MetricsSnapshot{ return MetricsSnapshot{

65
tests/debug_logging.bats Normal file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bats
setup_file() {
PROJECT_ROOT="$(cd "${BATS_TEST_DIRNAME}/.." && pwd)"
export PROJECT_ROOT
ORIGINAL_HOME="${HOME:-}"
export ORIGINAL_HOME
HOME="$(mktemp -d "${BATS_TEST_DIRNAME}/tmp-debug-logging.XXXXXX")"
export HOME
mkdir -p "$HOME"
}
teardown_file() {
rm -rf "$HOME"
if [[ -n "${ORIGINAL_HOME:-}" ]]; then
export HOME="$ORIGINAL_HOME"
fi
}
setup() {
export TERM="xterm-256color"
rm -rf "${HOME:?}"/*
mkdir -p "$HOME/.config/mole"
}
@test "mo clean --debug creates debug log file" {
run env HOME="$HOME" MO_DEBUG=1 "$PROJECT_ROOT/mole" clean --dry-run
[ "$status" -eq 0 ]
MOLE_OUTPUT="$output"
# Check if log file exists
DEBUG_LOG="$HOME/.config/mole/mole_debug_session.log"
[ -f "$DEBUG_LOG" ]
# Validates log content
run grep "Mole Debug Session" "$DEBUG_LOG"
[ "$status" -eq 0 ]
# Validates standard output message (ignoring colors)
[[ "$MOLE_OUTPUT" =~ "Debug session log saved to" ]]
}
@test "mo clean without debug does not show debug log path" {
run env HOME="$HOME" MO_DEBUG=0 "$PROJECT_ROOT/mole" clean --dry-run
[ "$status" -eq 0 ]
[[ "$output" != *"Debug session log saved to"* ]]
}
@test "mo clean --debug logs system info" {
run env HOME="$HOME" MO_DEBUG=1 "$PROJECT_ROOT/mole" clean --dry-run
[ "$status" -eq 0 ]
DEBUG_LOG="$HOME/.config/mole/mole_debug_session.log"
# Check for system info headers
run grep "User:" "$DEBUG_LOG"
[ "$status" -eq 0 ]
run grep "Architecture:" "$DEBUG_LOG"
[ "$status" -eq 0 ]
}