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.
168 lines
6.2 KiB
Go
168 lines
6.2 KiB
Go
// Package check provides the check command.
|
|
package check
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/rclone/rclone/cmd"
|
|
"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"
|
|
)
|
|
|
|
// Globals
|
|
var (
|
|
download = false
|
|
oneway = false
|
|
combined = ""
|
|
missingOnSrc = ""
|
|
missingOnDst = ""
|
|
match = ""
|
|
differ = ""
|
|
errFile = ""
|
|
checkFileHashType = ""
|
|
)
|
|
|
|
func init() {
|
|
cmd.Root.AddCommand(commandDefinition)
|
|
cmdFlags := commandDefinition.Flags()
|
|
flags.BoolVarP(cmdFlags, &download, "download", "", download, "Check by downloading rather than with hash", "")
|
|
flags.StringVarP(cmdFlags, &checkFileHashType, "checkfile", "C", checkFileHashType, "Treat source:path as a SUM file with hashes of given type", "")
|
|
AddFlags(cmdFlags)
|
|
}
|
|
|
|
// AddFlags adds the check flags to the cmdFlags command
|
|
func AddFlags(cmdFlags *pflag.FlagSet) {
|
|
flags.BoolVarP(cmdFlags, &oneway, "one-way", "", oneway, "Check one way only, source files must exist on remote", "")
|
|
flags.StringVarP(cmdFlags, &combined, "combined", "", combined, "Make a combined report of changes to this file", "")
|
|
flags.StringVarP(cmdFlags, &missingOnSrc, "missing-on-src", "", missingOnSrc, "Report all files missing from the source to this file", "")
|
|
flags.StringVarP(cmdFlags, &missingOnDst, "missing-on-dst", "", missingOnDst, "Report all files missing from the destination to this file", "")
|
|
flags.StringVarP(cmdFlags, &match, "match", "", match, "Report all matching files to this file", "")
|
|
flags.StringVarP(cmdFlags, &differ, "differ", "", differ, "Report all non-matching files to this file", "")
|
|
flags.StringVarP(cmdFlags, &errFile, "error", "", errFile, "Report all files with errors (hashing or reading) to this file", "")
|
|
}
|
|
|
|
// FlagsHelp describes the flags for the help
|
|
// Warning! "|" will be replaced by backticks below
|
|
var FlagsHelp = strings.ReplaceAll(`
|
|
If you supply the |--one-way| flag, it will only check that files in
|
|
the source match the files in the destination, not the other way
|
|
around. This means that extra files in the destination that are not in
|
|
the source will not be detected.
|
|
|
|
The |--differ|, |--missing-on-dst|, |--missing-on-src|, |--match|
|
|
and |--error| flags write paths, one per line, to the file name (or
|
|
stdout if it is |-|) supplied. What they write is described in the
|
|
help below. For example |--differ| will write all paths which are
|
|
present on both the source and destination but different.
|
|
|
|
The |--combined| flag will write a file (or stdout) which contains all
|
|
file paths with a symbol and then a space and then the path to tell
|
|
you what happened to it. These are reminiscent of diff files.
|
|
|
|
- |= path| means path was found in source and destination and was identical
|
|
- |- path| means path was missing on the source, so only in the destination
|
|
- |+ path| means path was missing on the destination, so only in the source
|
|
- |* path| means path was present in source and destination but different.
|
|
- |! path| means there was an error reading or hashing the source or dest.
|
|
|
|
The default number of parallel checks is 8. See the [--checkers](/docs/#checkers-int)
|
|
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) {
|
|
opt = &operations.CheckOpt{
|
|
Fsrc: fsrc,
|
|
Fdst: fdst,
|
|
OneWay: oneway,
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
return opt, close, nil
|
|
}
|
|
|
|
var commandDefinition = &cobra.Command{
|
|
Use: "check source:path dest:path",
|
|
Short: `Checks the files in the source and destination match.`,
|
|
Long: strings.ReplaceAll(`Checks the files in the source and destination match. It compares
|
|
sizes and hashes (MD5 or SHA1) and logs a report of files that don't
|
|
match. It doesn't alter the source or destination.
|
|
|
|
For the [crypt](/crypt/) remote there is a dedicated command,
|
|
[cryptcheck](/commands/rclone_cryptcheck/), that are able to check
|
|
the checksums of the encrypted files.
|
|
|
|
If you supply the |--size-only| flag, it will only compare the sizes not
|
|
the hashes as well. Use this for a quick check.
|
|
|
|
If you supply the |--download| flag, it will download the data from
|
|
both remotes and check them against each other on the fly. This can
|
|
be useful for remotes that don't support hashes or if you really want
|
|
to check all the data.
|
|
|
|
If you supply the |--checkfile HASH| flag with a valid hash name,
|
|
the |source:path| must point to a text file in the SUM format.
|
|
`, "|", "`") + FlagsHelp,
|
|
Annotations: map[string]string{
|
|
"groups": "Filter,Listing,Check",
|
|
},
|
|
RunE: func(command *cobra.Command, args []string) error {
|
|
cmd.CheckArgs(2, 2, command, args)
|
|
var (
|
|
fsrc, fdst fs.Fs
|
|
hashType hash.Type
|
|
fsum fs.Fs
|
|
sumFile string
|
|
)
|
|
if checkFileHashType != "" {
|
|
if err := hashType.Set(checkFileHashType); err != nil {
|
|
fmt.Println(hash.HelpString(0))
|
|
return err
|
|
}
|
|
fsum, sumFile, fsrc = cmd.NewFsSrcFileDst(args)
|
|
} else {
|
|
fsrc, fdst = cmd.NewFsSrcDst(args)
|
|
}
|
|
|
|
cmd.Run(false, true, command, func() error {
|
|
opt, close, err := GetCheckOpt(fsrc, fdst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer close()
|
|
|
|
if checkFileHashType != "" {
|
|
return operations.CheckSum(context.Background(), fsrc, fsum, sumFile, hashType, opt, download)
|
|
}
|
|
|
|
if download {
|
|
return operations.CheckDownload(context.Background(), opt)
|
|
}
|
|
hashType := fsrc.Hashes().Overlap(fdst.Hashes()).GetOne()
|
|
if hashType == hash.None {
|
|
fs.Errorf(nil, "No common hash found - not using a hash for checks")
|
|
} else {
|
|
fs.Infof(nil, "Using %v for hash comparisons", hashType)
|
|
}
|
|
return operations.Check(context.Background(), opt)
|
|
})
|
|
return nil
|
|
},
|
|
}
|