operations: share the report file opening between check and sync
The code which opens the --combined, --differ etc report files (or stdout for "-") and closes them afterwards was duplicated between the check command and the sync logger flags. This moves it into operations.OpenReportFiles which both now use. It also closes any files already opened if a later one fails to open.
This commit is contained in:
+9
-46
@@ -4,8 +4,6 @@ package check
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/rclone/rclone/cmd"
|
||||
@@ -78,58 +76,23 @@ option for more information.`, "|", "`")
|
||||
|
||||
// GetCheckOpt gets the options corresponding to the check flags
|
||||
func GetCheckOpt(fsrc, fdst fs.Fs) (opt *operations.CheckOpt, close func(), err error) {
|
||||
closers := []io.Closer{}
|
||||
|
||||
opt = &operations.CheckOpt{
|
||||
Fsrc: fsrc,
|
||||
Fdst: fdst,
|
||||
OneWay: oneway,
|
||||
}
|
||||
|
||||
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(combined, &opt.Combined); err != nil {
|
||||
close, err = operations.OpenReportFiles(
|
||||
operations.ReportFile{Name: combined, Out: &opt.Combined},
|
||||
operations.ReportFile{Name: missingOnSrc, Out: &opt.MissingOnSrc},
|
||||
operations.ReportFile{Name: missingOnDst, Out: &opt.MissingOnDst},
|
||||
operations.ReportFile{Name: match, Out: &opt.Match},
|
||||
operations.ReportFile{Name: differ, Out: &opt.Differ},
|
||||
operations.ReportFile{Name: errFile, Out: &opt.Error},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = open(missingOnSrc, &opt.MissingOnSrc); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = open(missingOnDst, &opt.MissingOnDst); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = open(match, &opt.Match); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = open(differ, &opt.Differ); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = open(errFile, &opt.Error); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
close = func() {
|
||||
for _, closer := range closers {
|
||||
err := closer.Close()
|
||||
if err != nil {
|
||||
fs.Errorf(nil, "Failed to close report output: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return opt, close, nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
mutex "sync"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
@@ -302,6 +303,48 @@ func WinningSide(ctx context.Context, sigil Sigil, src, dst fs.DirEntry, err err
|
||||
return winner
|
||||
}
|
||||
|
||||
// ReportFile pairs the name of a file a report is written to with
|
||||
// the writer to set when it is opened.
|
||||
type ReportFile struct {
|
||||
Name string // file name, "" for no report or "-" for stdout
|
||||
Out *io.Writer // set to the opened file
|
||||
}
|
||||
|
||||
// OpenReportFiles opens the report files for writing and returns a
|
||||
// function to close them.
|
||||
//
|
||||
// For each file an empty Name leaves Out unchanged so the report is
|
||||
// not written, "-" sets it to stdout and any other Name is created as
|
||||
// a file, truncating it if it exists.
|
||||
func OpenReportFiles(files ...ReportFile) (close func(), err error) {
|
||||
closers := []io.Closer{}
|
||||
close = func() {
|
||||
for _, closer := range closers {
|
||||
err := closer.Close()
|
||||
if err != nil {
|
||||
fs.Errorf(nil, "Failed to close report output: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, file := range files {
|
||||
switch file.Name {
|
||||
case "":
|
||||
continue
|
||||
case "-":
|
||||
*file.Out = os.Stdout
|
||||
default:
|
||||
out, err := os.Create(file.Name)
|
||||
if err != nil {
|
||||
close()
|
||||
return nil, err
|
||||
}
|
||||
*file.Out = out
|
||||
closers = append(closers, out)
|
||||
}
|
||||
}
|
||||
return close, nil
|
||||
}
|
||||
|
||||
// NewSyncLoggerOpt returns a LoggerOpt with no report writers set and
|
||||
// the default listing options for the DestAfter report.
|
||||
func NewSyncLoggerOpt() LoggerOpt {
|
||||
|
||||
@@ -5,8 +5,6 @@ package operationsflags
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
@@ -76,55 +74,18 @@ func AddLoggerFlags(cmdFlags *pflag.FlagSet, opt *operations.LoggerOpt, flagsOpt
|
||||
|
||||
// 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{}
|
||||
|
||||
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 {
|
||||
close, err := operations.OpenReportFiles(
|
||||
operations.ReportFile{Name: flagsOpt.Combined, Out: &opt.Combined},
|
||||
operations.ReportFile{Name: flagsOpt.MissingOnSrc, Out: &opt.MissingOnSrc},
|
||||
operations.ReportFile{Name: flagsOpt.MissingOnDst, Out: &opt.MissingOnDst},
|
||||
operations.ReportFile{Name: flagsOpt.Match, Out: &opt.Match},
|
||||
operations.ReportFile{Name: flagsOpt.Differ, Out: &opt.Differ},
|
||||
operations.ReportFile{Name: flagsOpt.ErrFile, Out: &opt.Error},
|
||||
operations.ReportFile{Name: flagsOpt.DestAfter, Out: &opt.DestAfter},
|
||||
)
|
||||
if 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
opt.Init(ctx, fdst, command.Flags())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user