rc: add sync report parameters to sync/sync, sync/copy and sync/move - fixes #9846

The sync report flags (--combined, --missing-on-src, --missing-on-dst,
--match, --differ, --error and --dest-after) were only wired up in the
CLI commands so there was no way to get these reports over the rc or
from librclone.

This adds boolean parameters of the same names as operations/check
(combined, missingOnSrc, missingOnDst, match, differ, error and
destAfter) to sync/sync, sync/copy and sync/move. Each requested
report is returned as an array of strings in the output, just as
operations/check does. All default to off so existing callers see no
change in the output.

To share the code between the CLI and the rc the report writer helper
from operations/check is exported as operations.RcReportWriter, the
lsf defaults for --dest-after are moved into
operations.NewSyncLoggerOpt and the listing setup and --no-traverse
warnings from operationsflags.ConfigureLoggers into LoggerOpt.Init.
This commit is contained in:
Nick Craig-Wood
2026-09-08 10:34:07 +01:00
parent bc4a208e7e
commit af382608c4
5 changed files with 176 additions and 55 deletions
+25 -20
View File
@@ -764,6 +764,25 @@ func (s stringWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
// RcReportWriter returns a writer for the report called name.
//
// The report is enabled if in[name] is true, or if in[name] is absent
// and Default is true. When enabled, each line written to the returned
// writer is collected as a string in out[name], otherwise nil is
// returned to disable the report.
func RcReportWriter(in rc.Params, out rc.Params, name string, Default bool) io.Writer {
active, err := in.GetBool(name)
if err != nil {
active = Default
}
if !active {
return nil
}
result := []string{}
out[name] = &result
return stringWriter{&result}
}
// Check two directories
func rcCheck(ctx context.Context, in rc.Params) (out rc.Params, err error) {
srcFs, err := rc.GetFsNamed(ctx, in, "srcFs")
@@ -822,26 +841,12 @@ func rcCheck(ctx context.Context, in rc.Params) (out rc.Params, err error) {
}
out = rc.Params{}
getOutput := func(name string, Default bool) io.Writer {
active, err := in.GetBool(name)
if err != nil {
active = Default
}
if !active {
return nil
}
result := []string{}
out[name] = &result
return stringWriter{&result}
}
opt.Combined = getOutput("combined", false)
opt.MissingOnSrc = getOutput("missingOnSrc", true)
opt.MissingOnDst = getOutput("missingOnDst", true)
opt.Match = getOutput("match", false)
opt.Differ = getOutput("differ", true)
opt.Error = getOutput("error", true)
opt.Combined = RcReportWriter(in, out, "combined", false)
opt.MissingOnSrc = RcReportWriter(in, out, "missingOnSrc", true)
opt.MissingOnDst = RcReportWriter(in, out, "missingOnDst", true)
opt.Match = RcReportWriter(in, out, "match", false)
opt.Differ = RcReportWriter(in, out, "differ", true)
opt.Error = RcReportWriter(in, out, "error", true)
if checkFileHash != "" {
out["hashType"] = checkFileHashType.String()