refactor: Clean up whitespace and improve formatting in backup update logic

This commit is contained in:
Peter Wood
2025-05-30 08:57:28 -04:00
parent 137e5e8e2f
commit 374da47bf5

View File

@@ -479,10 +479,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.backupStatus[msg.service] == nil {
m.backupStatus[msg.service] = &BackupStatus{}
}
// Create context for this backup
ctx, cancel := context.WithCancel(context.Background())
m.backupStatus[msg.service].Service = msg.service
m.backupStatus[msg.service].Status = "running"
m.backupStatus[msg.service].LastRun = time.Now()
@@ -490,9 +490,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.backupStatus[msg.service].Progress = 0
m.backupStatus[msg.service].Context = ctx
m.backupStatus[msg.service].Cancel = cancel
m.viewport.SetContent(fmt.Sprintf("🚀 Starting backup for %s...\n\nInitializing backup process...\nPress 'x' to cancel if needed.", msg.service))
// Start progress ticker for time-based progress estimation
cmds = append(cmds, m.startProgressTicker(msg.service))
@@ -547,18 +547,18 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.backupStatus[msg.service].EndTime = time.Now()
m.backupStatus[msg.service].Duration = m.backupStatus[msg.service].EndTime.Sub(m.backupStatus[msg.service].StartTime).String()
m.backupStatus[msg.service].Progress = 100
// Clean up context
if m.backupStatus[msg.service].Cancel != nil {
m.backupStatus[msg.service].Cancel()
}
}
delete(m.runningBackups, msg.service)
// Parse output for additional info
lines := strings.Split(msg.output, "\n")
var summary strings.Builder
// Extract meaningful summary information
for _, line := range lines {
if strings.Contains(line, "Total files:") ||
@@ -569,18 +569,18 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
summary.WriteString("📊 " + strings.TrimSpace(line) + "\n")
}
}
summaryText := summary.String()
if summaryText == "" {
summaryText = "📊 Backup completed successfully"
}
duration := ""
if m.backupStatus[msg.service] != nil {
duration = m.backupStatus[msg.service].Duration
}
m.viewport.SetContent(fmt.Sprintf("✅ Backup completed successfully for %s!\n\nDuration: %s\n\n%s\n\n📋 Full Output:\n%s",
m.viewport.SetContent(fmt.Sprintf("✅ Backup completed successfully for %s!\n\nDuration: %s\n\n%s\n\n📋 Full Output:\n%s",
msg.service, duration, summaryText, msg.output))
case backupErrorMsg:
@@ -589,19 +589,19 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.backupStatus[msg.service].Error = msg.error
m.backupStatus[msg.service].EndTime = time.Now()
m.backupStatus[msg.service].Duration = m.backupStatus[msg.service].EndTime.Sub(m.backupStatus[msg.service].StartTime).String()
// Clean up context
if m.backupStatus[msg.service].Cancel != nil {
m.backupStatus[msg.service].Cancel()
}
}
delete(m.runningBackups, msg.service)
duration := ""
if m.backupStatus[msg.service] != nil {
duration = m.backupStatus[msg.service].Duration
}
// Provide helpful error analysis
var errorAnalysis string
if strings.Contains(msg.error, "permission denied") {
@@ -613,8 +613,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} else if strings.Contains(msg.error, "space") {
errorAnalysis = "\n💡 This might be a disk space issue. Check available storage."
}
m.viewport.SetContent(fmt.Sprintf("❌ Backup failed for %s!\n\nDuration: %s%s\n\n🚨 Error Details:\n%s",
m.viewport.SetContent(fmt.Sprintf("❌ Backup failed for %s!\n\nDuration: %s%s\n\n🚨 Error Details:\n%s",
msg.service, duration, errorAnalysis, msg.error))
case spinner.TickMsg:
@@ -663,11 +663,11 @@ func (m *Model) updateViewportForRunningService(service string, outputForDisplay
totalEstimatedDuration := time.Duration(totalEstimatedRaw)
remainingDuration := totalEstimatedDuration - elapsed
if remainingDuration > 0 {
etaStr = fmt.Sprintf("\\nETA: %s", remainingDuration.Round(time.Second))
etaStr = fmt.Sprintf("\nETA: %s", remainingDuration.Round(time.Second))
}
}
m.viewport.SetContent(fmt.Sprintf("⏳ Backup in progress for %s...\\n\\n%s %d%%%%\\nElapsed: %s%s\\n\\n📋 Latest output:\\n%s\\n\\nPress 'x' to stop the backup.",
m.viewport.SetContent(fmt.Sprintf("⏳ Backup in progress for %s...\n\n%s %d%%\nElapsed: %s%s\n\n📋 Latest output:\n%s\n\nPress 'x' to stop the backup.",
service, progressBar, progress, elapsed.Round(time.Second), etaStr, outputForDisplay))
}
@@ -702,7 +702,7 @@ func (m Model) View() string {
if m.activePanel == 1 {
viewportStyle = viewportStyle.BorderStyle(lipgloss.ThickBorder()).BorderForeground(lipgloss.Color("#7D56F4"))
}
// Add view indicator to viewport title
viewportTitle := ""
switch m.currentView {
@@ -715,7 +715,7 @@ func (m Model) View() string {
default:
viewportTitle = "💻 Output"
}
// Layout based on active panel
return lipgloss.JoinVertical(lipgloss.Left,
titleStyle.Render("🔧 Media & Plex Backup Manager"),
@@ -833,7 +833,7 @@ func (m *Model) showStatus() {
for _, service := range services {
status := m.backupStatus[service]
content.WriteString(fmt.Sprintf("🔧 Service: %s\n", strings.ToUpper(service)))
// Status with emoji
statusIcon := "⭕"
switch status.Status {
@@ -847,34 +847,34 @@ func (m *Model) showStatus() {
statusIcon = "🛑"
}
content.WriteString(fmt.Sprintf(" Status: %s %s\n", statusIcon, status.Status))
if !status.LastRun.IsZero() {
content.WriteString(fmt.Sprintf(" Last Run: %s\n", status.LastRun.Format("2006-01-02 15:04:05")))
}
if status.Duration != "" {
content.WriteString(fmt.Sprintf(" Duration: %s\n", status.Duration))
}
if status.Progress > 0 && status.Status == "running" {
content.WriteString(fmt.Sprintf(" Progress: %d%%\n", status.Progress))
}
if status.BackupSize != "" {
content.WriteString(fmt.Sprintf(" Size: %s\n", status.BackupSize))
}
if status.FilesCount > 0 {
content.WriteString(fmt.Sprintf(" Files: %d\n", status.FilesCount))
}
if status.Error != "" {
content.WriteString(fmt.Sprintf(" Error: %s\n", status.Error[:min(100, len(status.Error))]))
}
content.WriteString("\n")
}
// Add summary
running := 0
success := 0
@@ -889,7 +889,7 @@ func (m *Model) showStatus() {
failed++
}
}
content.WriteString("📊 SUMMARY:\n")
content.WriteString(fmt.Sprintf(" Running: %d | Success: %d | Failed: %d\n", running, success, failed))
}
@@ -916,7 +916,7 @@ func (m *Model) showConfig() {
if len(item.args) > 0 {
content.WriteString(fmt.Sprintf(" Args: %s\n", strings.Join(item.args, " ")))
}
// Check if script exists
if _, err := os.Stat(item.script); os.IsNotExist(err) {
content.WriteString(" ⚠️ Status: Script not found\n")
@@ -950,10 +950,10 @@ func (m *Model) stopBackup(service string, process *RunningProcess) tea.Cmd {
if process.Cancel != nil {
process.Cancel()
}
// Give process time to shut down gracefully
time.Sleep(2 * time.Second)
// Force kill if still running
if process.Cmd != nil && process.Cmd.Process != nil {
if process.Cmd.ProcessState == nil || !process.Cmd.ProcessState.Exited() {
@@ -977,11 +977,11 @@ func (m Model) runBackupCommand(item BackupItem) tea.Cmd {
// Create context for cancellation
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Execute the backup script with context
cmd := exec.CommandContext(ctx, item.script, item.args...)
cmd.Dir = m.shellPath
// Create pipes for stdout and stderr
stdout, err := cmd.StdoutPipe()
if err != nil {
@@ -990,7 +990,7 @@ func (m Model) runBackupCommand(item BackupItem) tea.Cmd {
error: fmt.Sprintf("Failed to create stdout pipe: %s", err.Error()),
}
}
stderr, err := cmd.StderrPipe()
if err != nil {
return backupErrorMsg{
@@ -998,7 +998,7 @@ func (m Model) runBackupCommand(item BackupItem) tea.Cmd {
error: fmt.Sprintf("Failed to create stderr pipe: %s", err.Error()),
}
}
// Start the command
if err := cmd.Start(); err != nil {
return backupErrorMsg{
@@ -1006,14 +1006,14 @@ func (m Model) runBackupCommand(item BackupItem) tea.Cmd {
error: fmt.Sprintf("Failed to start backup: %s", err.Error()),
}
}
var outputBuilder strings.Builder
var allOutput []string
// Monitor stdout and stderr in goroutines
var wg sync.WaitGroup
wg.Add(2)
// Read stdout
go func() {
defer wg.Done()
@@ -1024,7 +1024,7 @@ func (m Model) runBackupCommand(item BackupItem) tea.Cmd {
allOutput = append(allOutput, line)
}
}()
// Read stderr
go func() {
defer wg.Done()
@@ -1035,21 +1035,21 @@ func (m Model) runBackupCommand(item BackupItem) tea.Cmd {
allOutput = append(allOutput, "[STDERR] "+line)
}
}()
// Wait for the command to complete
err = cmd.Wait()
// Wait for output readers to finish
wg.Wait()
finalOutput := outputBuilder.String()
if err != nil {
// Check if it was cancelled
if ctx.Err() == context.Canceled {
return backupStopMsg{service: item.service}
}
return backupErrorMsg{
service: item.service,
error: fmt.Sprintf("Backup failed: %s\n\n📋 Output:\n%s", err.Error(), finalOutput),
@@ -1068,7 +1068,7 @@ func estimateProgress(output []string, service string) int {
if len(output) == 0 {
return 0
}
switch service {
case "plex":
// Plex backup stages: stop service (10%), backup files (60%), verify (20%), archive (10%)
@@ -1080,7 +1080,7 @@ func estimateProgress(output []string, service string) int {
"archiving": 90,
"completed": 100,
}
for _, line := range output {
line = strings.ToLower(line)
for stage, progress := range stages {
@@ -1089,7 +1089,7 @@ func estimateProgress(output []string, service string) int {
}
}
}
case "immich":
// Immich stages: database dump (50%), uploads backup (40%), upload to B2 (10%)
stages := map[string]int{
@@ -1099,7 +1099,7 @@ func estimateProgress(output []string, service string) int {
"uploading to": 90,
"completed": 100,
}
for _, line := range output {
line = strings.ToLower(line)
for stage, progress := range stages {
@@ -1108,26 +1108,26 @@ func estimateProgress(output []string, service string) int {
}
}
}
case "media":
// Media services backup: each service adds progress
services := []string{"sonarr", "radarr", "prowlarr", "audiobookshelf", "tautulli", "sabnzbd", "jellyseerr"}
completed := 0
for _, service := range services {
for _, line := range output {
if strings.Contains(strings.ToLower(line), service) &&
(strings.Contains(strings.ToLower(line), "success") ||
if strings.Contains(strings.ToLower(line), service) &&
(strings.Contains(strings.ToLower(line), "success") ||
strings.Contains(strings.ToLower(line), "completed")) {
completed++
break
}
}
}
return (completed * 100) / len(services)
}
// Default progress estimation based on line count
if len(output) < 10 {
return 20
@@ -1136,7 +1136,7 @@ func estimateProgress(output []string, service string) int {
} else if len(output) < 100 {
return 80
}
return 90
}
@@ -1248,11 +1248,11 @@ func createProgressBar(progress int) string {
if progress > 100 {
progress = 100
}
const barWidth = 30
filled := (progress * barWidth) / 100
empty := barWidth - filled
bar := strings.Repeat("█", filled) + strings.Repeat("░", empty)
return fmt.Sprintf("[%s]", bar)
}
@@ -1263,7 +1263,7 @@ func (m Model) startProgressTicker(service string) tea.Cmd {
// Check if backup is still running
if status, exists := m.backupStatus[service]; exists && status.Status == "running" {
elapsed := time.Since(status.StartTime)
// Estimate progress based on typical backup durations
var estimatedDuration time.Duration
switch service {
@@ -1276,13 +1276,13 @@ func (m Model) startProgressTicker(service string) tea.Cmd {
default:
estimatedDuration = 5 * time.Minute
}
// Calculate progress (cap at 95% until actual completion)
progress := int((elapsed.Seconds() / estimatedDuration.Seconds()) * 95)
if progress > 95 {
progress = 95
}
return backupProgressMsg{
service: service,
progress: progress,