package external import ( "context" "fmt" "os" "strings" ) // ResticTool wraps restic backup operations type ResticTool struct { *BaseTool repository string password string } // NewResticTool creates a new restic tool wrapper func NewResticTool() *ResticTool { return &ResticTool{ BaseTool: NewBaseTool("restic", "restic"), } } // SetRepository sets the restic repository func (r *ResticTool) SetRepository(repo string) { r.repository = repo } // SetPassword sets the restic password func (r *ResticTool) SetPassword(password string) { r.password = password } // InitRepository initializes a new restic repository func (r *ResticTool) InitRepository(ctx context.Context) error { env := r.getEnvironment() cmd := r.BaseTool originalEnv := os.Environ() defer func() { os.Clearenv() for _, kv := range originalEnv { if k, v, found := strings.Cut(kv, "="); found { _ = os.Setenv(k, v) } } }() // Set environment variables for k, v := range env { _ = os.Setenv(k, v) } args := []string{"init"} if r.repository != "" { args = append(args, "--repo", r.repository) } _, err := cmd.Execute(ctx, args...) if err != nil { return fmt.Errorf("initializing repository: %w", err) } return nil } // Backup creates a backup func (r *ResticTool) Backup(ctx context.Context, paths []string, excludes []string, tags []string) error { env := r.getEnvironment() cmd := r.BaseTool originalEnv := os.Environ() defer func() { os.Clearenv() for _, kv := range originalEnv { if k, v, found := strings.Cut(kv, "="); found { _ = os.Setenv(k, v) } } }() // Set environment variables for k, v := range env { _ = os.Setenv(k, v) } args := []string{"backup"} if r.repository != "" { args = append(args, "--repo", r.repository) } // Add paths args = append(args, paths...) // Add excludes for _, exclude := range excludes { args = append(args, "--exclude", exclude) } // Add tags for _, tag := range tags { args = append(args, "--tag", tag) } _, err := cmd.Execute(ctx, args...) if err != nil { return fmt.Errorf("creating backup: %w", err) } return nil } // Restore restores from backup func (r *ResticTool) Restore(ctx context.Context, snapshotID, target string) error { env := r.getEnvironment() cmd := r.BaseTool originalEnv := os.Environ() defer func() { os.Clearenv() for _, kv := range originalEnv { if k, v, found := strings.Cut(kv, "="); found { _ = os.Setenv(k, v) } } }() // Set environment variables for k, v := range env { _ = os.Setenv(k, v) } args := []string{"restore", snapshotID, "--target", target} if r.repository != "" { args = append(args, "--repo", r.repository) } _, err := cmd.Execute(ctx, args...) if err != nil { return fmt.Errorf("restoring backup: %w", err) } return nil } // ListSnapshots lists available snapshots func (r *ResticTool) ListSnapshots(ctx context.Context, tags []string) ([]byte, error) { env := r.getEnvironment() cmd := r.BaseTool originalEnv := os.Environ() defer func() { os.Clearenv() for _, kv := range originalEnv { if k, v, found := strings.Cut(kv, "="); found { _ = os.Setenv(k, v) } } }() // Set environment variables for k, v := range env { _ = os.Setenv(k, v) } args := []string{"snapshots", "--json"} if r.repository != "" { args = append(args, "--repo", r.repository) } // Add tag filters for _, tag := range tags { args = append(args, "--tag", tag) } output, err := cmd.Execute(ctx, args...) if err != nil { return nil, fmt.Errorf("listing snapshots: %w", err) } return output, nil } // Check verifies repository integrity func (r *ResticTool) Check(ctx context.Context) error { env := r.getEnvironment() cmd := r.BaseTool originalEnv := os.Environ() defer func() { os.Clearenv() for _, kv := range originalEnv { if k, v, found := strings.Cut(kv, "="); found { _ = os.Setenv(k, v) } } }() // Set environment variables for k, v := range env { _ = os.Setenv(k, v) } args := []string{"check"} if r.repository != "" { args = append(args, "--repo", r.repository) } _, err := cmd.Execute(ctx, args...) if err != nil { return fmt.Errorf("checking repository: %w", err) } return nil } // Forget removes snapshots func (r *ResticTool) Forget(ctx context.Context, keepLast int, keepDaily int, keepWeekly int, keepMonthly int, prune bool) error { env := r.getEnvironment() cmd := r.BaseTool originalEnv := os.Environ() defer func() { os.Clearenv() for _, kv := range originalEnv { if k, v, found := strings.Cut(kv, "="); found { _ = os.Setenv(k, v) } } }() // Set environment variables for k, v := range env { _ = os.Setenv(k, v) } args := []string{"forget"} if r.repository != "" { args = append(args, "--repo", r.repository) } if keepLast > 0 { args = append(args, "--keep-last", fmt.Sprintf("%d", keepLast)) } if keepDaily > 0 { args = append(args, "--keep-daily", fmt.Sprintf("%d", keepDaily)) } if keepWeekly > 0 { args = append(args, "--keep-weekly", fmt.Sprintf("%d", keepWeekly)) } if keepMonthly > 0 { args = append(args, "--keep-monthly", fmt.Sprintf("%d", keepMonthly)) } if prune { args = append(args, "--prune") } _, err := cmd.Execute(ctx, args...) if err != nil { return fmt.Errorf("forgetting snapshots: %w", err) } return nil } // getEnvironment returns environment variables for restic func (r *ResticTool) getEnvironment() map[string]string { env := make(map[string]string) if r.repository != "" { env["RESTIC_REPOSITORY"] = r.repository } if r.password != "" { env["RESTIC_PASSWORD"] = r.password } return env }