restic/internal/walker/rewriter.go

85 lines
2.2 KiB
Go
Raw Normal View History

2022-09-06 20:30:45 +00:00
package walker
import (
"context"
"fmt"
2022-09-06 20:30:45 +00:00
"path"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/restic"
)
// SelectByNameFunc returns true for all items that should be included (files and
// dirs). If false is returned, files are ignored and dirs are not even walked.
type SelectByNameFunc func(item string) bool
2022-09-06 20:30:45 +00:00
type TreeFilterVisitor struct {
SelectByName SelectByNameFunc
2022-09-06 20:30:45 +00:00
PrintExclude func(string)
}
2022-10-14 21:26:13 +00:00
type BlobLoadSaver interface {
restic.BlobSaver
restic.BlobLoader
}
func FilterTree(ctx context.Context, repo BlobLoadSaver, nodepath string, nodeID restic.ID, visitor *TreeFilterVisitor) (newNodeID restic.ID, err error) {
2022-09-06 20:30:45 +00:00
curTree, err := restic.LoadTree(ctx, repo, nodeID)
if err != nil {
return restic.ID{}, err
}
// check that we can properly encode this tree without losing information
// The alternative of using json/Decoder.DisallowUnknownFields() doesn't work as we use
// a custom UnmarshalJSON to decode trees, see also https://github.com/golang/go/issues/41144
testID, err := restic.SaveTree(ctx, repo, curTree)
if err != nil {
return restic.ID{}, err
}
if nodeID != testID {
2023-04-23 09:38:06 +00:00
return restic.ID{}, fmt.Errorf("cannot encode tree at %q without losing information", nodepath)
}
2022-09-06 20:30:45 +00:00
debug.Log("filterTree: %s, nodeId: %s\n", nodepath, nodeID.Str())
tb := restic.NewTreeJSONBuilder()
for _, node := range curTree.Nodes {
path := path.Join(nodepath, node.Name)
if !visitor.SelectByName(path) {
2022-09-06 20:30:45 +00:00
if visitor.PrintExclude != nil {
visitor.PrintExclude(path)
}
continue
}
if node.Type != "dir" {
2022-09-06 20:30:45 +00:00
err = tb.AddNode(node)
if err != nil {
return restic.ID{}, err
}
continue
}
newID, err := FilterTree(ctx, repo, path, *node.Subtree, visitor)
if err != nil {
return restic.ID{}, err
}
node.Subtree = &newID
err = tb.AddNode(node)
if err != nil {
return restic.ID{}, err
}
}
tree, err := tb.Finalize()
if err != nil {
return restic.ID{}, err
}
2022-09-06 20:30:45 +00:00
// Save new tree
newTreeID, _, _, err := repo.SaveBlob(ctx, restic.TreeBlob, tree, restic.ID{}, false)
if !newTreeID.Equal(nodeID) {
2022-09-06 20:30:45 +00:00
debug.Log("filterTree: save new tree for %s as %v\n", nodepath, newTreeID)
}
return newTreeID, err
2022-09-06 20:30:45 +00:00
}