mirror of
https://github.com/tw93/Mole.git
synced 2026-02-16 22:49:12 +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:
BIN
bin/analyze-go
BIN
bin/analyze-go
Binary file not shown.
BIN
bin/status-go
BIN
bin/status-go
Binary file not shown.
@@ -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
|
||||||
|
|||||||
@@ -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
65
tests/debug_logging.bats
Normal 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 ]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user