mirror of
https://github.com/rclone/rclone.git
synced 2026-01-06 18:43:50 +00:00
drive: constrain list by filter #5023
Google Drive API allows for clauses like "modifiedTime > '2012-06-04T12:00:00'" in the query param, so the filter flags --max-age and --min-age can be applied directly at the directory listing phase rather than in a filter. This is extremely helpful when we want to do an incremental backup of a remote drive with many files but the number of recently changed file is small. Co-authored-by: fotile96 <fotile96@users.noreply.github.com>
This commit is contained in:
@@ -598,9 +598,9 @@ func (f *Filter) UsesDirectoryFilters() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Context key for config
|
||||
type configContextKeyType struct{}
|
||||
|
||||
// Context key for config
|
||||
var configContextKey = configContextKeyType{}
|
||||
|
||||
// GetConfig returns the global or context sensitive config
|
||||
@@ -645,3 +645,29 @@ func ReplaceConfig(ctx context.Context, f *Filter) context.Context {
|
||||
newCtx := context.WithValue(ctx, configContextKey, f)
|
||||
return newCtx
|
||||
}
|
||||
|
||||
// Context key for the "use filter" flag
|
||||
type useFlagContextKeyType struct{}
|
||||
|
||||
var useFlagContextKey = useFlagContextKeyType{}
|
||||
|
||||
// GetUseFilter obtains the "use filter" flag from context
|
||||
// The flag tells filter-aware backends (Drive) to constrain List using filter
|
||||
func GetUseFilter(ctx context.Context) bool {
|
||||
if ctx != nil {
|
||||
if pVal := ctx.Value(useFlagContextKey); pVal != nil {
|
||||
return *(pVal.(*bool))
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetUseFilter returns a context having (re)set the "use filter" flag
|
||||
func SetUseFilter(ctx context.Context, useFilter bool) context.Context {
|
||||
if useFilter == GetUseFilter(ctx) {
|
||||
return ctx // Minimize depth of nested contexts
|
||||
}
|
||||
pVal := new(bool)
|
||||
*pVal = useFilter
|
||||
return context.WithValue(ctx, useFlagContextKey, pVal)
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type Marcher interface {
|
||||
}
|
||||
|
||||
// init sets up a march over opt.Fsrc, and opt.Fdst calling back callback for each match
|
||||
// Note: this will flag filter-aware backends on the source side
|
||||
func (m *March) init(ctx context.Context) {
|
||||
ci := fs.GetConfig(ctx)
|
||||
m.srcListDir = m.makeListDir(ctx, m.Fsrc, m.SrcIncludeAll)
|
||||
@@ -76,13 +77,15 @@ type listDirFn func(dir string) (entries fs.DirEntries, err error)
|
||||
|
||||
// makeListDir makes constructs a listing function for the given fs
|
||||
// and includeAll flags for marching through the file system.
|
||||
// Note: this will optionally flag filter-aware backends!
|
||||
func (m *March) makeListDir(ctx context.Context, f fs.Fs, includeAll bool) listDirFn {
|
||||
ci := fs.GetConfig(ctx)
|
||||
fi := filter.GetConfig(ctx)
|
||||
if !(ci.UseListR && f.Features().ListR != nil) && // !--fast-list active and
|
||||
!(ci.NoTraverse && fi.HaveFilesFrom()) { // !(--files-from and --no-traverse)
|
||||
return func(dir string) (entries fs.DirEntries, err error) {
|
||||
return list.DirSorted(m.Ctx, f, includeAll, dir)
|
||||
dirCtx := filter.SetUseFilter(m.Ctx, !includeAll) // make filter-aware backends constrain List
|
||||
return list.DirSorted(dirCtx, f, includeAll, dir)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +101,8 @@ func (m *March) makeListDir(ctx context.Context, f fs.Fs, includeAll bool) listD
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if !started {
|
||||
dirs, dirsErr = walk.NewDirTree(m.Ctx, f, m.Dir, includeAll, ci.MaxDepth)
|
||||
dirCtx := filter.SetUseFilter(m.Ctx, !includeAll) // make filter-aware backends constrain List
|
||||
dirs, dirsErr = walk.NewDirTree(dirCtx, f, m.Dir, includeAll, ci.MaxDepth)
|
||||
started = true
|
||||
}
|
||||
if dirsErr != nil {
|
||||
|
||||
@@ -57,10 +57,13 @@ type Func func(path string, entries fs.DirEntries, err error) error
|
||||
// If --files-from and --no-traverse is set then a DirTree will be
|
||||
// constructed with just those files in and then walked with WalkR
|
||||
//
|
||||
// Note: this will flag filter-aware backends!
|
||||
//
|
||||
// NB (f, path) to be replaced by fs.Dir at some point
|
||||
func Walk(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLevel int, fn Func) error {
|
||||
ci := fs.GetConfig(ctx)
|
||||
fi := filter.GetConfig(ctx)
|
||||
ctx = filter.SetUseFilter(ctx, !includeAll) // make filter-aware backends constrain List
|
||||
if ci.NoTraverse && fi.HaveFilesFrom() {
|
||||
return walkR(ctx, f, path, includeAll, maxLevel, fn, fi.MakeListR(ctx, f.NewObject))
|
||||
}
|
||||
@@ -138,6 +141,8 @@ func (l ListType) Filter(in *fs.DirEntries) {
|
||||
// This is implemented by using ListR on the backend if possible and
|
||||
// efficient, otherwise by Walk.
|
||||
//
|
||||
// Note: this will flag filter-aware backends
|
||||
//
|
||||
// NB (f, path) to be replaced by fs.Dir at some point
|
||||
func ListR(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLevel int, listType ListType, fn fs.ListRCallback) error {
|
||||
fi := filter.GetConfig(ctx)
|
||||
@@ -152,10 +157,12 @@ func ListR(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLevel
|
||||
fi.UsesDirectoryFilters() { // ...using any directory filters
|
||||
return listRwalk(ctx, f, path, includeAll, maxLevel, listType, fn)
|
||||
}
|
||||
ctx = filter.SetUseFilter(ctx, !includeAll) // make filter-aware backends constrain List
|
||||
return listR(ctx, f, path, includeAll, listType, fn, doListR, listType.Dirs() && f.Features().BucketBased)
|
||||
}
|
||||
|
||||
// listRwalk walks the file tree for ListR using Walk
|
||||
// Note: this will flag filter-aware backends (via Walk)
|
||||
func listRwalk(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLevel int, listType ListType, fn fs.ListRCallback) error {
|
||||
var listErr error
|
||||
walkErr := Walk(ctx, f, path, includeAll, maxLevel, func(path string, entries fs.DirEntries, err error) error {
|
||||
|
||||
Reference in New Issue
Block a user