Files
wild-cloud/wild-cli/internal/external/restic.go

289 lines
5.6 KiB
Go

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
}