mirror of
https://github.com/rclone/rclone.git
synced 2025-08-18 17:38:52 +02:00
copy,copyto,move,moveto: implement logger flags to store result of sync
This enables the logger flags (`--combined`, `--missing-on-src` etc.) for the `rclone copy` and `move` commands (as well as their `copyto` and `moveto` variants) akin to `rclone sync`. Warnings for unsupported/wonky flag combinations are also printed, e.g. when the destination is not traversed but `--dest-after` is specified. - fs/operations: add reusable methods for operation logging - cmd/sync: use reusable methods for implementing logging in sync command - cmd: implement logging for copy/copyto/move/moveto commands - fs/operations/operationsflags: warn about logs in conjunction with --no-traverse - cmd: add logger docs to copy and move commands Fixes #8115
This commit is contained in:
@@ -3,12 +3,28 @@
|
||||
package operationsflags
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/fs/config/flags"
|
||||
"github.com/rclone/rclone/fs/hash"
|
||||
"github.com/rclone/rclone/fs/operations"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
//go:embed operationsflags.md
|
||||
var help string
|
||||
|
||||
// Help returns the help string cleaned up to simplify appending
|
||||
func Help() string {
|
||||
return strings.TrimSpace(help) + "\n\n"
|
||||
}
|
||||
|
||||
// AddLoggerFlagsOptions contains options for the Logger Flags
|
||||
type AddLoggerFlagsOptions struct {
|
||||
Combined string // a file with file names with leading sigils
|
||||
@@ -20,6 +36,20 @@ type AddLoggerFlagsOptions struct {
|
||||
DestAfter string // files that exist on the destination post-sync
|
||||
}
|
||||
|
||||
// AnySet checks if any of the logger flags have a non-blank value
|
||||
func (o AddLoggerFlagsOptions) AnySet() bool {
|
||||
return anyNotBlank(o.Combined, o.MissingOnSrc, o.MissingOnDst, o.Match, o.Differ, o.ErrFile, o.DestAfter)
|
||||
}
|
||||
|
||||
func anyNotBlank(s ...string) bool {
|
||||
for _, x := range s {
|
||||
if x != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AddLoggerFlags adds the logger flags to the cmdFlags command
|
||||
func AddLoggerFlags(cmdFlags *pflag.FlagSet, opt *operations.LoggerOpt, flagsOpt *AddLoggerFlagsOptions) {
|
||||
flags.StringVarP(cmdFlags, &flagsOpt.Combined, "combined", "", flagsOpt.Combined, "Make a combined report of changes to this file", "Sync")
|
||||
@@ -43,3 +73,75 @@ func AddLoggerFlags(cmdFlags *pflag.FlagSet, opt *operations.LoggerOpt, flagsOpt
|
||||
flags.BoolVarP(cmdFlags, &opt.Absolute, "absolute", "", false, "Put a leading / in front of path names", "Sync")
|
||||
// flags.BoolVarP(cmdFlags, &recurse, "recursive", "R", false, "Recurse into the listing", "")
|
||||
}
|
||||
|
||||
// ConfigureLoggers verifies and sets up writers for log files requested via CLI flags
|
||||
func ConfigureLoggers(ctx context.Context, fdst fs.Fs, command *cobra.Command, opt *operations.LoggerOpt, flagsOpt AddLoggerFlagsOptions) (func(), error) {
|
||||
closers := []io.Closer{}
|
||||
|
||||
if opt.TimeFormat == "max" {
|
||||
opt.TimeFormat = operations.FormatForLSFPrecision(fdst.Precision())
|
||||
}
|
||||
opt.SetListFormat(ctx, command.Flags())
|
||||
opt.NewListJSON(ctx, fdst, "")
|
||||
|
||||
open := func(name string, pout *io.Writer) error {
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
if name == "-" {
|
||||
*pout = os.Stdout
|
||||
return nil
|
||||
}
|
||||
out, err := os.Create(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*pout = out
|
||||
closers = append(closers, out)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := open(flagsOpt.Combined, &opt.Combined); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := open(flagsOpt.MissingOnSrc, &opt.MissingOnSrc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := open(flagsOpt.MissingOnDst, &opt.MissingOnDst); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := open(flagsOpt.Match, &opt.Match); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := open(flagsOpt.Differ, &opt.Differ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := open(flagsOpt.ErrFile, &opt.Error); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := open(flagsOpt.DestAfter, &opt.DestAfter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
close := func() {
|
||||
for _, closer := range closers {
|
||||
err := closer.Close()
|
||||
if err != nil {
|
||||
fs.Errorf(nil, "Failed to close report output: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ci := fs.GetConfig(ctx)
|
||||
if ci.NoTraverse && opt.Combined != nil {
|
||||
fs.LogPrintf(fs.LogLevelWarning, nil, "--no-traverse does not list any deletes (-) in --combined output\n")
|
||||
}
|
||||
if ci.NoTraverse && opt.MissingOnSrc != nil {
|
||||
fs.LogPrintf(fs.LogLevelWarning, nil, "--no-traverse makes --missing-on-src produce empty output\n")
|
||||
}
|
||||
if ci.NoTraverse && opt.DestAfter != nil {
|
||||
fs.LogPrintf(fs.LogLevelWarning, nil, "--no-traverse makes --dest-after produce incomplete output\n")
|
||||
}
|
||||
|
||||
return close, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user