mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 16:34:30 +01:00
filter: allow multiple --exclude-if-present flags - fixes #6219
This commit is contained in:
parent
20aaeba547
commit
f4f0e444bf
@ -2136,6 +2136,7 @@ For the filtering options
|
||||
* `--filter-from`
|
||||
* `--exclude`
|
||||
* `--exclude-from`
|
||||
* `--exclude-if-present`
|
||||
* `--include`
|
||||
* `--include-from`
|
||||
* `--files-from`
|
||||
|
@ -750,7 +750,9 @@ Useful for debugging.
|
||||
|
||||
The `--exclude-if-present` flag controls whether a directory is
|
||||
within the scope of an rclone command based on the presence of a
|
||||
named file within it.
|
||||
named file within it. The flag can be repeated to check for
|
||||
multiple file names, presence of any of them will exclude the
|
||||
directory.
|
||||
|
||||
This flag has a priority over other filter flags.
|
||||
|
||||
@ -764,8 +766,6 @@ E.g. for the following directory structure:
|
||||
The command `rclone ls --exclude-if-present .ignore dir1` does
|
||||
not list `dir3`, `file3` or `.ignore`.
|
||||
|
||||
`--exclude-if-present` can only be used once in an rclone command.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
The most frequent filter support issues on
|
||||
|
@ -47,7 +47,7 @@ These flags are available for every command.
|
||||
--error-on-no-transfer Sets exit code 9 if no files are transferred, useful in scripts
|
||||
--exclude stringArray Exclude files matching pattern
|
||||
--exclude-from stringArray Read exclude patterns from file (use - to read from stdin)
|
||||
--exclude-if-present string Exclude directories if filename is present
|
||||
--exclude-if-present stringArray Exclude directories if filename is present
|
||||
--expect-continue-timeout duration Timeout when using expect / 100-continue in HTTP (default 1s)
|
||||
--fast-list Use recursive list if available; uses more memory but fewer transactions
|
||||
--files-from stringArray Read list of source-file names from file (use - to read from stdin)
|
||||
|
@ -86,7 +86,7 @@ type Opt struct {
|
||||
FilterFrom []string
|
||||
ExcludeRule []string
|
||||
ExcludeFrom []string
|
||||
ExcludeFile string
|
||||
ExcludeFile []string
|
||||
IncludeRule []string
|
||||
IncludeFrom []string
|
||||
FilesFrom []string
|
||||
@ -392,11 +392,13 @@ func (f *Filter) ListContainsExcludeFile(entries fs.DirEntries) bool {
|
||||
obj, ok := entry.(fs.Object)
|
||||
if ok {
|
||||
basename := path.Base(obj.Remote())
|
||||
if basename == f.Opt.ExcludeFile {
|
||||
for _, excludeFile := range f.Opt.ExcludeFile {
|
||||
if basename == excludeFile {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -436,7 +438,8 @@ func (f *Filter) IncludeDirectory(ctx context.Context, fs fs.Fs) func(string) (b
|
||||
// empty string (for testing).
|
||||
func (f *Filter) DirContainsExcludeFile(ctx context.Context, fremote fs.Fs, remote string) (bool, error) {
|
||||
if len(f.Opt.ExcludeFile) > 0 {
|
||||
exists, err := fs.FileExists(ctx, fremote, path.Join(remote, f.Opt.ExcludeFile))
|
||||
for _, excludeFile := range f.Opt.ExcludeFile {
|
||||
exists, err := fs.FileExists(ctx, fremote, path.Join(remote, excludeFile))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -444,6 +447,7 @@ func (f *Filter) DirContainsExcludeFile(ctx context.Context, fremote fs.Fs, remo
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ func AddFlags(flagSet *pflag.FlagSet) {
|
||||
flags.StringArrayVarP(flagSet, &Opt.FilterFrom, "filter-from", "", nil, "Read filtering patterns from a file (use - to read from stdin)")
|
||||
flags.StringArrayVarP(flagSet, &Opt.ExcludeRule, "exclude", "", nil, "Exclude files matching pattern")
|
||||
flags.StringArrayVarP(flagSet, &Opt.ExcludeFrom, "exclude-from", "", nil, "Read exclude patterns from file (use - to read from stdin)")
|
||||
flags.StringVarP(flagSet, &Opt.ExcludeFile, "exclude-if-present", "", "", "Exclude directories if filename is present")
|
||||
flags.StringArrayVarP(flagSet, &Opt.ExcludeFile, "exclude-if-present", "", nil, "Exclude directories if filename is present")
|
||||
flags.StringArrayVarP(flagSet, &Opt.IncludeRule, "include", "", nil, "Include files matching pattern")
|
||||
flags.StringArrayVarP(flagSet, &Opt.IncludeFrom, "include-from", "", nil, "Read include patterns from file (use - to read from stdin)")
|
||||
flags.StringArrayVarP(flagSet, &Opt.FilesFrom, "files-from", "", nil, "Read list of source-file names from file (use - to read from stdin)")
|
||||
|
@ -81,7 +81,7 @@ func TestListDirSorted(t *testing.T) {
|
||||
assert.Equal(t, "sub dir/sub sub dir/", str(1))
|
||||
|
||||
// testing ignore file
|
||||
fi.Opt.ExcludeFile = ".ignore"
|
||||
fi.Opt.ExcludeFile = []string{".ignore"}
|
||||
|
||||
items, err = list.DirSorted(context.Background(), r.Fremote, false, "sub dir")
|
||||
require.NoError(t, err)
|
||||
@ -98,7 +98,7 @@ func TestListDirSorted(t *testing.T) {
|
||||
assert.Equal(t, "sub dir/ignore dir/.ignore", str(0))
|
||||
assert.Equal(t, "sub dir/ignore dir/should be ignored", str(1))
|
||||
|
||||
fi.Opt.ExcludeFile = ""
|
||||
fi.Opt.ExcludeFile = nil
|
||||
items, err = list.DirSorted(context.Background(), r.Fremote, false, "sub dir/ignore dir")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 2)
|
||||
|
@ -1309,7 +1309,7 @@ func TestOverlappingFilterCheckWithFilter(t *testing.T) {
|
||||
fi, err := filter.NewFilter(nil)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fi.Add(false, "*/exclude/"))
|
||||
fi.Opt.ExcludeFile = ".ignore"
|
||||
fi.Opt.ExcludeFile = []string{".ignore"}
|
||||
ctx = filter.ReplaceConfig(ctx, fi)
|
||||
|
||||
src := &testFs{testFsInfo{name: "name", root: "root"}}
|
||||
|
@ -1452,7 +1452,7 @@ func TestSyncOverlapWithFilter(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, fi.Add(false, "/rclone-sync-test/"))
|
||||
require.NoError(t, fi.Add(false, "*/layer2/"))
|
||||
fi.Opt.ExcludeFile = ".ignore"
|
||||
fi.Opt.ExcludeFile = []string{".ignore"}
|
||||
ctx = filter.ReplaceConfig(ctx, fi)
|
||||
|
||||
subRemoteName := r.FremoteName + "/rclone-sync-test"
|
||||
|
@ -507,12 +507,14 @@ func walkRDirTree(ctx context.Context, f fs.Fs, startPath string, includeAll boo
|
||||
// Check if we need to prune a directory later.
|
||||
if !includeAll && len(fi.Opt.ExcludeFile) > 0 {
|
||||
basename := path.Base(x.Remote())
|
||||
if basename == fi.Opt.ExcludeFile {
|
||||
for _, excludeFile := range fi.Opt.ExcludeFile {
|
||||
if basename == excludeFile {
|
||||
excludeDir := parentDir(x.Remote())
|
||||
toPrune[excludeDir] = true
|
||||
fs.Debugf(basename, "Excluded from sync (and deletion) based on exclude file")
|
||||
}
|
||||
}
|
||||
}
|
||||
case fs.Directory:
|
||||
inc, err := includeDirectory(x.Remote())
|
||||
if err != nil {
|
||||
|
@ -736,13 +736,13 @@ b/c/d/
|
||||
e
|
||||
`, nil, "", -1, "ign", true},
|
||||
} {
|
||||
fi.Opt.ExcludeFile = test.excludeFile
|
||||
fi.Opt.ExcludeFile = []string{test.excludeFile}
|
||||
r, err := walkRDirTree(context.Background(), nil, test.root, test.includeAll, test.level, makeListRCallback(test.entries, test.err))
|
||||
assert.Equal(t, test.err, err, fmt.Sprintf("%+v", test))
|
||||
assert.Equal(t, test.want, r.String(), fmt.Sprintf("%+v", test))
|
||||
}
|
||||
// Set to default value, to avoid side effects
|
||||
fi.Opt.ExcludeFile = ""
|
||||
fi.Opt.ExcludeFile = nil
|
||||
}
|
||||
|
||||
func TestListType(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user