Log changed files after backup

This commit is contained in:
Mikei386
2026-07-10 11:32:48 +02:00
parent 99e2753c10
commit 5aa28cf43e
9 changed files with 193 additions and 8 deletions
+62
View File
@@ -98,6 +98,16 @@ type Stats struct {
TotalBlobCount int64 `json:"total_blob_count"`
}
type DiffEntry struct {
Kind string
Path string
}
type DiffResult struct {
Entries []DiffEntry
Total int
}
func (r *Runner) Init(ctx context.Context, repo model.Repository) error {
return r.run(ctx, repo, []string{"init"}, nil, nil)
}
@@ -280,6 +290,58 @@ func (r *Runner) List(ctx context.Context, repo model.Repository, snapshot, path
return items, scanner.Err()
}
func (r *Runner) Diff(ctx context.Context, repo model.Repository, before, after string, limit int) (DiffResult, error) {
var output []byte
if err := r.run(ctx, repo, []string{"diff", "--metadata", before, after}, nil, &output); err != nil {
return DiffResult{}, err
}
return parseDiffOutput(output, limit), nil
}
func parseDiffOutput(output []byte, limit int) DiffResult {
if limit <= 0 {
limit = 50
}
result := DiffResult{}
scanner := bufio.NewScanner(bytes.NewReader(output))
scanner.Buffer(make([]byte, 0, 64*1024), 2*1024*1024)
for scanner.Scan() {
line := scanner.Text()
if len(line) < 2 {
continue
}
kind := diffKind(line[0])
if kind == "" {
continue
}
path := strings.TrimSpace(line[1:])
if path == "" || !strings.HasPrefix(path, "/") {
continue
}
result.Total++
if len(result.Entries) == limit {
copy(result.Entries, result.Entries[1:])
result.Entries[len(result.Entries)-1] = DiffEntry{Kind: kind, Path: path}
continue
}
result.Entries = append(result.Entries, DiffEntry{Kind: kind, Path: path})
}
return result
}
func diffKind(marker byte) string {
switch marker {
case '+':
return "new"
case '-':
return "removed"
case 'M':
return "modified"
default:
return ""
}
}
func (r *Runner) Restore(ctx context.Context, repo model.Repository, task model.RestoreTask, progress ProgressCallback) error {
args := []string{"restore", task.SnapshotID, "--target", task.Target, "--json"}
for _, include := range task.Includes {
+43
View File
@@ -190,6 +190,49 @@ func TestRestoreReportsProgress(t *testing.T) {
}
}
func TestDiffReportsLastChangedPaths(t *testing.T) {
dir := t.TempDir()
argsPath := filepath.Join(dir, "args")
script := filepath.Join(dir, "restic")
body := fmt.Sprintf(`#!/bin/sh
printf '%%s\n' "$@" > '%s'
printf '%%s\n' 'comparing snapshot before to after:'
printf '%%s\n' '+ /mnt/user/new.txt'
printf '%%s\n' 'M /mnt/user/modified-a.txt'
printf '%%s\n' '- /mnt/user/removed.txt'
printf '%%s\n' 'M /mnt/user/modified-b.txt'
printf '%%s\n' 'Files: 1 new, 1 removed, 2 changed'
`, argsPath)
if err := os.WriteFile(script, []byte(body), 0700); err != nil {
t.Fatal(err)
}
runner := &Runner{Binary: script, RuntimeDir: dir, Secrets: fakeSecrets{"password": "secret"}}
repo := model.Repository{Type: model.RepositoryLocal, Location: "/repo", PasswordRef: "password"}
diff, err := runner.Diff(context.Background(), repo, "before", "after", 3)
if err != nil {
t.Fatal(err)
}
if diff.Total != 4 || len(diff.Entries) != 3 {
t.Fatalf("unexpected diff result: %+v", diff)
}
expected := []DiffEntry{
{Kind: "modified", Path: "/mnt/user/modified-a.txt"},
{Kind: "removed", Path: "/mnt/user/removed.txt"},
{Kind: "modified", Path: "/mnt/user/modified-b.txt"},
}
for index, entry := range expected {
if diff.Entries[index] != entry {
t.Fatalf("entry %d = %+v, want %+v", index, diff.Entries[index], entry)
}
}
args, _ := os.ReadFile(argsPath)
for _, expected := range []string{"diff", "--metadata", "before", "after"} {
if !strings.Contains(string(args), expected) {
t.Fatalf("arguments missing %q: %s", expected, args)
}
}
}
func TestStatsUsesRequestedRepositoryCountingMode(t *testing.T) {
dir := t.TempDir()
argsPath := filepath.Join(dir, "args")