walker: add callback to inform about leaving a directory

This commit is contained in:
Michael Eischer
2024-01-20 23:36:08 +01:00
parent b2703a4089
commit 9ecbda059c
6 changed files with 34 additions and 16 deletions

View File

@@ -70,7 +70,7 @@ func sendNodes(ctx context.Context, repo restic.Repository, root *restic.Node, c
return nil
}
err := walker.Walk(ctx, repo, *root.Subtree, func(_ restic.ID, nodepath string, node *restic.Node, err error) error {
err := walker.Walk(ctx, repo, *root.Subtree, walker.WalkVisitor{ProcessNode: func(_ restic.ID, nodepath string, node *restic.Node, err error) error {
if err != nil {
return err
}
@@ -91,7 +91,7 @@ func sendNodes(ctx context.Context, repo restic.Repository, root *restic.Node, c
}
return nil
})
}})
return err
}

View File

@@ -23,12 +23,20 @@ var ErrSkipNode = errors.New("skip this node")
// tree are skipped.
type WalkFunc func(parentTreeID restic.ID, path string, node *restic.Node, nodeErr error) (err error)
type WalkVisitor struct {
// If the node is a `dir`, it will be entered afterwards unless `ErrSkipNode`
// was returned. This function is mandatory
ProcessNode WalkFunc
// Optional callback
LeaveDir func(path string)
}
// Walk calls walkFn recursively for each node in root. If walkFn returns an
// error, it is passed up the call stack. The trees in ignoreTrees are not
// walked. If walkFn ignores trees, these are added to the set.
func Walk(ctx context.Context, repo restic.BlobLoader, root restic.ID, walkFn WalkFunc) error {
func Walk(ctx context.Context, repo restic.BlobLoader, root restic.ID, visitor WalkVisitor) error {
tree, err := restic.LoadTree(ctx, repo, root)
err = walkFn(root, "/", nil, err)
err = visitor.ProcessNode(root, "/", nil, err)
if err != nil {
if err == ErrSkipNode {
@@ -37,13 +45,13 @@ func Walk(ctx context.Context, repo restic.BlobLoader, root restic.ID, walkFn Wa
return err
}
return walk(ctx, repo, "/", root, tree, walkFn)
return walk(ctx, repo, "/", root, tree, visitor)
}
// walk recursively traverses the tree, ignoring subtrees when the ID of the
// subtree is in ignoreTrees. If err is nil and ignore is true, the subtree ID
// will be added to ignoreTrees by walk.
func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTreeID restic.ID, tree *restic.Tree, walkFn WalkFunc) (err error) {
func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTreeID restic.ID, tree *restic.Tree, visitor WalkVisitor) (err error) {
sort.Slice(tree.Nodes, func(i, j int) bool {
return tree.Nodes[i].Name < tree.Nodes[j].Name
})
@@ -56,7 +64,7 @@ func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTree
}
if node.Type != "dir" {
err := walkFn(parentTreeID, p, node, nil)
err := visitor.ProcessNode(parentTreeID, p, node, nil)
if err != nil {
if err == ErrSkipNode {
// skip the remaining entries in this tree
@@ -74,18 +82,22 @@ func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTree
}
subtree, err := restic.LoadTree(ctx, repo, *node.Subtree)
err = walkFn(parentTreeID, p, node, err)
err = visitor.ProcessNode(parentTreeID, p, node, err)
if err != nil {
if err == ErrSkipNode {
continue
}
}
err = walk(ctx, repo, p, *node.Subtree, subtree, walkFn)
err = walk(ctx, repo, p, *node.Subtree, subtree, visitor)
if err != nil {
return err
}
}
if visitor.LeaveDir != nil {
visitor.LeaveDir(prefix)
}
return nil
}

View File

@@ -406,7 +406,7 @@ func TestWalker(t *testing.T) {
defer cancel()
fn, last := check(t)
err := Walk(ctx, repo, root, fn)
err := Walk(ctx, repo, root, WalkVisitor{ProcessNode: fn})
if err != nil {
t.Error(err)
}