diff --git a/backup/cmd/backup.go b/backup/cmd/backup.go index a2ff473..deba0c2 100644 --- a/backup/cmd/backup.go +++ b/backup/cmd/backup.go @@ -2,26 +2,61 @@ package cmd import ( "fmt" + "log" + "os" + "time" + + "backup-rsync/backup/internal" "github.com/spf13/cobra" ) -// Add the run and simulate verbs with empty implementations +func executeSyncJobs(cfg internal.Config, simulate bool) { + logPath := fmt.Sprintf("logs/sync-%s", time.Now().Format("2006-01-02T15-04-05")) + + if err := os.MkdirAll(logPath, 0755); err != nil { + log.Fatalf("Failed to create log directory: %v", err) + } + + overallLogPath := fmt.Sprintf("%s/summary.log", logPath) + overallLogFile, err := os.OpenFile(overallLogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + log.Fatalf("Failed to open overall log file: %v", err) + } + defer overallLogFile.Close() + overallLogger := log.New(overallLogFile, "", log.LstdFlags) + + for _, job := range cfg.Jobs { + jobLogPath := fmt.Sprintf("%s/job-%s.log", logPath, job.Name) + logFile, err := os.OpenFile(jobLogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + if err != nil { + overallLogger.Printf("ERROR [%s]: Failed to create job log file: %v", job.Name, err) + continue + } + defer logFile.Close() + jobLogger := log.New(logFile, "", log.LstdFlags) + + status := internal.ExecuteJob(job, simulate, jobLogger) + overallLogger.Printf("STATUS [%s]: %s", job.Name, status) + fmt.Printf("Status [%s]: %s\n", job.Name, status) + } +} + var runCmd = &cobra.Command{ Use: "run", - Short: "Run the backup jobs", + Short: "Execute the sync jobs", Run: func(cmd *cobra.Command, args []string) { - // Empty implementation for now - fmt.Println("Run command executed.") + cfg := loadResolvedConfig(configPath) + executeSyncJobs(cfg, false) }, } var simulateCmd = &cobra.Command{ Use: "simulate", - Short: "Simulate the backup jobs", + Short: "Simulate the sync jobs", Run: func(cmd *cobra.Command, args []string) { - // Empty implementation for now - fmt.Println("Simulate command executed.") + cfg := loadResolvedConfig(configPath) + executeSyncJobs(cfg, true) }, } diff --git a/backup/internal/job.go b/backup/internal/job.go index 4efb5c8..305c27c 100644 --- a/backup/internal/job.go +++ b/backup/internal/job.go @@ -7,7 +7,7 @@ import ( "strings" ) -func buildRsyncCmd(job Job, dryRun bool) *exec.Cmd { +func buildRsyncCmd(job Job, simulate bool) *exec.Cmd { args := []string{"-aiv", "--info=progress2"} if job.Delete == nil || *job.Delete { args = append(args, "--delete") @@ -16,22 +16,22 @@ func buildRsyncCmd(job Job, dryRun bool) *exec.Cmd { args = append(args, fmt.Sprintf("--exclude=%s", excl)) } args = append(args, job.Source, job.Target) - if dryRun { + if simulate { args = append([]string{"--dry-run"}, args...) } return exec.Command("rsync", args...) } -func executeJob(job Job, dryRun bool, logger *log.Logger) string { +func ExecuteJob(job Job, simulate bool, logger *log.Logger) string { if job.Enabled != nil && !*job.Enabled { logger.Printf("SKIPPED [%s]: Job is disabled", job.Name) return "SKIPPED" } - cmd := buildRsyncCmd(job, dryRun) + cmd := buildRsyncCmd(job, simulate) fmt.Printf("Job: %s\n", job.Name) fmt.Printf("Command: %s\n", strings.Join(cmd.Args, " ")) - if !dryRun { + if !simulate { out, err := cmd.CombinedOutput() if err != nil { logger.Printf("ERROR [%s]: %v\nOutput: %s", job.Name, err, string(out)) diff --git a/backup/internal/job_test.go b/backup/internal/job_test.go index 0cd1865..329938e 100644 --- a/backup/internal/job_test.go +++ b/backup/internal/job_test.go @@ -44,7 +44,7 @@ func TestExecuteJob(t *testing.T) { dryRun := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := executeJob(job, dryRun, logger) + status := ExecuteJob(job, dryRun, logger) if status != "SUCCESS" { t.Errorf("Expected status SUCCESS, got %s", status) } @@ -56,7 +56,7 @@ func TestExecuteJob(t *testing.T) { Enabled: boolPtr(false), } - status = executeJob(disabledJob, dryRun, logger) + status = ExecuteJob(disabledJob, dryRun, logger) if status != "SKIPPED" { t.Errorf("Expected status SKIPPED, got %s", status) } @@ -68,7 +68,7 @@ func TestExecuteJob(t *testing.T) { Target: "/mnt/backup1/invalid/", } - status = executeJob(invalidJob, false, logger) + status = ExecuteJob(invalidJob, false, logger) if status != "FAILURE" { t.Errorf("Expected status FAILURE, got %s", status) } @@ -84,7 +84,7 @@ func TestJobSkippedEnabledTrue(t *testing.T) { dryRun := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := executeJob(job, dryRun, logger) + status := ExecuteJob(job, dryRun, logger) if status != "SUCCESS" { t.Errorf("Expected status SUCCESS, got %s", status) } @@ -100,7 +100,7 @@ func TestJobSkippedEnabledFalse(t *testing.T) { dryRun := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := executeJob(disabledJob, dryRun, logger) + status := ExecuteJob(disabledJob, dryRun, logger) if status != "SKIPPED" { t.Errorf("Expected status SKIPPED, got %s", status) } @@ -115,7 +115,7 @@ func TestJobSkippedEnabledOmitted(t *testing.T) { dryRun := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := executeJob(job, dryRun, logger) + status := ExecuteJob(job, dryRun, logger) if status != "SUCCESS" { t.Errorf("Expected status SUCCESS, got %s", status) }