Add live activity progress and logs
This commit is contained in:
@@ -35,11 +35,24 @@ type Summary struct {
|
||||
TotalFilesProcessed int64 `json:"total_files_processed"`
|
||||
}
|
||||
|
||||
type Progress struct {
|
||||
MessageType string `json:"message_type"`
|
||||
PercentDone float64 `json:"percent_done"`
|
||||
TotalFiles int64 `json:"total_files"`
|
||||
FilesDone int64 `json:"files_done"`
|
||||
TotalBytes int64 `json:"total_bytes"`
|
||||
BytesDone int64 `json:"bytes_done"`
|
||||
SecondsRemaining int64 `json:"seconds_remaining"`
|
||||
CurrentFiles []string `json:"current_files"`
|
||||
}
|
||||
|
||||
type ProgressCallback func(Progress)
|
||||
|
||||
func (r *Runner) Init(ctx context.Context, repo model.Repository) error {
|
||||
return r.run(ctx, repo, []string{"init"}, nil, nil)
|
||||
}
|
||||
|
||||
func (r *Runner) Backup(ctx context.Context, repo model.Repository, job model.Job, sources []string) (Summary, error) {
|
||||
func (r *Runner) Backup(ctx context.Context, repo model.Repository, job model.Job, sources []string, progress ProgressCallback) (Summary, error) {
|
||||
args := []string{"backup", "--json", "--compression", job.Compression}
|
||||
for _, tag := range append([]string{"backupper", "job:" + job.ID}, job.Tags...) {
|
||||
args = append(args, "--tag", tag)
|
||||
@@ -50,6 +63,13 @@ func (r *Runner) Backup(ctx context.Context, repo model.Repository, job model.Jo
|
||||
args = append(args, sources...)
|
||||
var summary Summary
|
||||
err := r.run(ctx, repo, args, func(line []byte) {
|
||||
var status Progress
|
||||
if json.Unmarshal(line, &status) == nil && status.MessageType == "status" {
|
||||
if progress != nil {
|
||||
progress(status)
|
||||
}
|
||||
return
|
||||
}
|
||||
var candidate Summary
|
||||
if json.Unmarshal(line, &candidate) == nil && candidate.MessageType == "summary" {
|
||||
summary = candidate
|
||||
|
||||
@@ -20,20 +20,24 @@ func TestBackupUsesPasswordFileAndStructuredArguments(t *testing.T) {
|
||||
argsPath := filepath.Join(dir, "args")
|
||||
passwordPath := filepath.Join(dir, "password")
|
||||
script := filepath.Join(dir, "restic")
|
||||
body := fmt.Sprintf("#!/bin/sh\nprintf '%%s\\n' \"$@\" > '%s'\ncat \"$RESTIC_PASSWORD_FILE\" > '%s'\nprintf '%%s\\n' '{\"message_type\":\"summary\",\"snapshot_id\":\"abc123\",\"data_added\":42,\"files_new\":3,\"files_changed\":2,\"total_bytes_processed\":1024,\"total_files_processed\":12}'\n", argsPath, passwordPath)
|
||||
body := fmt.Sprintf("#!/bin/sh\nprintf '%%s\\n' \"$@\" > '%s'\ncat \"$RESTIC_PASSWORD_FILE\" > '%s'\nprintf '%%s\\n' '{\"message_type\":\"status\",\"percent_done\":0.5,\"total_files\":12,\"files_done\":6,\"total_bytes\":1024,\"bytes_done\":512,\"seconds_remaining\":4,\"current_files\":[\"/source path/file.txt\"]}'\nprintf '%%s\\n' '{\"message_type\":\"summary\",\"snapshot_id\":\"abc123\",\"data_added\":42,\"files_new\":3,\"files_changed\":2,\"total_bytes_processed\":1024,\"total_files_processed\":12}'\n", argsPath, passwordPath)
|
||||
if err := os.WriteFile(script, []byte(body), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runner := &Runner{Binary: script, RuntimeDir: dir, Secrets: fakeSecrets{"password": "top-secret"}}
|
||||
repo := model.Repository{Type: model.RepositoryLocal, Location: "/repo path", PasswordRef: "password"}
|
||||
job := model.Job{ID: "job", Compression: "auto", Tags: []string{"daily"}, Excludes: []string{"*.tmp"}}
|
||||
summary, err := runner.Backup(context.Background(), repo, job, []string{"/source path"})
|
||||
var progress Progress
|
||||
summary, err := runner.Backup(context.Background(), repo, job, []string{"/source path"}, func(value Progress) { progress = value })
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if summary.SnapshotID != "abc123" || summary.DataAdded != 42 || summary.FilesChanged != 2 || summary.TotalBytesProcessed != 1024 || summary.TotalFilesProcessed != 12 {
|
||||
t.Fatalf("unexpected summary: %+v", summary)
|
||||
}
|
||||
if progress.PercentDone != 0.5 || progress.FilesDone != 6 || progress.BytesDone != 512 || len(progress.CurrentFiles) != 1 {
|
||||
t.Fatalf("unexpected progress: %+v", progress)
|
||||
}
|
||||
args, _ := os.ReadFile(argsPath)
|
||||
for _, expected := range []string{"/repo path", "backup", "--json", "/source path"} {
|
||||
if !strings.Contains(string(args), expected) {
|
||||
|
||||
Reference in New Issue
Block a user