diff --git a/backup/cmd/backup.go b/backup/cmd/backup.go index deba0c2..41b8369 100644 --- a/backup/cmd/backup.go +++ b/backup/cmd/backup.go @@ -36,12 +36,18 @@ func executeSyncJobs(cfg internal.Config, simulate bool) { defer logFile.Close() jobLogger := log.New(logFile, "", log.LstdFlags) - status := internal.ExecuteJob(job, simulate, jobLogger) + status := internal.ExecuteJob(job, simulate, false, jobLogger) overallLogger.Printf("STATUS [%s]: %s", job.Name, status) fmt.Printf("Status [%s]: %s\n", job.Name, status) } } +func listCommands(cfg internal.Config, simulate bool) { + for _, job := range cfg.Jobs { + internal.ExecuteJob(job, simulate, true, nil) + } +} + var runCmd = &cobra.Command{ Use: "run", Short: "Execute the sync jobs", @@ -60,7 +66,17 @@ var simulateCmd = &cobra.Command{ }, } +var listCmd = &cobra.Command{ + Use: "list", + Short: "List the commands that will be executed", + Run: func(cmd *cobra.Command, args []string) { + cfg := loadResolvedConfig(configPath) + listCommands(cfg, true) + }, +} + func init() { RootCmd.AddCommand(runCmd) RootCmd.AddCommand(simulateCmd) + RootCmd.AddCommand(listCmd) } diff --git a/backup/internal/job.go b/backup/internal/job.go index 3643060..3d705cd 100644 --- a/backup/internal/job.go +++ b/backup/internal/job.go @@ -9,7 +9,7 @@ import ( var execCommand = exec.Command -func buildRsyncCmd(job Job, simulate bool) *exec.Cmd { +func buildRsyncCmd(job Job, simulate bool) []string { args := []string{"-aiv", "--info=progress2"} if job.Delete == nil || *job.Delete { args = append(args, "--delete") @@ -21,23 +21,35 @@ func buildRsyncCmd(job Job, simulate bool) *exec.Cmd { if simulate { args = append([]string{"--dry-run"}, args...) } - return execCommand("rsync", args...) + return args } -func ExecuteJob(job Job, simulate bool, logger *log.Logger) string { +func ExecuteJob(job Job, simulate bool, show bool, logger *log.Logger) string { if job.Enabled != nil && !*job.Enabled { - logger.Printf("SKIPPED [%s]: Job is disabled", job.Name) + if logger != nil { + logger.Printf("SKIPPED [%s]: Job is disabled", job.Name) + } return "SKIPPED" } - cmd := buildRsyncCmd(job, simulate) + args := buildRsyncCmd(job, simulate) fmt.Printf("Job: %s\n", job.Name) - fmt.Printf("Command: %s\n", strings.Join(cmd.Args, " ")) + fmt.Printf("Command: rsync %s\n", strings.Join(args, " ")) + + if show { + return "SUCCESS" + } + + cmd := execCommand("rsync", args...) out, err := cmd.CombinedOutput() if err != nil { - logger.Printf("ERROR [%s]: %v\nOutput: %s", job.Name, err, string(out)) + if logger != nil { + logger.Printf("ERROR [%s]: %v\nOutput: %s", job.Name, err, string(out)) + } return "FAILURE" } - logger.Printf("SUCCESS [%s]: %s", job.Name, string(out)) + if logger != nil { + logger.Printf("SUCCESS [%s]: %s", job.Name, string(out)) + } return "SUCCESS" } diff --git a/backup/internal/job_test.go b/backup/internal/job_test.go index 26730f0..02c11a4 100644 --- a/backup/internal/job_test.go +++ b/backup/internal/job_test.go @@ -16,16 +16,15 @@ func boolPtr(b bool) *bool { var capturedArgs []string var mockExecCommand = func(name string, args ...string) *exec.Cmd { - capturedArgs = args // Capture arguments for assertions if name == "rsync" { + capturedArgs = append(capturedArgs, args...) // Append arguments for assertions + if strings.Contains(strings.Join(args, " "), "--dry-run") { + return exec.Command("echo", "mocked rsync success") // Simulate success for dry-run + } if strings.Contains(strings.Join(args, " "), "/invalid/source/path") { - cmd := exec.Command("false") // Simulate failure for invalid paths - cmd.Args = append([]string{name}, args...) - return cmd + return exec.Command("false") // Simulate failure for invalid paths } - cmd := exec.Command("echo") - cmd.Args = append([]string{name}, args...) - return cmd + return exec.Command("echo", "mocked rsync success") // Simulate general success } return exec.Command(name, args...) } @@ -42,16 +41,16 @@ func TestBuildRsyncCmd(t *testing.T) { Exclusions: []string{"*.tmp", "node_modules/"}, } simulate := true - cmd := buildRsyncCmd(job, simulate) + args := buildRsyncCmd(job, simulate) expectedArgs := []string{ - "rsync", "--dry-run", "-aiv", "--info=progress2", "--delete", + "--dry-run", "-aiv", "--info=progress2", "--delete", "--exclude=*.tmp", "--exclude=node_modules/", "/home/user/Music/", "/target/user/music/home", } - if strings.Join(cmd.Args, " ") != strings.Join(expectedArgs, " ") { - t.Errorf("Expected %v, got %v", expectedArgs, cmd.Args) + if strings.Join(args, " ") != strings.Join(expectedArgs, " ") { + t.Errorf("Expected %v, got %v", expectedArgs, args) } } @@ -66,7 +65,7 @@ func TestExecuteJob(t *testing.T) { simulate := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := ExecuteJob(job, simulate, logger) + status := ExecuteJob(job, simulate, false, logger) if status != "SUCCESS" { t.Errorf("Expected status SUCCESS, got %s", status) } @@ -78,7 +77,7 @@ func TestExecuteJob(t *testing.T) { Enabled: boolPtr(false), } - status = ExecuteJob(disabledJob, simulate, logger) + status = ExecuteJob(disabledJob, simulate, false, logger) if status != "SKIPPED" { t.Errorf("Expected status SKIPPED, got %s", status) } @@ -90,7 +89,7 @@ func TestExecuteJob(t *testing.T) { Target: "/mnt/backup1/invalid/", } - status = ExecuteJob(invalidJob, false, logger) + status = ExecuteJob(invalidJob, false, false, logger) if status != "FAILURE" { t.Errorf("Expected status FAILURE, got %s", status) } @@ -106,7 +105,7 @@ func TestJobSkippedEnabledTrue(t *testing.T) { simulate := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := ExecuteJob(job, simulate, logger) + status := ExecuteJob(job, simulate, false, logger) if status != "SUCCESS" { t.Errorf("Expected status SUCCESS, got %s", status) } @@ -122,7 +121,7 @@ func TestJobSkippedEnabledFalse(t *testing.T) { simulate := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := ExecuteJob(disabledJob, simulate, logger) + status := ExecuteJob(disabledJob, simulate, false, logger) if status != "SKIPPED" { t.Errorf("Expected status SKIPPED, got %s", status) } @@ -137,7 +136,7 @@ func TestJobSkippedEnabledOmitted(t *testing.T) { simulate := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - status := ExecuteJob(job, simulate, logger) + status := ExecuteJob(job, simulate, false, logger) if status != "SUCCESS" { t.Errorf("Expected status SUCCESS, got %s", status) } @@ -157,7 +156,11 @@ func TestExecuteJobWithMockedRsync(t *testing.T) { simulate := true logger := log.New(&bytes.Buffer{}, "", log.LstdFlags) - _ = ExecuteJob(job, simulate, logger) + status := ExecuteJob(job, simulate, false, logger) + + if status != "SUCCESS" { + t.Errorf("Expected status SUCCESS, got %s", status) + } if len(capturedArgs) == 0 || capturedArgs[0] != "--dry-run" { t.Errorf("Expected --dry-run flag, got %v", capturedArgs)