Release 2026.09.27.r002: clarify rsync dry runs and expand run diagnostics
This commit is contained in:
+37
-19
@@ -40,16 +40,19 @@ type Progress struct {
|
||||
Bytes int64
|
||||
Files int64
|
||||
CurrentFile string
|
||||
Change string
|
||||
}
|
||||
|
||||
type Summary struct {
|
||||
Bytes int64
|
||||
Files int64
|
||||
Bytes int64
|
||||
Files int64
|
||||
Deleted int64
|
||||
}
|
||||
|
||||
var (
|
||||
progressPattern = regexp.MustCompile(`^\s*([0-9,]+)\s+([0-9]+)%`)
|
||||
filesPattern = regexp.MustCompile(`^Number of regular files transferred:\s*([0-9,]+)`)
|
||||
deletedPattern = regexp.MustCompile(`^Number of deleted files:\s*([0-9,]+)`)
|
||||
bytesPattern = regexp.MustCompile(`^Total transferred file size:\s*([0-9,]+) bytes`)
|
||||
)
|
||||
|
||||
@@ -88,17 +91,12 @@ func (r *Runner) Run(ctx context.Context, runID string, job model.Job, callback
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
scanOutput(stdout, func(line string) {
|
||||
if value, ok := parseCount(filesPattern, line); ok {
|
||||
summary.Files = value
|
||||
}
|
||||
if value, ok := parseCount(bytesPattern, line); ok {
|
||||
summary.Bytes = value
|
||||
}
|
||||
summary.parseLine(line)
|
||||
if callback != nil {
|
||||
if progress, ok := parseProgress(line); ok {
|
||||
callback(progress)
|
||||
} else if strings.HasPrefix(line, "FILE|") {
|
||||
callback(Progress{CurrentFile: strings.TrimPrefix(line, "FILE|")})
|
||||
} else if change, ok := parseChange(line); ok {
|
||||
callback(change)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -106,9 +104,10 @@ func (r *Runner) Run(ctx context.Context, runID string, job model.Job, callback
|
||||
}()
|
||||
stderrDone := make(chan []byte, 1)
|
||||
go func() { stderrDone <- drainLimited(stderr, 1024*1024) }()
|
||||
err = cmd.Wait()
|
||||
// Drain both pipes before Wait closes them, including the final statistics.
|
||||
<-done
|
||||
errBytes := <-stderrDone
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
if errors.Is(ctx.Err(), context.Canceled) {
|
||||
return Summary{}, fmt.Errorf("cancelled: %w", ctx.Err())
|
||||
@@ -163,20 +162,16 @@ func (r *Runner) Estimate(ctx context.Context, runID string, job model.Job) (Sum
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
scanOutput(stdout, func(line string) {
|
||||
if value, ok := parseCount(filesPattern, line); ok {
|
||||
summary.Files = value
|
||||
}
|
||||
if value, ok := parseCount(bytesPattern, line); ok {
|
||||
summary.Bytes = value
|
||||
}
|
||||
summary.parseLine(line)
|
||||
})
|
||||
close(done)
|
||||
}()
|
||||
stderrDone := make(chan []byte, 1)
|
||||
go func() { stderrDone <- drainLimited(stderr, 1024*1024) }()
|
||||
err = cmd.Wait()
|
||||
// Drain both pipes before Wait closes them, including the final statistics.
|
||||
<-done
|
||||
errBytes := <-stderrDone
|
||||
err = cmd.Wait()
|
||||
if err != nil {
|
||||
if errors.Is(ctx.Err(), context.Canceled) {
|
||||
return Summary{}, fmt.Errorf("cancelled: %w", ctx.Err())
|
||||
@@ -188,7 +183,7 @@ func (r *Runner) Estimate(ctx context.Context, runID string, job model.Job) (Sum
|
||||
|
||||
func Arguments(job model.Job) []string {
|
||||
options := job.Rsync
|
||||
args := []string{"--recursive", "--human-readable", "--info=progress2", "--stats", "--partial", "--out-format=FILE|%n"}
|
||||
args := []string{"--recursive", "--info=progress2", "--stats", "--partial", "--outbuf=L", "--out-format=CHANGE|%i|%n%L"}
|
||||
if !options.Overwrite {
|
||||
args = append(args, "--ignore-existing")
|
||||
}
|
||||
@@ -322,3 +317,26 @@ func parseCount(pattern *regexp.Regexp, line string) (int64, bool) {
|
||||
value, err := strconv.ParseInt(strings.ReplaceAll(match[1], ",", ""), 10, 64)
|
||||
return value, err == nil
|
||||
}
|
||||
|
||||
func (s *Summary) parseLine(line string) {
|
||||
if value, ok := parseCount(filesPattern, line); ok {
|
||||
s.Files = value
|
||||
}
|
||||
if value, ok := parseCount(bytesPattern, line); ok {
|
||||
s.Bytes = value
|
||||
}
|
||||
if value, ok := parseCount(deletedPattern, line); ok {
|
||||
s.Deleted = value
|
||||
}
|
||||
}
|
||||
|
||||
func parseChange(line string) (Progress, bool) {
|
||||
if !strings.HasPrefix(line, "CHANGE|") {
|
||||
return Progress{}, false
|
||||
}
|
||||
fields := strings.SplitN(strings.TrimPrefix(line, "CHANGE|"), "|", 2)
|
||||
if len(fields) != 2 || len(fields[0]) != 11 {
|
||||
return Progress{}, false
|
||||
}
|
||||
return Progress{Change: fields[0], CurrentFile: fields[1]}, true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user