support exclude file in --fast-list mode
This commit is contained in:
parent
557dd8f031
commit
538246f6c3
5 changed files with 83 additions and 23 deletions
55
fs/filter.go
55
fs/filter.go
|
@ -406,22 +406,51 @@ func (f *Filter) ListContainsExcludeFile(entries DirEntries) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// IncludeDirectory returns whether this directory should be included
|
// IncludeDirectory returns a function which checks whether this
|
||||||
// in the sync or not.
|
// directory should be included in the sync or not.
|
||||||
func (f *Filter) IncludeDirectory(remote string) bool {
|
func (f *Filter) IncludeDirectory(fs Fs) func(string) (bool, error) {
|
||||||
remote = strings.Trim(remote, "/")
|
return func(remote string) (bool, error) {
|
||||||
// filesFrom takes precedence
|
remote = strings.Trim(remote, "/")
|
||||||
if f.files != nil {
|
// first check if we need to remove directory based on
|
||||||
_, include := f.dirs[remote]
|
// the exclude file
|
||||||
return include
|
excl, err := f.DirContainsExcludeFile(fs, remote)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if excl {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// filesFrom takes precedence
|
||||||
|
if f.files != nil {
|
||||||
|
_, include := f.dirs[remote]
|
||||||
|
return include, nil
|
||||||
|
}
|
||||||
|
remote += "/"
|
||||||
|
for _, rule := range f.dirRules.rules {
|
||||||
|
if rule.Match(remote) {
|
||||||
|
return rule.Include, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
remote += "/"
|
}
|
||||||
for _, rule := range f.dirRules.rules {
|
|
||||||
if rule.Match(remote) {
|
// DirContainsExcludeFile checks if exclude file is present in a
|
||||||
return rule.Include
|
// directroy. If fs is nil, it works properly if ExcludeFile is an
|
||||||
|
// empty string (for testing).
|
||||||
|
func (f *Filter) DirContainsExcludeFile(fs Fs, remote string) (bool, error) {
|
||||||
|
if len(Config.Filter.ExcludeFile) > 0 {
|
||||||
|
exists, err := FileExists(fs, path.Join(remote, Config.Filter.ExcludeFile))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include returns whether this object should be included into the
|
// Include returns whether this object should be included into the
|
||||||
|
|
|
@ -164,7 +164,8 @@ type includeDirTest struct {
|
||||||
|
|
||||||
func testDirInclude(t *testing.T, f *Filter, tests []includeDirTest) {
|
func testDirInclude(t *testing.T, f *Filter, tests []includeDirTest) {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
got := f.IncludeDirectory(test.in)
|
got, err := f.IncludeDirectory(nil)(test.in)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, test.want, got, test.in)
|
assert.Equal(t, test.want, got, test.in)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -622,17 +622,20 @@ func ListDirSorted(fs Fs, includeAll bool, dir string) (entries DirEntries, err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// This should happen only if exclude files lives in the
|
||||||
|
// starting directory, otherwise ListDirSorted should not be
|
||||||
|
// called.
|
||||||
if !includeAll && Config.Filter.ListContainsExcludeFile(entries) {
|
if !includeAll && Config.Filter.ListContainsExcludeFile(entries) {
|
||||||
Debugf(dir, "Excluded from sync (and deletion) based on exclude file")
|
Debugf(dir, "Excluded from sync (and deletion)")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return filterAndSortDir(entries, includeAll, dir, Config.Filter.IncludeObject, Config.Filter.IncludeDirectory)
|
return filterAndSortDir(entries, includeAll, dir, Config.Filter.IncludeObject, Config.Filter.IncludeDirectory(fs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter (if required) and check the entries, then sort them
|
// filter (if required) and check the entries, then sort them
|
||||||
func filterAndSortDir(entries DirEntries, includeAll bool, dir string,
|
func filterAndSortDir(entries DirEntries, includeAll bool, dir string,
|
||||||
IncludeObject func(o Object) bool,
|
IncludeObject func(o Object) bool,
|
||||||
IncludeDirectory func(remote string) bool) (newEntries DirEntries, err error) {
|
IncludeDirectory func(remote string) (bool, error)) (newEntries DirEntries, err error) {
|
||||||
newEntries = entries[:0] // in place filter
|
newEntries = entries[:0] // in place filter
|
||||||
prefix := ""
|
prefix := ""
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
|
@ -649,9 +652,15 @@ func filterAndSortDir(entries DirEntries, includeAll bool, dir string,
|
||||||
Debugf(x, "Excluded from sync (and deletion)")
|
Debugf(x, "Excluded from sync (and deletion)")
|
||||||
}
|
}
|
||||||
case Directory:
|
case Directory:
|
||||||
if !includeAll && !IncludeDirectory(x.Remote()) {
|
if !includeAll {
|
||||||
ok = false
|
include, err := IncludeDirectory(x.Remote())
|
||||||
Debugf(x, "Excluded from sync (and deletion)")
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !include {
|
||||||
|
ok = false
|
||||||
|
Debugf(x, "Excluded from sync (and deletion)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, errors.Errorf("unknown object type %T", entry)
|
return nil, errors.Errorf("unknown object type %T", entry)
|
||||||
|
|
|
@ -22,8 +22,8 @@ func TestFilterAndSortIncludeAll(t *testing.T) {
|
||||||
includeObject := func(o Object) bool {
|
includeObject := func(o Object) bool {
|
||||||
return o != oB
|
return o != oB
|
||||||
}
|
}
|
||||||
includeDirectory := func(remote string) bool {
|
includeDirectory := func(remote string) (bool, error) {
|
||||||
return remote != "c"
|
return remote != "c", nil
|
||||||
}
|
}
|
||||||
// no filter
|
// no filter
|
||||||
newEntries, err := filterAndSortDir(entries, true, "", includeObject, includeDirectory)
|
newEntries, err := filterAndSortDir(entries, true, "", includeObject, includeDirectory)
|
||||||
|
|
23
fs/walk.go
23
fs/walk.go
|
@ -349,6 +349,10 @@ func (dt DirTree) String() string {
|
||||||
|
|
||||||
func walkRDirTree(f Fs, startPath string, includeAll bool, maxLevel int, listR ListRFn) (DirTree, error) {
|
func walkRDirTree(f Fs, startPath string, includeAll bool, maxLevel int, listR ListRFn) (DirTree, error) {
|
||||||
dirs := make(DirTree)
|
dirs := make(DirTree)
|
||||||
|
// Entries can come in arbitrary order. We use toPrune to keep
|
||||||
|
// all directories to exclude later.
|
||||||
|
toPrune := make(map[string]bool)
|
||||||
|
includeDirectory := Config.Filter.IncludeDirectory(f)
|
||||||
var mu sync.Mutex
|
var mu sync.Mutex
|
||||||
err := listR(startPath, func(entries DirEntries) error {
|
err := listR(startPath, func(entries DirEntries) error {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
|
@ -372,8 +376,21 @@ func walkRDirTree(f Fs, startPath string, includeAll bool, maxLevel int, listR L
|
||||||
} else {
|
} else {
|
||||||
Debugf(x, "Excluded from sync (and deletion)")
|
Debugf(x, "Excluded from sync (and deletion)")
|
||||||
}
|
}
|
||||||
|
// Check if we need to prune a directory later.
|
||||||
|
if !includeAll && len(Config.Filter.ExcludeFile) > 0 {
|
||||||
|
basename := path.Base(x.Remote())
|
||||||
|
if basename == Config.Filter.ExcludeFile {
|
||||||
|
excludeDir := parentDir(x.Remote())
|
||||||
|
toPrune[excludeDir] = true
|
||||||
|
Debugf(basename, "Excluded from sync (and deletion) based on exclude file")
|
||||||
|
}
|
||||||
|
}
|
||||||
case Directory:
|
case Directory:
|
||||||
if includeAll || Config.Filter.IncludeDirectory(x.Remote()) {
|
inc, err := includeDirectory(x.Remote())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if includeAll || inc {
|
||||||
if maxLevel < 0 || slashes <= maxLevel-1 {
|
if maxLevel < 0 || slashes <= maxLevel-1 {
|
||||||
if slashes == maxLevel-1 {
|
if slashes == maxLevel-1 {
|
||||||
// Just add the object if at maxLevel
|
// Just add the object if at maxLevel
|
||||||
|
@ -398,6 +415,10 @@ func walkRDirTree(f Fs, startPath string, includeAll bool, maxLevel int, listR L
|
||||||
if len(dirs) == 0 {
|
if len(dirs) == 0 {
|
||||||
dirs[startPath] = nil
|
dirs[startPath] = nil
|
||||||
}
|
}
|
||||||
|
err = dirs.Prune(toPrune)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
dirs.Sort()
|
dirs.Sort()
|
||||||
return dirs, nil
|
return dirs, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue