data: split node and snapshot code from restic package

This commit is contained in:
Michael Eischer
2025-09-23 20:01:09 +02:00
parent c85b157e0e
commit 56ac8360c7
166 changed files with 1170 additions and 1107 deletions

View File

@@ -19,6 +19,7 @@ import (
"golang.org/x/sync/errgroup"
"github.com/restic/restic/internal/archiver"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/filter"
@@ -76,7 +77,7 @@ type BackupOptions struct {
filter.ExcludePatternOptions
Parent string
GroupBy restic.SnapshotGroupByOptions
GroupBy data.SnapshotGroupByOptions
Force bool
ExcludeOtherFS bool
ExcludeIfPresent []string
@@ -86,7 +87,7 @@ type BackupOptions struct {
Stdin bool
StdinFilename string
StdinCommand bool
Tags restic.TagLists
Tags data.TagLists
Host string
FilesFrom []string
FilesFromVerbatim []string
@@ -104,7 +105,7 @@ type BackupOptions struct {
func (opts *BackupOptions) AddFlags(f *pflag.FlagSet) {
f.StringVar(&opts.Parent, "parent", "", "use this parent `snapshot` (default: latest snapshot in the group determined by --group-by and not newer than the timestamp determined by --time)")
opts.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
opts.GroupBy = data.SnapshotGroupByOptions{Host: true, Path: true}
f.VarP(&opts.GroupBy, "group-by", "g", "`group` snapshots by host, paths and/or tags, separated by comma (disable grouping with '')")
f.BoolVarP(&opts.Force, "force", "f", false, `force re-reading the source files/directories (overrides the "parent" flag)`)
@@ -446,7 +447,7 @@ func collectTargets(opts BackupOptions, args []string, warnf func(msg string, ar
// parent returns the ID of the parent snapshot. If there is none, nil is
// returned.
func findParentSnapshot(ctx context.Context, repo restic.ListerLoaderUnpacked, opts BackupOptions, targets []string, timeStampLimit time.Time) (*restic.Snapshot, error) {
func findParentSnapshot(ctx context.Context, repo restic.ListerLoaderUnpacked, opts BackupOptions, targets []string, timeStampLimit time.Time) (*data.Snapshot, error) {
if opts.Force {
return nil, nil
}
@@ -455,7 +456,7 @@ func findParentSnapshot(ctx context.Context, repo restic.ListerLoaderUnpacked, o
if snName == "" {
snName = "latest"
}
f := restic.SnapshotFilter{TimestampLimit: timeStampLimit}
f := data.SnapshotFilter{TimestampLimit: timeStampLimit}
if opts.GroupBy.Host {
f.Hosts = []string{opts.Host}
}
@@ -463,12 +464,12 @@ func findParentSnapshot(ctx context.Context, repo restic.ListerLoaderUnpacked, o
f.Paths = targets
}
if opts.GroupBy.Tag {
f.Tags = []restic.TagList{opts.Tags.Flatten()}
f.Tags = []data.TagList{opts.Tags.Flatten()}
}
sn, _, err := f.FindLatest(ctx, repo, repo, snName)
// Snapshot not found is ok if no explicit parent was set
if opts.Parent == "" && errors.Is(err, restic.ErrNoSnapshotFound) {
if opts.Parent == "" && errors.Is(err, data.ErrNoSnapshotFound) {
err = nil
}
return sn, err
@@ -529,7 +530,7 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
return err
}
var parentSnapshot *restic.Snapshot
var parentSnapshot *data.Snapshot
if !opts.Stdin {
parentSnapshot, err = findParentSnapshot(ctx, repo, opts, targets, timeStamp)
if err != nil {

View File

@@ -9,6 +9,7 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
@@ -22,7 +23,7 @@ func testRunBackupAssumeFailure(t testing.TB, dir string, target []string, opts
defer cleanup()
}
opts.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
opts.GroupBy = data.SnapshotGroupByOptions{Host: true, Path: true}
return runBackup(ctx, opts, gopts, gopts.term, target)
})
}
@@ -473,7 +474,7 @@ func TestBackupTags(t *testing.T) {
"expected no tags, got %v", newest.Tags)
parent := newest
opts.Tags = restic.TagLists{[]string{"NL"}}
opts.Tags = data.TagLists{[]string{"NL"}}
testRunBackup(t, "", []string{env.testdata}, opts, env.gopts)
testRunCheck(t, env.gopts)
newest, _ = testRunSnapshots(t, env.gopts)

View File

@@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
@@ -105,7 +106,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string, term ui.Ter
printer.S(string(buf))
return nil
case "snapshot":
sn, _, err := restic.FindSnapshot(ctx, repo, repo, args[1])
sn, _, err := data.FindSnapshot(ctx, repo, repo, args[1])
if err != nil {
return errors.Fatalf("could not find snapshot: %v", err)
}
@@ -190,7 +191,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string, term ui.Ter
return errors.Fatal("blob not found")
case "tree":
sn, subfolder, err := restic.FindSnapshot(ctx, repo, repo, args[1])
sn, subfolder, err := data.FindSnapshot(ctx, repo, repo, args[1])
if err != nil {
return errors.Fatalf("could not find snapshot: %v", err)
}
@@ -200,7 +201,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string, term ui.Ter
return err
}
sn.Tree, err = restic.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
sn.Tree, err = data.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
if err != nil {
return err
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
@@ -59,7 +60,7 @@ Exit status is 12 if the password is incorrect.
// CopyOptions bundles all options for the copy command.
type CopyOptions struct {
secondaryRepoOptions
restic.SnapshotFilter
data.SnapshotFilter
}
func (opts *CopyOptions) AddFlags(f *pflag.FlagSet) {
@@ -109,7 +110,7 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
return err
}
dstSnapshotByOriginal := make(map[restic.ID][]*restic.Snapshot)
dstSnapshotByOriginal := make(map[restic.ID][]*data.Snapshot)
for sn := range FindFilteredSnapshots(ctx, dstSnapshotLister, dstRepo, &opts.SnapshotFilter, nil, printer) {
if sn.Original != nil && !sn.Original.IsNull() {
dstSnapshotByOriginal[*sn.Original] = append(dstSnapshotByOriginal[*sn.Original], sn)
@@ -158,7 +159,7 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
if sn.Original == nil {
sn.Original = sn.ID()
}
newID, err := restic.SaveSnapshot(ctx, dstRepo, sn)
newID, err := data.SaveSnapshot(ctx, dstRepo, sn)
if err != nil {
return err
}
@@ -167,7 +168,7 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
return ctx.Err()
}
func similarSnapshots(sna *restic.Snapshot, snb *restic.Snapshot) bool {
func similarSnapshots(sna *data.Snapshot, snb *data.Snapshot) bool {
// everything except Parent and Original must match
if !sna.Time.Equal(snb.Time) || !sna.Tree.Equal(*snb.Tree) || sna.Hostname != snb.Hostname ||
sna.Username != snb.Username || sna.UID != snb.UID || sna.GID != snb.GID ||
@@ -191,7 +192,7 @@ func copyTree(ctx context.Context, srcRepo restic.Repository, dstRepo restic.Rep
wg, wgCtx := errgroup.WithContext(ctx)
treeStream := restic.StreamTrees(wgCtx, wg, srcRepo, restic.IDs{rootTreeID}, func(treeID restic.ID) bool {
treeStream := data.StreamTrees(wgCtx, wg, srcRepo, restic.IDs{rootTreeID}, func(treeID restic.ID) bool {
visited := visitedTrees.Has(treeID)
visitedTrees.Insert(treeID)
return visited

View File

@@ -22,6 +22,7 @@ import (
"golang.org/x/sync/errgroup"
"github.com/restic/restic/internal/crypto"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/repository/index"
@@ -115,7 +116,7 @@ func prettyPrintJSON(wr io.Writer, item interface{}) error {
}
func debugPrintSnapshots(ctx context.Context, repo *repository.Repository, wr io.Writer) error {
return restic.ForAllSnapshots(ctx, repo, repo, nil, func(id restic.ID, snapshot *restic.Snapshot, err error) error {
return data.ForAllSnapshots(ctx, repo, repo, nil, func(id restic.ID, snapshot *data.Snapshot, err error) error {
if err != nil {
return err
}

View File

@@ -7,6 +7,7 @@ import (
"reflect"
"sort"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
@@ -69,8 +70,8 @@ func (opts *DiffOptions) AddFlags(f *pflag.FlagSet) {
f.BoolVar(&opts.ShowMetadata, "metadata", false, "print changes in metadata")
}
func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.LoaderUnpacked, desc string) (*restic.Snapshot, string, error) {
sn, subfolder, err := restic.FindSnapshot(ctx, be, repo, desc)
func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.LoaderUnpacked, desc string) (*data.Snapshot, string, error) {
sn, subfolder, err := data.FindSnapshot(ctx, be, repo, desc)
if err != nil {
return nil, "", errors.Fatalf("%s", err)
}
@@ -106,15 +107,15 @@ type DiffStat struct {
}
// Add adds stats information for node to s.
func (s *DiffStat) Add(node *restic.Node) {
func (s *DiffStat) Add(node *data.Node) {
if node == nil {
return
}
switch node.Type {
case restic.NodeTypeFile:
case data.NodeTypeFile:
s.Files++
case restic.NodeTypeDir:
case data.NodeTypeDir:
s.Dirs++
default:
s.Others++
@@ -122,13 +123,13 @@ func (s *DiffStat) Add(node *restic.Node) {
}
// addBlobs adds the blobs of node to s.
func addBlobs(bs restic.BlobSet, node *restic.Node) {
func addBlobs(bs restic.BlobSet, node *data.Node) {
if node == nil {
return
}
switch node.Type {
case restic.NodeTypeFile:
case data.NodeTypeFile:
for _, blob := range node.Content {
h := restic.BlobHandle{
ID: blob,
@@ -136,7 +137,7 @@ func addBlobs(bs restic.BlobSet, node *restic.Node) {
}
bs.Insert(h)
}
case restic.NodeTypeDir:
case data.NodeTypeDir:
h := restic.BlobHandle{
ID: *node.Subtree,
Type: restic.TreeBlob,
@@ -177,7 +178,7 @@ func updateBlobs(repo restic.Loader, blobs restic.BlobSet, stats *DiffStat, prin
func (c *Comparer) printDir(ctx context.Context, mode string, stats *DiffStat, blobs restic.BlobSet, prefix string, id restic.ID) error {
debug.Log("print %v tree %v", mode, id)
tree, err := restic.LoadTree(ctx, c.repo, id)
tree, err := data.LoadTree(ctx, c.repo, id)
if err != nil {
return err
}
@@ -188,14 +189,14 @@ func (c *Comparer) printDir(ctx context.Context, mode string, stats *DiffStat, b
}
name := path.Join(prefix, node.Name)
if node.Type == restic.NodeTypeDir {
if node.Type == data.NodeTypeDir {
name += "/"
}
c.printChange(NewChange(name, mode))
stats.Add(node)
addBlobs(blobs, node)
if node.Type == restic.NodeTypeDir {
if node.Type == data.NodeTypeDir {
err := c.printDir(ctx, mode, stats, blobs, name, *node.Subtree)
if err != nil && err != context.Canceled {
c.printError("error: %v", err)
@@ -208,7 +209,7 @@ func (c *Comparer) printDir(ctx context.Context, mode string, stats *DiffStat, b
func (c *Comparer) collectDir(ctx context.Context, blobs restic.BlobSet, id restic.ID) error {
debug.Log("print tree %v", id)
tree, err := restic.LoadTree(ctx, c.repo, id)
tree, err := data.LoadTree(ctx, c.repo, id)
if err != nil {
return err
}
@@ -220,7 +221,7 @@ func (c *Comparer) collectDir(ctx context.Context, blobs restic.BlobSet, id rest
addBlobs(blobs, node)
if node.Type == restic.NodeTypeDir {
if node.Type == data.NodeTypeDir {
err := c.collectDir(ctx, blobs, *node.Subtree)
if err != nil && err != context.Canceled {
c.printError("error: %v", err)
@@ -231,15 +232,15 @@ func (c *Comparer) collectDir(ctx context.Context, blobs restic.BlobSet, id rest
return ctx.Err()
}
func uniqueNodeNames(tree1, tree2 *restic.Tree) (tree1Nodes, tree2Nodes map[string]*restic.Node, uniqueNames []string) {
func uniqueNodeNames(tree1, tree2 *data.Tree) (tree1Nodes, tree2Nodes map[string]*data.Node, uniqueNames []string) {
names := make(map[string]struct{})
tree1Nodes = make(map[string]*restic.Node)
tree1Nodes = make(map[string]*data.Node)
for _, node := range tree1.Nodes {
tree1Nodes[node.Name] = node
names[node.Name] = struct{}{}
}
tree2Nodes = make(map[string]*restic.Node)
tree2Nodes = make(map[string]*data.Node)
for _, node := range tree2.Nodes {
tree2Nodes[node.Name] = node
names[node.Name] = struct{}{}
@@ -256,12 +257,12 @@ func uniqueNodeNames(tree1, tree2 *restic.Tree) (tree1Nodes, tree2Nodes map[stri
func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, prefix string, id1, id2 restic.ID) error {
debug.Log("diffing %v to %v", id1, id2)
tree1, err := restic.LoadTree(ctx, c.repo, id1)
tree1, err := data.LoadTree(ctx, c.repo, id1)
if err != nil {
return err
}
tree2, err := restic.LoadTree(ctx, c.repo, id2)
tree2, err := data.LoadTree(ctx, c.repo, id2)
if err != nil {
return err
}
@@ -288,12 +289,12 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref
mod += "T"
}
if node2.Type == restic.NodeTypeDir {
if node2.Type == data.NodeTypeDir {
name += "/"
}
if node1.Type == restic.NodeTypeFile &&
node2.Type == restic.NodeTypeFile &&
if node1.Type == data.NodeTypeFile &&
node2.Type == data.NodeTypeFile &&
!reflect.DeepEqual(node1.Content, node2.Content) {
mod += "M"
stats.ChangedFiles++
@@ -315,7 +316,7 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref
c.printChange(NewChange(name, mod))
}
if node1.Type == restic.NodeTypeDir && node2.Type == restic.NodeTypeDir {
if node1.Type == data.NodeTypeDir && node2.Type == data.NodeTypeDir {
var err error
if (*node1.Subtree).Equal(*node2.Subtree) {
err = c.collectDir(ctx, stats.BlobsCommon, *node1.Subtree)
@@ -328,13 +329,13 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref
}
case t1 && !t2:
prefix := path.Join(prefix, name)
if node1.Type == restic.NodeTypeDir {
if node1.Type == data.NodeTypeDir {
prefix += "/"
}
c.printChange(NewChange(prefix, "-"))
stats.Removed.Add(node1)
if node1.Type == restic.NodeTypeDir {
if node1.Type == data.NodeTypeDir {
err := c.printDir(ctx, "-", &stats.Removed, stats.BlobsBefore, prefix, *node1.Subtree)
if err != nil && err != context.Canceled {
c.printError("error: %v", err)
@@ -342,13 +343,13 @@ func (c *Comparer) diffTree(ctx context.Context, stats *DiffStatsContainer, pref
}
case !t1 && t2:
prefix := path.Join(prefix, name)
if node2.Type == restic.NodeTypeDir {
if node2.Type == data.NodeTypeDir {
prefix += "/"
}
c.printChange(NewChange(prefix, "+"))
stats.Added.Add(node2)
if node2.Type == restic.NodeTypeDir {
if node2.Type == data.NodeTypeDir {
err := c.printDir(ctx, "+", &stats.Added, stats.BlobsAfter, prefix, *node2.Subtree)
if err != nil && err != context.Canceled {
c.printError("error: %v", err)
@@ -403,12 +404,12 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
return errors.Errorf("snapshot %v has nil tree", sn2.ID().Str())
}
sn1.Tree, err = restic.FindTreeDirectory(ctx, repo, sn1.Tree, subfolder1)
sn1.Tree, err = data.FindTreeDirectory(ctx, repo, sn1.Tree, subfolder1)
if err != nil {
return err
}
sn2.Tree, err = restic.FindTreeDirectory(ctx, repo, sn2.Tree, subfolder2)
sn2.Tree, err = data.FindTreeDirectory(ctx, repo, sn2.Tree, subfolder2)
if err != nil {
return err
}

View File

@@ -7,6 +7,7 @@ import (
"path"
"path/filepath"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/dump"
"github.com/restic/restic/internal/errors"
@@ -57,7 +58,7 @@ Exit status is 12 if the password is incorrect.
// DumpOptions collects all options for the dump command.
type DumpOptions struct {
restic.SnapshotFilter
data.SnapshotFilter
Archive string
Target string
}
@@ -77,7 +78,7 @@ func splitPath(p string) []string {
return append(s, f)
}
func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.BlobLoader, prefix string, pathComponents []string, d *dump.Dumper, canWriteArchiveFunc func() error) error {
func printFromTree(ctx context.Context, tree *data.Tree, repo restic.BlobLoader, prefix string, pathComponents []string, d *dump.Dumper, canWriteArchiveFunc func() error) error {
// If we print / we need to assume that there are multiple nodes at that
// level in the tree.
if pathComponents[0] == "" {
@@ -98,26 +99,26 @@ func printFromTree(ctx context.Context, tree *restic.Tree, repo restic.BlobLoade
// first item it finds and dump that according to the switch case below.
if node.Name == pathComponents[0] {
switch {
case l == 1 && node.Type == restic.NodeTypeFile:
case l == 1 && node.Type == data.NodeTypeFile:
return d.WriteNode(ctx, node)
case l > 1 && node.Type == restic.NodeTypeDir:
subtree, err := restic.LoadTree(ctx, repo, *node.Subtree)
case l > 1 && node.Type == data.NodeTypeDir:
subtree, err := data.LoadTree(ctx, repo, *node.Subtree)
if err != nil {
return errors.Wrapf(err, "cannot load subtree for %q", item)
}
return printFromTree(ctx, subtree, repo, item, pathComponents[1:], d, canWriteArchiveFunc)
case node.Type == restic.NodeTypeDir:
case node.Type == data.NodeTypeDir:
if err := canWriteArchiveFunc(); err != nil {
return err
}
subtree, err := restic.LoadTree(ctx, repo, *node.Subtree)
subtree, err := data.LoadTree(ctx, repo, *node.Subtree)
if err != nil {
return err
}
return d.DumpTree(ctx, subtree, item)
case l > 1:
return fmt.Errorf("%q should be a dir, but is a %q", item, node.Type)
case node.Type != restic.NodeTypeFile:
case node.Type != data.NodeTypeFile:
return fmt.Errorf("%q should be a file, but is a %q", item, node.Type)
}
}
@@ -151,7 +152,7 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []
}
defer unlock()
sn, subfolder, err := (&restic.SnapshotFilter{
sn, subfolder, err := (&data.SnapshotFilter{
Hosts: opts.Hosts,
Paths: opts.Paths,
Tags: opts.Tags,
@@ -165,12 +166,12 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []
return err
}
sn.Tree, err = restic.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
sn.Tree, err = data.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
if err != nil {
return err
}
tree, err := restic.LoadTree(ctx, repo, *sn.Tree)
tree, err := data.LoadTree(ctx, repo, *sn.Tree)
if err != nil {
return errors.Fatalf("loading tree for snapshot %q failed: %v", snapshotIDString, err)
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/filter"
@@ -70,7 +71,7 @@ type FindOptions struct {
ListLong bool
HumanReadable bool
Reverse bool
restic.SnapshotFilter
data.SnapshotFilter
}
func (opts *FindOptions) AddFlags(f *pflag.FlagSet) {
@@ -124,8 +125,8 @@ type statefulOutput struct {
HumanReadable bool
JSON bool
inuse bool
newsn *restic.Snapshot
oldsn *restic.Snapshot
newsn *data.Snapshot
oldsn *data.Snapshot
hits int
printer interface {
S(string, ...interface{})
@@ -135,8 +136,8 @@ type statefulOutput struct {
stdout io.Writer
}
func (s *statefulOutput) PrintPatternJSON(path string, node *restic.Node) {
type findNode restic.Node
func (s *statefulOutput) PrintPatternJSON(path string, node *data.Node) {
type findNode data.Node
b, err := json.Marshal(struct {
// Add these attributes
Path string `json:"path,omitempty"`
@@ -179,7 +180,7 @@ func (s *statefulOutput) PrintPatternJSON(path string, node *restic.Node) {
s.hits++
}
func (s *statefulOutput) PrintPatternNormal(path string, node *restic.Node) {
func (s *statefulOutput) PrintPatternNormal(path string, node *data.Node) {
if s.newsn != s.oldsn {
if s.oldsn != nil {
s.printer.P("")
@@ -190,7 +191,7 @@ func (s *statefulOutput) PrintPatternNormal(path string, node *restic.Node) {
s.printer.S(formatNode(path, node, s.ListLong, s.HumanReadable))
}
func (s *statefulOutput) PrintPattern(path string, node *restic.Node) {
func (s *statefulOutput) PrintPattern(path string, node *data.Node) {
if s.JSON {
s.PrintPatternJSON(path, node)
} else {
@@ -198,7 +199,7 @@ func (s *statefulOutput) PrintPattern(path string, node *restic.Node) {
}
}
func (s *statefulOutput) PrintObjectJSON(kind, id, nodepath, treeID string, sn *restic.Snapshot) {
func (s *statefulOutput) PrintObjectJSON(kind, id, nodepath, treeID string, sn *data.Snapshot) {
b, err := json.Marshal(struct {
// Add these attributes
ObjectType string `json:"object_type"`
@@ -230,7 +231,7 @@ func (s *statefulOutput) PrintObjectJSON(kind, id, nodepath, treeID string, sn *
s.hits++
}
func (s *statefulOutput) PrintObjectNormal(kind, id, nodepath, treeID string, sn *restic.Snapshot) {
func (s *statefulOutput) PrintObjectNormal(kind, id, nodepath, treeID string, sn *data.Snapshot) {
s.printer.S("Found %s %s", kind, id)
if kind == "blob" {
s.printer.S(" ... in file %s", nodepath)
@@ -241,7 +242,7 @@ func (s *statefulOutput) PrintObjectNormal(kind, id, nodepath, treeID string, sn
s.printer.S(" ... in snapshot %s (%s)", sn.ID().Str(), sn.Time.Local().Format(TimeFormat))
}
func (s *statefulOutput) PrintObject(kind, id, nodepath, treeID string, sn *restic.Snapshot) {
func (s *statefulOutput) PrintObject(kind, id, nodepath, treeID string, sn *data.Snapshot) {
if s.JSON {
s.PrintObjectJSON(kind, id, nodepath, treeID, sn)
} else {
@@ -279,7 +280,7 @@ type Finder struct {
}
}
func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error {
func (f *Finder) findInSnapshot(ctx context.Context, sn *data.Snapshot) error {
debug.Log("searching in snapshot %s\n for entries within [%s %s]", sn.ID(), f.pat.oldest, f.pat.newest)
if sn.Tree == nil {
@@ -287,7 +288,7 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error
}
f.out.newsn = sn
return walker.Walk(ctx, f.repo, *sn.Tree, walker.WalkVisitor{ProcessNode: func(parentTreeID restic.ID, nodepath string, node *restic.Node, err error) error {
return walker.Walk(ctx, f.repo, *sn.Tree, walker.WalkVisitor{ProcessNode: func(parentTreeID restic.ID, nodepath string, node *data.Node, err error) error {
if err != nil {
debug.Log("Error loading tree %v: %v", parentTreeID, err)
@@ -320,7 +321,7 @@ func (f *Finder) findInSnapshot(ctx context.Context, sn *restic.Snapshot) error
}
var errIfNoMatch error
if node.Type == restic.NodeTypeDir {
if node.Type == data.NodeTypeDir {
var childMayMatch bool
for _, pat := range f.pat.pattern {
mayMatch, err := filter.ChildMatch(pat, normalizedNodepath)
@@ -378,7 +379,7 @@ func (f *Finder) findTree(treeID restic.ID, nodepath string) error {
return nil
}
func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error {
func (f *Finder) findIDs(ctx context.Context, sn *data.Snapshot) error {
debug.Log("searching IDs in snapshot %s", sn.ID())
if sn.Tree == nil {
@@ -386,7 +387,7 @@ func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error {
}
f.out.newsn = sn
return walker.Walk(ctx, f.repo, *sn.Tree, walker.WalkVisitor{ProcessNode: func(parentTreeID restic.ID, nodepath string, node *restic.Node, err error) error {
return walker.Walk(ctx, f.repo, *sn.Tree, walker.WalkVisitor{ProcessNode: func(parentTreeID restic.ID, nodepath string, node *data.Node, err error) error {
if err != nil {
debug.Log("Error loading tree %v: %v", parentTreeID, err)
@@ -411,7 +412,7 @@ func (f *Finder) findIDs(ctx context.Context, sn *restic.Snapshot) error {
}
}
if node.Type == restic.NodeTypeFile && f.blobIDs != nil {
if node.Type == data.NodeTypeFile && f.blobIDs != nil {
for _, id := range node.Content {
if ctx.Err() != nil {
return ctx.Err()
@@ -654,7 +655,7 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
}
}
var filteredSnapshots []*restic.Snapshot
var filteredSnapshots []*data.Snapshot
for sn := range FindFilteredSnapshots(ctx, snapshotLister, repo, &opts.SnapshotFilter, opts.Snapshots, printer) {
filteredSnapshots = append(filteredSnapshots, sn)
}

View File

@@ -7,6 +7,7 @@ import (
"io"
"strconv"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui"
@@ -102,21 +103,21 @@ type ForgetOptions struct {
Weekly ForgetPolicyCount
Monthly ForgetPolicyCount
Yearly ForgetPolicyCount
Within restic.Duration
WithinHourly restic.Duration
WithinDaily restic.Duration
WithinWeekly restic.Duration
WithinMonthly restic.Duration
WithinYearly restic.Duration
KeepTags restic.TagLists
Within data.Duration
WithinHourly data.Duration
WithinDaily data.Duration
WithinWeekly data.Duration
WithinMonthly data.Duration
WithinYearly data.Duration
KeepTags data.TagLists
UnsafeAllowRemoveAll bool
restic.SnapshotFilter
data.SnapshotFilter
Compact bool
// Grouping
GroupBy restic.SnapshotGroupByOptions
GroupBy data.SnapshotGroupByOptions
DryRun bool
Prune bool
}
@@ -147,7 +148,7 @@ func (opts *ForgetOptions) AddFlags(f *pflag.FlagSet) {
initMultiSnapshotFilter(f, &opts.SnapshotFilter, false)
f.BoolVarP(&opts.Compact, "compact", "c", false, "use compact output format")
opts.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
opts.GroupBy = data.SnapshotGroupByOptions{Host: true, Path: true}
f.VarP(&opts.GroupBy, "group-by", "g", "`group` snapshots by host, paths and/or tags, separated by comma (disable grouping with '')")
f.BoolVarP(&opts.DryRun, "dry-run", "n", false, "do not delete anything, just print what would be done")
f.BoolVar(&opts.Prune, "prune", false, "automatically run the 'prune' command if snapshots have been removed")
@@ -161,7 +162,7 @@ func verifyForgetOptions(opts *ForgetOptions) error {
return errors.Fatal("negative values other than -1 are not allowed for --keep-*")
}
for _, d := range []restic.Duration{opts.Within, opts.WithinHourly, opts.WithinDaily,
for _, d := range []data.Duration{opts.Within, opts.WithinHourly, opts.WithinDaily,
opts.WithinMonthly, opts.WithinWeekly, opts.WithinYearly} {
if d.Hours < 0 || d.Days < 0 || d.Months < 0 || d.Years < 0 {
return errors.Fatal("durations containing negative values are not allowed for --keep-within*")
@@ -193,7 +194,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
}
defer unlock()
var snapshots restic.Snapshots
var snapshots data.Snapshots
removeSnIDs := restic.NewIDSet()
for sn := range FindFilteredSnapshots(ctx, repo, repo, &opts.SnapshotFilter, args, printer) {
@@ -211,12 +212,12 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
removeSnIDs.Insert(*sn.ID())
}
} else {
snapshotGroups, _, err := restic.GroupSnapshots(snapshots, opts.GroupBy)
snapshotGroups, _, err := data.GroupSnapshots(snapshots, opts.GroupBy)
if err != nil {
return err
}
policy := restic.ExpirePolicy{
policy := data.ExpirePolicy{
Last: int(opts.Last),
Hourly: int(opts.Hourly),
Daily: int(opts.Daily),
@@ -257,7 +258,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
}
}
var key restic.SnapshotGroupKey
var key data.SnapshotGroupKey
if json.Unmarshal([]byte(k), &key) != nil {
return err
}
@@ -267,7 +268,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
fg.Host = key.Hostname
fg.Paths = key.Paths
keep, remove, reasons := restic.ApplyPolicy(snapshotGroup, policy)
keep, remove, reasons := data.ApplyPolicy(snapshotGroup, policy)
if !policy.Empty() && len(keep) == 0 {
return fmt.Errorf("refusing to delete last snapshot of snapshot group \"%v\"", key.String())
@@ -361,7 +362,7 @@ type ForgetGroup struct {
Reasons []KeepReason `json:"reasons"`
}
func asJSONSnapshots(list restic.Snapshots) []Snapshot {
func asJSONSnapshots(list data.Snapshots) []Snapshot {
var resultList []Snapshot
for _, sn := range list {
k := Snapshot{
@@ -380,7 +381,7 @@ type KeepReason struct {
Matches []string `json:"matches"`
}
func asJSONKeeps(list []restic.KeepReason) []KeepReason {
func asJSONKeeps(list []data.KeepReason) []KeepReason {
var resultList []KeepReason
for _, keep := range list {
k := KeepReason{

View File

@@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
)
@@ -38,8 +38,8 @@ func TestRunForgetSafetyNet(t *testing.T) {
// --keep-tags invalid
err := testRunForgetMayFail(t, env.gopts, ForgetOptions{
KeepTags: restic.TagLists{restic.TagList{"invalid"}},
GroupBy: restic.SnapshotGroupByOptions{Host: true, Path: true},
KeepTags: data.TagLists{data.TagList{"invalid"}},
GroupBy: data.SnapshotGroupByOptions{Host: true, Path: true},
})
rtest.Assert(t, strings.Contains(err.Error(), `refusing to delete last snapshot of snapshot group "host example, path`), "wrong error message got %v", err)
@@ -56,8 +56,8 @@ func TestRunForgetSafetyNet(t *testing.T) {
// `forget --host example --unsafe-allow-remove-all` should work
testRunForget(t, env.gopts, ForgetOptions{
UnsafeAllowRemoveAll: true,
GroupBy: restic.SnapshotGroupByOptions{Host: true, Path: true},
SnapshotFilter: restic.SnapshotFilter{
GroupBy: data.SnapshotGroupByOptions{Host: true, Path: true},
SnapshotFilter: data.SnapshotFilter{
Hosts: []string{opts.Host},
},
})

View File

@@ -3,7 +3,7 @@ package main
import (
"testing"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
"github.com/spf13/pflag"
)
@@ -69,18 +69,18 @@ func TestForgetOptionValues(t *testing.T) {
{ForgetOptions{Weekly: -2}, negValErrorMsg},
{ForgetOptions{Monthly: -2}, negValErrorMsg},
{ForgetOptions{Yearly: -2}, negValErrorMsg},
{ForgetOptions{Within: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinHourly: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinDaily: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinWeekly: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinMonthly: restic.ParseDurationOrPanic("2y4m6d8h")}, ""},
{ForgetOptions{WithinYearly: restic.ParseDurationOrPanic("2y4m6d8h")}, ""},
{ForgetOptions{Within: restic.ParseDurationOrPanic("-1y2m3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinHourly: restic.ParseDurationOrPanic("1y-2m3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinDaily: restic.ParseDurationOrPanic("1y2m-3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinWeekly: restic.ParseDurationOrPanic("1y2m3d-3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinMonthly: restic.ParseDurationOrPanic("-2y4m6d8h")}, negDurationValErrorMsg},
{ForgetOptions{WithinYearly: restic.ParseDurationOrPanic("2y-4m6d8h")}, negDurationValErrorMsg},
{ForgetOptions{Within: data.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinHourly: data.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinDaily: data.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinWeekly: data.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinMonthly: data.ParseDurationOrPanic("2y4m6d8h")}, ""},
{ForgetOptions{WithinYearly: data.ParseDurationOrPanic("2y4m6d8h")}, ""},
{ForgetOptions{Within: data.ParseDurationOrPanic("-1y2m3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinHourly: data.ParseDurationOrPanic("1y-2m3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinDaily: data.ParseDurationOrPanic("1y2m-3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinWeekly: data.ParseDurationOrPanic("1y2m3d-3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinMonthly: data.ParseDurationOrPanic("-2y4m6d8h")}, negDurationValErrorMsg},
{ForgetOptions{WithinYearly: data.ParseDurationOrPanic("2y-4m6d8h")}, negDurationValErrorMsg},
}
for _, testCase := range testCases {

View File

@@ -15,6 +15,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
@@ -70,7 +71,7 @@ Exit status is 12 if the password is incorrect.
// LsOptions collects all options for the ls command.
type LsOptions struct {
ListLong bool
restic.SnapshotFilter
data.SnapshotFilter
Recursive bool
HumanReadable bool
Ncdu bool
@@ -89,8 +90,8 @@ func (opts *LsOptions) AddFlags(f *pflag.FlagSet) {
}
type lsPrinter interface {
Snapshot(sn *restic.Snapshot) error
Node(path string, node *restic.Node, isPrefixDirectory bool) error
Snapshot(sn *data.Snapshot) error
Node(path string, node *data.Node, isPrefixDirectory bool) error
LeaveDir(path string) error
Close() error
}
@@ -99,9 +100,9 @@ type jsonLsPrinter struct {
enc *json.Encoder
}
func (p *jsonLsPrinter) Snapshot(sn *restic.Snapshot) error {
func (p *jsonLsPrinter) Snapshot(sn *data.Snapshot) error {
type lsSnapshot struct {
*restic.Snapshot
*data.Snapshot
ID *restic.ID `json:"id"`
ShortID string `json:"short_id"` // deprecated
MessageType string `json:"message_type"` // "snapshot"
@@ -118,14 +119,14 @@ func (p *jsonLsPrinter) Snapshot(sn *restic.Snapshot) error {
}
// Node formats node in our custom JSON format, followed by a newline.
func (p *jsonLsPrinter) Node(path string, node *restic.Node, isPrefixDirectory bool) error {
func (p *jsonLsPrinter) Node(path string, node *data.Node, isPrefixDirectory bool) error {
if isPrefixDirectory {
return nil
}
return lsNodeJSON(p.enc, path, node)
}
func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
func lsNodeJSON(enc *json.Encoder, path string, node *data.Node) error {
n := &struct {
Name string `json:"name"`
Type string `json:"type"`
@@ -161,7 +162,7 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
}
// Always print size for regular files, even when empty,
// but never for other types.
if node.Type == restic.NodeTypeFile {
if node.Type == data.NodeTypeFile {
n.Size = &n.size
}
@@ -179,7 +180,7 @@ type ncduLsPrinter struct {
// Snapshot prints a restic snapshot in Ncdu save format.
// It opens the JSON list. Nodes are added with lsNodeNcdu and the list is closed by lsCloseNcdu.
// Format documentation: https://dev.yorhel.nl/ncdu/jsonfmt
func (p *ncduLsPrinter) Snapshot(sn *restic.Snapshot) error {
func (p *ncduLsPrinter) Snapshot(sn *data.Snapshot) error {
const NcduMajorVer = 1
const NcduMinorVer = 2
@@ -192,7 +193,7 @@ func (p *ncduLsPrinter) Snapshot(sn *restic.Snapshot) error {
return err
}
func lsNcduNode(_ string, node *restic.Node) ([]byte, error) {
func lsNcduNode(_ string, node *data.Node) ([]byte, error) {
type NcduNode struct {
Name string `json:"name"`
Asize uint64 `json:"asize"`
@@ -217,7 +218,7 @@ func lsNcduNode(_ string, node *restic.Node) ([]byte, error) {
Dev: node.DeviceID,
Ino: node.Inode,
NLink: node.Links,
NotReg: node.Type != restic.NodeTypeDir && node.Type != restic.NodeTypeFile,
NotReg: node.Type != data.NodeTypeDir && node.Type != data.NodeTypeFile,
UID: node.UID,
GID: node.GID,
Mode: uint16(node.Mode & os.ModePerm),
@@ -241,13 +242,13 @@ func lsNcduNode(_ string, node *restic.Node) ([]byte, error) {
return json.Marshal(outNode)
}
func (p *ncduLsPrinter) Node(path string, node *restic.Node, _ bool) error {
func (p *ncduLsPrinter) Node(path string, node *data.Node, _ bool) error {
out, err := lsNcduNode(path, node)
if err != nil {
return err
}
if node.Type == restic.NodeTypeDir {
if node.Type == data.NodeTypeDir {
_, err = fmt.Fprintf(p.out, ",\n%s[\n%s%s", strings.Repeat(" ", p.depth), strings.Repeat(" ", p.depth+1), string(out))
p.depth++
} else {
@@ -277,11 +278,11 @@ type textLsPrinter struct {
}
}
func (p *textLsPrinter) Snapshot(sn *restic.Snapshot) error {
func (p *textLsPrinter) Snapshot(sn *data.Snapshot) error {
p.termPrinter.P("%v filtered by %v:", sn, p.dirs)
return nil
}
func (p *textLsPrinter) Node(path string, node *restic.Node, isPrefixDirectory bool) error {
func (p *textLsPrinter) Node(path string, node *data.Node, isPrefixDirectory bool) error {
if !isPrefixDirectory {
p.termPrinter.S("%s", formatNode(path, node, p.ListLong, p.HumanReadable))
}
@@ -298,7 +299,7 @@ func (p *textLsPrinter) Close() error {
// for ls -l output sorting
type toSortOutput struct {
nodepath string
node *restic.Node
node *data.Node
}
func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []string, term ui.Terminal) error {
@@ -403,7 +404,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
}
}
sn, subfolder, err := (&restic.SnapshotFilter{
sn, subfolder, err := (&data.SnapshotFilter{
Hosts: opts.Hosts,
Paths: opts.Paths,
Tags: opts.Tags,
@@ -412,7 +413,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
return err
}
sn.Tree, err = restic.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
sn.Tree, err = data.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
if err != nil {
return err
}
@@ -421,7 +422,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
return err
}
processNode := func(_ restic.ID, nodepath string, node *restic.Node, err error) error {
processNode := func(_ restic.ID, nodepath string, node *data.Node, err error) error {
if err != nil {
return err
}
@@ -456,7 +457,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
// otherwise, signal the walker to not walk recursively into any
// subdirs
if node.Type == restic.NodeTypeDir {
if node.Type == data.NodeTypeDir {
// immediately generate leaveDir if the directory is skipped
if printedDir {
if err := printer.LeaveDir(nodepath); err != nil {
@@ -493,10 +494,10 @@ type sortedPrinter struct {
reverse bool
}
func (p *sortedPrinter) Snapshot(sn *restic.Snapshot) error {
func (p *sortedPrinter) Snapshot(sn *data.Snapshot) error {
return p.printer.Snapshot(sn)
}
func (p *sortedPrinter) Node(path string, node *restic.Node, isPrefixDirectory bool) error {
func (p *sortedPrinter) Node(path string, node *data.Node, isPrefixDirectory bool) error {
if !isPrefixDirectory {
p.collector = append(p.collector, toSortOutput{path, node})
}

View File

@@ -8,6 +8,7 @@ import (
"strings"
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
@@ -129,7 +130,7 @@ func TestRunLsJson(t *testing.T) {
// partial copy of snapshot structure from cmd_ls
type lsSnapshot struct {
*restic.Snapshot
*data.Snapshot
ID *restic.ID `json:"id"`
ShortID string `json:"short_id"` // deprecated
MessageType string `json:"message_type"` // "snapshot"

View File

@@ -7,13 +7,13 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
)
type lsTestNode struct {
path string
restic.Node
data.Node
}
var lsTestNodes = []lsTestNode{
@@ -21,9 +21,9 @@ var lsTestNodes = []lsTestNode{
// Permissions, by convention is "-" per mode bit
{
path: "/bar/baz",
Node: restic.Node{
Node: data.Node{
Name: "baz",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Size: 12345,
UID: 10000000,
GID: 20000000,
@@ -37,9 +37,9 @@ var lsTestNodes = []lsTestNode{
// Even empty files get an explicit size.
{
path: "/foo/empty",
Node: restic.Node{
Node: data.Node{
Name: "empty",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Size: 0,
UID: 1001,
GID: 1001,
@@ -54,9 +54,9 @@ var lsTestNodes = []lsTestNode{
// Mode is printed in decimal, including the type bits.
{
path: "/foo/link",
Node: restic.Node{
Node: data.Node{
Name: "link",
Type: restic.NodeTypeSymlink,
Type: data.NodeTypeSymlink,
Mode: os.ModeSymlink | 0777,
LinkTarget: "not printed",
},
@@ -64,9 +64,9 @@ var lsTestNodes = []lsTestNode{
{
path: "/some/directory",
Node: restic.Node{
Node: data.Node{
Name: "directory",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Mode: os.ModeDir | 0755,
ModTime: time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
AccessTime: time.Date(2021, 2, 3, 4, 5, 6, 7, time.UTC),
@@ -77,9 +77,9 @@ var lsTestNodes = []lsTestNode{
// Test encoding of setuid/setgid/sticky bit
{
path: "/some/sticky",
Node: restic.Node{
Node: data.Node{
Name: "sticky",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Mode: os.ModeDir | 0755 | os.ModeSetuid | os.ModeSetgid | os.ModeSticky,
},
},
@@ -134,24 +134,24 @@ func TestLsNcdu(t *testing.T) {
}
modTime := time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC)
rtest.OK(t, printer.Snapshot(&restic.Snapshot{
rtest.OK(t, printer.Snapshot(&data.Snapshot{
Hostname: "host",
Paths: []string{"/example"},
}))
rtest.OK(t, printer.Node("/directory", &restic.Node{
Type: restic.NodeTypeDir,
rtest.OK(t, printer.Node("/directory", &data.Node{
Type: data.NodeTypeDir,
Name: "directory",
ModTime: modTime,
}, false))
rtest.OK(t, printer.Node("/directory/data", &restic.Node{
Type: restic.NodeTypeFile,
rtest.OK(t, printer.Node("/directory/data", &data.Node{
Type: data.NodeTypeFile,
Name: "data",
Size: 42,
ModTime: modTime,
}, false))
rtest.OK(t, printer.LeaveDir("/directory"))
rtest.OK(t, printer.Node("/file", &restic.Node{
Type: restic.NodeTypeFile,
rtest.OK(t, printer.Node("/file", &data.Node{
Type: data.NodeTypeFile,
Name: "file",
Size: 12345,
ModTime: modTime,

View File

@@ -13,9 +13,9 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui"
"github.com/restic/restic/internal/fuse"
@@ -95,7 +95,7 @@ type MountOptions struct {
OwnerRoot bool
AllowOther bool
NoDefaultPermissions bool
restic.SnapshotFilter
data.SnapshotFilter
TimeTemplate string
PathTemplates []string
}

View File

@@ -13,6 +13,7 @@ import (
"time"
systemFuse "github.com/anacrolix/fuse"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
@@ -137,7 +138,7 @@ func checkSnapshots(t testing.TB, gopts GlobalOptions, mountpoint string, snapsh
defer unlock()
for _, id := range snapshotIDs {
snapshot, err := restic.LoadSnapshot(ctx, repo, id)
snapshot, err := data.LoadSnapshot(ctx, repo, id)
rtest.OK(t, err)
ts := snapshot.Time.Format(time.RFC3339)

View File

@@ -7,6 +7,7 @@ import (
"strconv"
"strings"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
@@ -278,8 +279,8 @@ func printPruneStats(printer progress.Printer, stats repository.PruneStats) erro
func getUsedBlobs(ctx context.Context, repo restic.Repository, usedBlobs restic.FindBlobSet, ignoreSnapshots restic.IDSet, printer progress.Printer) error {
var snapshotTrees restic.IDs
printer.P("loading all snapshots...\n")
err := restic.ForAllSnapshots(ctx, repo, repo, ignoreSnapshots,
func(id restic.ID, sn *restic.Snapshot, err error) error {
err := data.ForAllSnapshots(ctx, repo, repo, ignoreSnapshots,
func(id restic.ID, sn *data.Snapshot, err error) error {
if err != nil {
debug.Log("failed to load snapshot %v (error %v)", id, err)
return err
@@ -298,5 +299,5 @@ func getUsedBlobs(ctx context.Context, repo restic.Repository, usedBlobs restic.
bar.SetMax(uint64(len(snapshotTrees)))
defer bar.Done()
return restic.FindUsedBlobs(ctx, repo, snapshotTrees, usedBlobs, bar)
return data.FindUsedBlobs(ctx, repo, snapshotTrees, usedBlobs, bar)
}

View File

@@ -5,6 +5,7 @@ import (
"os"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
@@ -87,7 +88,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions, term ui.Terminal) erro
bar := printer.NewCounter("trees loaded")
bar.SetMax(uint64(len(trees)))
for id := range trees {
tree, err := restic.LoadTree(ctx, repo, id)
tree, err := data.LoadTree(ctx, repo, id)
if ctx.Err() != nil {
return ctx.Err()
}
@@ -97,7 +98,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions, term ui.Terminal) erro
}
for _, node := range tree.Nodes {
if node.Type == restic.NodeTypeDir && node.Subtree != nil {
if node.Type == data.NodeTypeDir && node.Subtree != nil {
trees[*node.Subtree] = true
}
}
@@ -106,7 +107,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions, term ui.Terminal) erro
bar.Done()
printer.P("load snapshots\n")
err = restic.ForAllSnapshots(ctx, snapshotLister, repo, nil, func(_ restic.ID, sn *restic.Snapshot, _ error) error {
err = data.ForAllSnapshots(ctx, snapshotLister, repo, nil, func(_ restic.ID, sn *data.Snapshot, _ error) error {
trees[*sn.Tree] = true
return nil
})
@@ -133,11 +134,11 @@ func runRecover(ctx context.Context, gopts GlobalOptions, term ui.Terminal) erro
return ctx.Err()
}
tree := restic.NewTree(len(roots))
tree := data.NewTree(len(roots))
for id := range roots {
var subtreeID = id
node := restic.Node{
Type: restic.NodeTypeDir,
node := data.Node{
Type: data.NodeTypeDir,
Name: id.Str(),
Mode: 0755,
Subtree: &subtreeID,
@@ -157,7 +158,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions, term ui.Terminal) erro
var treeID restic.ID
wg.Go(func() error {
var err error
treeID, err = restic.SaveTree(wgCtx, repo, tree)
treeID, err = data.SaveTree(wgCtx, repo, tree)
if err != nil {
return errors.Fatalf("unable to save new tree to the repository: %v", err)
}
@@ -178,14 +179,14 @@ func runRecover(ctx context.Context, gopts GlobalOptions, term ui.Terminal) erro
}
func createSnapshot(ctx context.Context, printer progress.Printer, name, hostname string, tags []string, repo restic.SaverUnpacked[restic.WriteableFileType], tree *restic.ID) error {
sn, err := restic.NewSnapshot([]string{name}, tags, hostname, time.Now())
sn, err := data.NewSnapshot([]string{name}, tags, hostname, time.Now())
if err != nil {
return errors.Fatalf("unable to save snapshot: %v", err)
}
sn.Tree = tree
id, err := restic.SaveSnapshot(ctx, repo, sn)
id, err := data.SaveSnapshot(ctx, repo, sn)
if err != nil {
return errors.Fatalf("unable to save snapshot: %v", err)
}

View File

@@ -3,6 +3,7 @@ package main
import (
"context"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui"
@@ -63,7 +64,7 @@ type RepairOptions struct {
DryRun bool
Forget bool
restic.SnapshotFilter
data.SnapshotFilter
}
func (opts *RepairOptions) AddFlags(f *pflag.FlagSet) {
@@ -96,12 +97,12 @@ func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOpt
// - trees which cannot be loaded (-> the tree contents will be removed)
// - files whose contents are not fully available (-> file will be modified)
rewriter := walker.NewTreeRewriter(walker.RewriteOpts{
RewriteNode: func(node *restic.Node, path string) *restic.Node {
if node.Type == restic.NodeTypeIrregular || node.Type == restic.NodeTypeInvalid {
RewriteNode: func(node *data.Node, path string) *data.Node {
if node.Type == data.NodeTypeIrregular || node.Type == data.NodeTypeInvalid {
printer.P(" file %q: removed node with invalid type %q", path, node.Type)
return nil
}
if node.Type != restic.NodeTypeFile {
if node.Type != data.NodeTypeFile {
return node
}
@@ -135,7 +136,7 @@ func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOpt
}
// If a subtree fails to load, remove it
printer.P(" dir %q: replaced with empty directory", path)
emptyID, err := restic.SaveTree(ctx, repo, &restic.Tree{})
emptyID, err := data.SaveTree(ctx, repo, &data.Tree{})
if err != nil {
return restic.ID{}, err
}
@@ -148,7 +149,7 @@ func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOpt
for sn := range FindFilteredSnapshots(ctx, snapshotLister, repo, &opts.SnapshotFilter, args, printer) {
printer.P("\n%v", sn)
changed, err := filterAndReplaceSnapshot(ctx, repo, sn,
func(ctx context.Context, sn *restic.Snapshot) (restic.ID, *restic.SnapshotSummary, error) {
func(ctx context.Context, sn *data.Snapshot) (restic.ID, *data.SnapshotSummary, error) {
id, err := rewriter.RewriteTree(ctx, repo, "/", *sn.Tree)
return id, nil, err
}, opts.DryRun, opts.Forget, nil, "repaired", printer)

View File

@@ -5,10 +5,10 @@ import (
"path/filepath"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/filter"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/restorer"
"github.com/restic/restic/internal/ui"
"github.com/restic/restic/internal/ui/progress"
@@ -59,7 +59,7 @@ type RestoreOptions struct {
filter.ExcludePatternOptions
filter.IncludePatternOptions
Target string
restic.SnapshotFilter
data.SnapshotFilter
DryRun bool
Sparse bool
Verify bool
@@ -142,7 +142,7 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
}
defer unlock()
sn, subfolder, err := (&restic.SnapshotFilter{
sn, subfolder, err := (&data.SnapshotFilter{
Hosts: opts.Hosts,
Paths: opts.Paths,
Tags: opts.Tags,
@@ -156,7 +156,7 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
return err
}
sn.Tree, err = restic.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
sn.Tree, err = data.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
if err != nil {
return err
}

View File

@@ -11,6 +11,7 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
@@ -37,7 +38,7 @@ func testRunRestoreAssumeFailure(t testing.TB, snapshotID string, opts RestoreOp
func testRunRestoreLatest(t testing.TB, gopts GlobalOptions, dir string, paths []string, hosts []string) {
opts := RestoreOptions{
Target: dir,
SnapshotFilter: restic.SnapshotFilter{
SnapshotFilter: data.SnapshotFilter{
Hosts: hosts,
Paths: paths,
},

View File

@@ -8,6 +8,7 @@ import (
"github.com/spf13/pflag"
"golang.org/x/sync/errgroup"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/filter"
@@ -105,7 +106,7 @@ type RewriteOptions struct {
SnapshotSummary bool
Metadata snapshotMetadataArgs
restic.SnapshotFilter
data.SnapshotFilter
filter.ExcludePatternOptions
}
@@ -122,9 +123,9 @@ func (opts *RewriteOptions) AddFlags(f *pflag.FlagSet) {
// rewriteFilterFunc returns the filtered tree ID or an error. If a snapshot summary is returned, the snapshot will
// be updated accordingly.
type rewriteFilterFunc func(ctx context.Context, sn *restic.Snapshot) (restic.ID, *restic.SnapshotSummary, error)
type rewriteFilterFunc func(ctx context.Context, sn *data.Snapshot) (restic.ID, *data.SnapshotSummary, error)
func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *restic.Snapshot, opts RewriteOptions, printer progress.Printer) (bool, error) {
func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *data.Snapshot, opts RewriteOptions, printer progress.Printer) (bool, error) {
if sn.Tree == nil {
return false, errors.Errorf("snapshot %v has nil tree", sn.ID().Str())
}
@@ -152,7 +153,7 @@ func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *resti
return true
}
rewriteNode := func(node *restic.Node, path string) *restic.Node {
rewriteNode := func(node *data.Node, path string) *data.Node {
if selectByName(path) {
return node
}
@@ -162,13 +163,13 @@ func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *resti
rewriter, querySize := walker.NewSnapshotSizeRewriter(rewriteNode)
filter = func(ctx context.Context, sn *restic.Snapshot) (restic.ID, *restic.SnapshotSummary, error) {
filter = func(ctx context.Context, sn *data.Snapshot) (restic.ID, *data.SnapshotSummary, error) {
id, err := rewriter.RewriteTree(ctx, repo, "/", *sn.Tree)
if err != nil {
return restic.ID{}, nil, err
}
ss := querySize()
summary := &restic.SnapshotSummary{}
summary := &data.SnapshotSummary{}
if sn.Summary != nil {
*summary = *sn.Summary
}
@@ -178,7 +179,7 @@ func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *resti
}
} else {
filter = func(_ context.Context, sn *restic.Snapshot) (restic.ID, *restic.SnapshotSummary, error) {
filter = func(_ context.Context, sn *data.Snapshot) (restic.ID, *data.SnapshotSummary, error) {
return *sn.Tree, nil, nil
}
}
@@ -187,14 +188,14 @@ func rewriteSnapshot(ctx context.Context, repo *repository.Repository, sn *resti
filter, opts.DryRun, opts.Forget, metadata, "rewrite", printer)
}
func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *restic.Snapshot,
func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *data.Snapshot,
filter rewriteFilterFunc, dryRun bool, forget bool, newMetadata *snapshotMetadata, addTag string, printer progress.Printer) (bool, error) {
wg, wgCtx := errgroup.WithContext(ctx)
repo.StartPackUploader(wgCtx, wg)
var filteredTree restic.ID
var summary *restic.SnapshotSummary
var summary *data.SnapshotSummary
wg.Go(func() error {
var err error
filteredTree, summary, err = filter(ctx, sn)
@@ -273,7 +274,7 @@ func filterAndReplaceSnapshot(ctx context.Context, repo restic.Repository, sn *r
}
// Save the new snapshot.
id, err := restic.SaveSnapshot(ctx, repo, sn)
id, err := data.SaveSnapshot(ctx, repo, sn)
if err != nil {
return false, err
}

View File

@@ -5,6 +5,7 @@ import (
"path/filepath"
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/filter"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
@@ -37,17 +38,17 @@ func createBasicRewriteRepo(t testing.TB, env *testEnvironment) restic.ID {
return snapshotIDs[0]
}
func getSnapshot(t testing.TB, snapshotID restic.ID, env *testEnvironment) *restic.Snapshot {
func getSnapshot(t testing.TB, snapshotID restic.ID, env *testEnvironment) *data.Snapshot {
t.Helper()
var snapshots []*restic.Snapshot
var snapshots []*data.Snapshot
err := withTermStatus(t, env.gopts, func(ctx context.Context, gopts GlobalOptions) error {
printer := ui.NewProgressPrinter(gopts.JSON, gopts.verbosity, gopts.term)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, false, printer)
rtest.OK(t, err)
defer unlock()
snapshots, err = restic.TestLoadAllSnapshots(ctx, repo, nil)
snapshots, err = data.TestLoadAllSnapshots(ctx, repo, nil)
return err
})
rtest.OK(t, err)
@@ -116,14 +117,14 @@ func testRewriteMetadata(t *testing.T, metadata snapshotMetadataArgs) {
createBasicRewriteRepo(t, env)
testRunRewriteExclude(t, env.gopts, []string{}, true, metadata)
var snapshots []*restic.Snapshot
var snapshots []*data.Snapshot
err := withTermStatus(t, env.gopts, func(ctx context.Context, gopts GlobalOptions) error {
printer := ui.NewProgressPrinter(gopts.JSON, gopts.verbosity, gopts.term)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, false, printer)
rtest.OK(t, err)
defer unlock()
snapshots, err = restic.TestLoadAllSnapshots(ctx, repo, nil)
snapshots, err = data.TestLoadAllSnapshots(ctx, repo, nil)
return err
})
rtest.OK(t, err)
@@ -164,19 +165,19 @@ func TestRewriteSnaphotSummary(t *testing.T) {
snapshots := testListSnapshots(t, env.gopts, 1)
// replace snapshot by one without a summary
var oldSummary *restic.SnapshotSummary
var oldSummary *data.SnapshotSummary
err := withTermStatus(t, env.gopts, func(ctx context.Context, gopts GlobalOptions) error {
printer := ui.NewProgressPrinter(gopts.JSON, gopts.verbosity, gopts.term)
_, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
rtest.OK(t, err)
defer unlock()
sn, err := restic.LoadSnapshot(ctx, repo, snapshots[0])
sn, err := data.LoadSnapshot(ctx, repo, snapshots[0])
rtest.OK(t, err)
oldSummary = sn.Summary
sn.Summary = nil
rtest.OK(t, repo.RemoveUnpacked(ctx, restic.WriteableSnapshotFile, snapshots[0]))
snapshots[0], err = restic.SaveSnapshot(ctx, repo, sn)
snapshots[0], err = data.SaveSnapshot(ctx, repo, sn)
return err
})
rtest.OK(t, err)

View File

@@ -8,6 +8,7 @@ import (
"sort"
"strings"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui"
"github.com/restic/restic/internal/ui/table"
@@ -46,11 +47,11 @@ Exit status is 12 if the password is incorrect.
// SnapshotOptions bundles all options for the snapshots command.
type SnapshotOptions struct {
restic.SnapshotFilter
data.SnapshotFilter
Compact bool
Last bool // This option should be removed in favour of Latest.
Latest int
GroupBy restic.SnapshotGroupByOptions
GroupBy data.SnapshotGroupByOptions
}
func (opts *SnapshotOptions) AddFlags(f *pflag.FlagSet) {
@@ -74,14 +75,14 @@ func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions
}
defer unlock()
var snapshots restic.Snapshots
var snapshots data.Snapshots
for sn := range FindFilteredSnapshots(ctx, repo, repo, &opts.SnapshotFilter, args, printer) {
snapshots = append(snapshots, sn)
}
if ctx.Err() != nil {
return ctx.Err()
}
snapshotGroups, grouped, err := restic.GroupSnapshots(snapshots, opts.GroupBy)
snapshotGroups, grouped, err := data.GroupSnapshots(snapshots, opts.GroupBy)
if err != nil {
return err
}
@@ -137,7 +138,7 @@ type filterLastSnapshotsKey struct {
}
// newFilterLastSnapshotsKey initializes a filterLastSnapshotsKey from a Snapshot
func newFilterLastSnapshotsKey(sn *restic.Snapshot) filterLastSnapshotsKey {
func newFilterLastSnapshotsKey(sn *data.Snapshot) filterLastSnapshotsKey {
// Shallow slice copy
var paths = make([]string, len(sn.Paths))
copy(paths, sn.Paths)
@@ -149,13 +150,13 @@ func newFilterLastSnapshotsKey(sn *restic.Snapshot) filterLastSnapshotsKey {
// the limit last entries for each hostname and path. If the snapshot
// contains multiple paths, they will be joined and treated as one
// item.
func FilterLatestSnapshots(list restic.Snapshots, limit int) restic.Snapshots {
func FilterLatestSnapshots(list data.Snapshots, limit int) data.Snapshots {
// Sort the snapshots so that the newer ones are listed first
sort.SliceStable(list, func(i, j int) bool {
return list[i].Time.After(list[j].Time)
})
var results restic.Snapshots
var results data.Snapshots
seen := make(map[filterLastSnapshotsKey]int)
for _, sn := range list {
key := newFilterLastSnapshotsKey(sn)
@@ -168,10 +169,10 @@ func FilterLatestSnapshots(list restic.Snapshots, limit int) restic.Snapshots {
}
// PrintSnapshots prints a text table of the snapshots in list to stdout.
func PrintSnapshots(stdout io.Writer, list restic.Snapshots, reasons []restic.KeepReason, compact bool) error {
func PrintSnapshots(stdout io.Writer, list data.Snapshots, reasons []data.KeepReason, compact bool) error {
// keep the reasons a snasphot is being kept in a map, so that it doesn't
// get lost when the list of snapshots is sorted
keepReasons := make(map[restic.ID]restic.KeepReason, len(reasons))
keepReasons := make(map[restic.ID]data.KeepReason, len(reasons))
if len(reasons) > 0 {
for i, sn := range list {
id := sn.ID()
@@ -287,7 +288,7 @@ func PrintSnapshots(stdout io.Writer, list restic.Snapshots, reasons []restic.Ke
// following snapshots belong to.
// Prints nothing, if we did not group at all.
func PrintSnapshotGroupHeader(stdout io.Writer, groupKeyJSON string) error {
var key restic.SnapshotGroupKey
var key data.SnapshotGroupKey
err := json.Unmarshal([]byte(groupKeyJSON), &key)
if err != nil {
@@ -320,7 +321,7 @@ func PrintSnapshotGroupHeader(stdout io.Writer, groupKeyJSON string) error {
// Snapshot helps to print Snapshots as JSON with their ID included.
type Snapshot struct {
*restic.Snapshot
*data.Snapshot
ID *restic.ID `json:"id"`
ShortID string `json:"short_id"` // deprecated
@@ -328,17 +329,17 @@ type Snapshot struct {
// SnapshotGroup helps to print SnapshotGroups as JSON with their GroupReasons included.
type SnapshotGroup struct {
GroupKey restic.SnapshotGroupKey `json:"group_key"`
Snapshots []Snapshot `json:"snapshots"`
GroupKey data.SnapshotGroupKey `json:"group_key"`
Snapshots []Snapshot `json:"snapshots"`
}
// printSnapshotGroupJSON writes the JSON representation of list to stdout.
func printSnapshotGroupJSON(stdout io.Writer, snGroups map[string]restic.Snapshots, grouped bool) error {
func printSnapshotGroupJSON(stdout io.Writer, snGroups map[string]data.Snapshots, grouped bool) error {
if grouped {
snapshotGroups := []SnapshotGroup{}
for k, list := range snGroups {
var key restic.SnapshotGroupKey
var key data.SnapshotGroupKey
var err error
var snapshots []Snapshot

View File

@@ -10,6 +10,7 @@ import (
"github.com/restic/chunker"
"github.com/restic/restic/internal/crypto"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/restorer"
@@ -79,7 +80,7 @@ type StatsOptions struct {
// the mode of counting to perform (see consts for available modes)
countMode string
restic.SnapshotFilter
data.SnapshotFilter
}
func (opts *StatsOptions) AddFlags(f *pflag.FlagSet) {
@@ -200,7 +201,7 @@ func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args
return nil
}
func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo restic.Loader, opts StatsOptions, stats *statsContainer) error {
func statsWalkSnapshot(ctx context.Context, snapshot *data.Snapshot, repo restic.Loader, opts StatsOptions, stats *statsContainer) error {
if snapshot.Tree == nil {
return fmt.Errorf("snapshot %s has nil tree", snapshot.ID().Str())
}
@@ -210,7 +211,7 @@ func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo rest
if opts.countMode == countModeRawData {
// count just the sizes of unique blobs; we don't need to walk the tree
// ourselves in this case, since a nifty function does it for us
return restic.FindUsedBlobs(ctx, repo, restic.IDs{*snapshot.Tree}, stats.blobs, nil)
return data.FindUsedBlobs(ctx, repo, restic.IDs{*snapshot.Tree}, stats.blobs, nil)
}
hardLinkIndex := restorer.NewHardlinkIndex[struct{}]()
@@ -225,7 +226,7 @@ func statsWalkSnapshot(ctx context.Context, snapshot *restic.Snapshot, repo rest
}
func statsWalkTree(repo restic.Loader, opts StatsOptions, stats *statsContainer, hardLinkIndex *restorer.HardlinkIndex[struct{}]) walker.WalkFunc {
return func(parentTreeID restic.ID, npath string, node *restic.Node, nodeErr error) error {
return func(parentTreeID restic.ID, npath string, node *data.Node, nodeErr error) error {
if nodeErr != nil {
return nodeErr
}
@@ -281,7 +282,7 @@ func statsWalkTree(repo restic.Loader, opts StatsOptions, stats *statsContainer,
// will still be restored
stats.TotalFileCount++
if node.Links == 1 || node.Type == restic.NodeTypeDir {
if node.Links == 1 || node.Type == data.NodeTypeDir {
stats.TotalSize += node.Size
} else {
// if hardlinks are present only count each deviceID+inode once
@@ -298,7 +299,7 @@ func statsWalkTree(repo restic.Loader, opts StatsOptions, stats *statsContainer,
// makeFileIDByContents returns a hash of the blob IDs of the
// node's Content in sequence.
func makeFileIDByContents(node *restic.Node) fileID {
func makeFileIDByContents(node *data.Node) fileID {
var bb []byte
for _, c := range node.Content {
bb = append(bb, c[:]...)

View File

@@ -6,6 +6,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
@@ -49,10 +50,10 @@ Exit status is 12 if the password is incorrect.
// TagOptions bundles all options for the 'tag' command.
type TagOptions struct {
restic.SnapshotFilter
SetTags restic.TagLists
AddTags restic.TagLists
RemoveTags restic.TagLists
data.SnapshotFilter
SetTags data.TagLists
AddTags data.TagLists
RemoveTags data.TagLists
}
func (opts *TagOptions) AddFlags(f *pflag.FlagSet) {
@@ -73,7 +74,7 @@ type changedSnapshotsSummary struct {
ChangedSnapshots int `json:"changed_snapshots"`
}
func changeTags(ctx context.Context, repo *repository.Repository, sn *restic.Snapshot, setTags, addTags, removeTags []string, printFunc func(changedSnapshot)) (bool, error) {
func changeTags(ctx context.Context, repo *repository.Repository, sn *data.Snapshot, setTags, addTags, removeTags []string, printFunc func(changedSnapshot)) (bool, error) {
var changed bool
if len(setTags) != 0 {
@@ -97,7 +98,7 @@ func changeTags(ctx context.Context, repo *repository.Repository, sn *restic.Sna
}
// Save the new snapshot.
id, err := restic.SaveSnapshot(ctx, repo, sn)
id, err := data.SaveSnapshot(ctx, repo, sn)
if err != nil {
return false, err
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"testing"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
)
@@ -32,7 +32,7 @@ func TestTag(t *testing.T) {
"expected original ID to be nil, got %v", newest.Original)
originalID := *newest.ID
testRunTag(t, TagOptions{SetTags: restic.TagLists{[]string{"NL"}}}, env.gopts)
testRunTag(t, TagOptions{SetTags: data.TagLists{[]string{"NL"}}}, env.gopts)
testRunCheck(t, env.gopts)
newest, _ = testRunSnapshots(t, env.gopts)
if newest == nil {
@@ -44,7 +44,7 @@ func TestTag(t *testing.T) {
rtest.Assert(t, *newest.Original == originalID,
"expected original ID to be set to the first snapshot id")
testRunTag(t, TagOptions{AddTags: restic.TagLists{[]string{"CH"}}}, env.gopts)
testRunTag(t, TagOptions{AddTags: data.TagLists{[]string{"CH"}}}, env.gopts)
testRunCheck(t, env.gopts)
newest, _ = testRunSnapshots(t, env.gopts)
if newest == nil {
@@ -56,7 +56,7 @@ func TestTag(t *testing.T) {
rtest.Assert(t, *newest.Original == originalID,
"expected original ID to be set to the first snapshot id")
testRunTag(t, TagOptions{RemoveTags: restic.TagLists{[]string{"NL"}}}, env.gopts)
testRunTag(t, TagOptions{RemoveTags: data.TagLists{[]string{"NL"}}}, env.gopts)
testRunCheck(t, env.gopts)
newest, _ = testRunSnapshots(t, env.gopts)
if newest == nil {
@@ -68,8 +68,8 @@ func TestTag(t *testing.T) {
rtest.Assert(t, *newest.Original == originalID,
"expected original ID to be set to the first snapshot id")
testRunTag(t, TagOptions{AddTags: restic.TagLists{[]string{"US", "RU"}}}, env.gopts)
testRunTag(t, TagOptions{RemoveTags: restic.TagLists{[]string{"CH", "US", "RU"}}}, env.gopts)
testRunTag(t, TagOptions{AddTags: data.TagLists{[]string{"US", "RU"}}}, env.gopts)
testRunTag(t, TagOptions{RemoveTags: data.TagLists{[]string{"CH", "US", "RU"}}}, env.gopts)
testRunCheck(t, env.gopts)
newest, _ = testRunSnapshots(t, env.gopts)
if newest == nil {
@@ -82,7 +82,7 @@ func TestTag(t *testing.T) {
"expected original ID to be set to the first snapshot id")
// Check special case of removing all tags.
testRunTag(t, TagOptions{SetTags: restic.TagLists{[]string{""}}}, env.gopts)
testRunTag(t, TagOptions{SetTags: data.TagLists{[]string{""}}}, env.gopts)
testRunCheck(t, env.gopts)
newest, _ = testRunSnapshots(t, env.gopts)
if newest == nil {

View File

@@ -4,6 +4,7 @@ import (
"context"
"os"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui/progress"
"github.com/spf13/pflag"
@@ -11,7 +12,7 @@ import (
// initMultiSnapshotFilter is used for commands that work on multiple snapshots
// MUST be combined with restic.FindFilteredSnapshots or FindFilteredSnapshots
func initMultiSnapshotFilter(flags *pflag.FlagSet, filt *restic.SnapshotFilter, addHostShorthand bool) {
func initMultiSnapshotFilter(flags *pflag.FlagSet, filt *data.SnapshotFilter, addHostShorthand bool) {
hostShorthand := "H"
if !addHostShorthand {
hostShorthand = ""
@@ -28,7 +29,7 @@ func initMultiSnapshotFilter(flags *pflag.FlagSet, filt *restic.SnapshotFilter,
// initSingleSnapshotFilter is used for commands that work on a single snapshot
// MUST be combined with restic.FindFilteredSnapshot
func initSingleSnapshotFilter(flags *pflag.FlagSet, filt *restic.SnapshotFilter) {
func initSingleSnapshotFilter(flags *pflag.FlagSet, filt *data.SnapshotFilter) {
flags.StringArrayVarP(&filt.Hosts, "host", "H", nil, "only consider snapshots for this `host`, when snapshot ID \"latest\" is given (can be specified multiple times) (default: $RESTIC_HOST)")
flags.Var(&filt.Tags, "tag", "only consider snapshots including `tag[,tag,...]`, when snapshot ID \"latest\" is given (can be specified multiple times)")
flags.StringArrayVar(&filt.Paths, "path", nil, "only consider snapshots including this (absolute) `path`, when snapshot ID \"latest\" is given (can be specified multiple times, snapshots must include all specified paths)")
@@ -40,8 +41,8 @@ func initSingleSnapshotFilter(flags *pflag.FlagSet, filt *restic.SnapshotFilter)
}
// FindFilteredSnapshots yields Snapshots, either given explicitly by `snapshotIDs` or filtered from the list of all snapshots.
func FindFilteredSnapshots(ctx context.Context, be restic.Lister, loader restic.LoaderUnpacked, f *restic.SnapshotFilter, snapshotIDs []string, printer progress.Printer) <-chan *restic.Snapshot {
out := make(chan *restic.Snapshot)
func FindFilteredSnapshots(ctx context.Context, be restic.Lister, loader restic.LoaderUnpacked, f *data.SnapshotFilter, snapshotIDs []string, printer progress.Printer) <-chan *data.Snapshot {
out := make(chan *data.Snapshot)
go func() {
defer close(out)
be, err := restic.MemorizeList(ctx, be, restic.SnapshotFile)
@@ -50,7 +51,7 @@ func FindFilteredSnapshots(ctx context.Context, be restic.Lister, loader restic.
return
}
err = f.FindAll(ctx, be, loader, snapshotIDs, func(id string, sn *restic.Snapshot, err error) error {
err = f.FindAll(ctx, be, loader, snapshotIDs, func(id string, sn *data.Snapshot, err error) error {
if err != nil {
printer.E("Ignoring %q: %v", id, err)
} else {

View File

@@ -3,7 +3,7 @@ package main
import (
"testing"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
"github.com/spf13/pflag"
)
@@ -45,7 +45,7 @@ func TestSnapshotFilter(t *testing.T) {
for _, mode := range []bool{false, true} {
set := pflag.NewFlagSet("test", pflag.PanicOnError)
flt := &restic.SnapshotFilter{}
flt := &data.SnapshotFilter{}
if mode {
initMultiSnapshotFilter(set, flt, false)
} else {

View File

@@ -4,11 +4,11 @@ import (
"fmt"
"os"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/ui"
)
func formatNode(path string, n *restic.Node, long bool, human bool) string {
func formatNode(path string, n *data.Node, long bool, human bool) string {
if !long {
return path
}
@@ -24,20 +24,20 @@ func formatNode(path string, n *restic.Node, long bool, human bool) string {
}
switch n.Type {
case restic.NodeTypeFile:
case data.NodeTypeFile:
mode = 0
case restic.NodeTypeDir:
case data.NodeTypeDir:
mode = os.ModeDir
case restic.NodeTypeSymlink:
case data.NodeTypeSymlink:
mode = os.ModeSymlink
target = fmt.Sprintf(" -> %v", n.LinkTarget)
case restic.NodeTypeDev:
case data.NodeTypeDev:
mode = os.ModeDevice
case restic.NodeTypeCharDev:
case data.NodeTypeCharDev:
mode = os.ModeDevice | os.ModeCharDevice
case restic.NodeTypeFifo:
case data.NodeTypeFifo:
mode = os.ModeNamedPipe
case restic.NodeTypeSocket:
case data.NodeTypeSocket:
mode = os.ModeSocket
}

View File

@@ -4,7 +4,7 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
rtest "github.com/restic/restic/internal/test"
)
@@ -17,9 +17,9 @@ func TestFormatNode(t *testing.T) {
}()
testPath := "/test/path"
node := restic.Node{
node := data.Node{
Name: "baz",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Size: 14680064,
UID: 1000,
GID: 2000,
@@ -28,7 +28,7 @@ func TestFormatNode(t *testing.T) {
for _, c := range []struct {
path string
restic.Node
data.Node
long bool
human bool
expect string

View File

@@ -15,6 +15,7 @@ import (
"github.com/restic/restic/internal/backend"
"github.com/restic/restic/internal/backend/retry"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/options"
"github.com/restic/restic/internal/repository"
@@ -365,15 +366,15 @@ func lastSnapshot(old, new map[string]struct{}) (map[string]struct{}, string) {
return old, ""
}
func testLoadSnapshot(t testing.TB, gopts GlobalOptions, id restic.ID) *restic.Snapshot {
var snapshot *restic.Snapshot
func testLoadSnapshot(t testing.TB, gopts GlobalOptions, id restic.ID) *data.Snapshot {
var snapshot *data.Snapshot
err := withTermStatus(t, gopts, func(ctx context.Context, gopts GlobalOptions) error {
printer := ui.NewProgressPrinter(gopts.JSON, gopts.verbosity, gopts.term)
_, repo, unlock, err := openWithReadLock(ctx, gopts, false, printer)
rtest.OK(t, err)
defer unlock()
snapshot, err = restic.LoadSnapshot(ctx, repo, id)
snapshot, err = data.LoadSnapshot(ctx, repo, id)
return err
})
rtest.OK(t, err)

View File

@@ -9,6 +9,7 @@ import (
"testing"
"github.com/restic/restic/internal/backend"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
@@ -170,7 +171,7 @@ func TestFindListOnce(t *testing.T) {
snapshotIDs = restic.NewIDSet()
// specify the two oldest snapshots explicitly and use "latest" to reference the newest one
for sn := range FindFilteredSnapshots(ctx, repo, repo, &restic.SnapshotFilter{}, []string{
for sn := range FindFilteredSnapshots(ctx, repo, repo, &data.SnapshotFilter{}, []string{
secondSnapshot[0].String(),
secondSnapshot[1].String()[:8],
"latest",

View File

@@ -11,6 +11,7 @@ import (
"sync"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/feature"
@@ -66,9 +67,9 @@ func (s *ItemStats) Add(other ItemStats) {
s.TreeSizeInRepo += other.TreeSizeInRepo
}
// ToNoder returns a restic.Node for a File.
// ToNoder returns a data.Node for a File.
type ToNoder interface {
ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*restic.Node, error)
ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*data.Node, error)
}
type archiverRepo interface {
@@ -116,7 +117,7 @@ type Archiver struct {
//
// CompleteItem may be called asynchronously from several different
// goroutines!
CompleteItem func(item string, previous, current *restic.Node, s ItemStats, d time.Duration)
CompleteItem func(item string, previous, current *data.Node, s ItemStats, d time.Duration)
// StartFile is called when a file is being processed by a worker.
StartFile func(filename string)
@@ -193,7 +194,7 @@ func New(repo archiverRepo, filesystem fs.FS, opts Options) *Archiver {
FS: filesystem,
Options: opts.ApplyDefaults(),
CompleteItem: func(string, *restic.Node, *restic.Node, ItemStats, time.Duration) {},
CompleteItem: func(string, *data.Node, *data.Node, ItemStats, time.Duration) {},
StartFile: func(string) {},
CompleteBlob: func(uint64) {},
}
@@ -223,7 +224,7 @@ func (arch *Archiver) error(item string, err error) error {
return errf
}
func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s ItemStats, d time.Duration) {
func (arch *Archiver) trackItem(item string, previous, current *data.Node, s ItemStats, d time.Duration) {
arch.CompleteItem(item, previous, current, s, d)
arch.mu.Lock()
@@ -239,7 +240,7 @@ func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s I
}
switch current.Type {
case restic.NodeTypeDir:
case data.NodeTypeDir:
switch {
case previous == nil:
arch.summary.Dirs.New++
@@ -249,7 +250,7 @@ func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s I
arch.summary.Dirs.Changed++
}
case restic.NodeTypeFile:
case data.NodeTypeFile:
switch {
case previous == nil:
arch.summary.Files.New++
@@ -262,7 +263,7 @@ func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s I
}
// nodeFromFileInfo returns the restic node from an os.FileInfo.
func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*restic.Node, error) {
func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*data.Node, error) {
node, err := meta.ToNode(ignoreXattrListError, func(format string, args ...any) {
_ = arch.error(filename, fmt.Errorf(format, args...))
})
@@ -275,7 +276,7 @@ func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ig
node.AccessTime = node.ModTime
}
if feature.Flag.Enabled(feature.DeviceIDForHardlinks) {
if node.Links == 1 || node.Type == restic.NodeTypeDir {
if node.Links == 1 || node.Type == data.NodeTypeDir {
// the DeviceID is only necessary for hardlinked files
// when using subvolumes or snapshots their deviceIDs tend to change which causes
// restic to upload new tree blobs
@@ -285,7 +286,7 @@ func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ig
// overwrite name to match that within the snapshot
node.Name = path.Base(snPath)
// do not filter error for nodes of irregular or invalid type
if node.Type != restic.NodeTypeIrregular && node.Type != restic.NodeTypeInvalid && err != nil {
if node.Type != data.NodeTypeIrregular && node.Type != data.NodeTypeInvalid && err != nil {
err = fmt.Errorf("incomplete metadata for %v: %w", filename, err)
return node, arch.error(filename, err)
}
@@ -294,12 +295,12 @@ func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ig
// loadSubtree tries to load the subtree referenced by node. In case of an error, nil is returned.
// If there is no node to load, then nil is returned without an error.
func (arch *Archiver) loadSubtree(ctx context.Context, node *restic.Node) (*restic.Tree, error) {
if node == nil || node.Type != restic.NodeTypeDir || node.Subtree == nil {
func (arch *Archiver) loadSubtree(ctx context.Context, node *data.Node) (*data.Tree, error) {
if node == nil || node.Type != data.NodeTypeDir || node.Subtree == nil {
return nil, nil
}
tree, err := restic.LoadTree(ctx, arch.Repo, *node.Subtree)
tree, err := data.LoadTree(ctx, arch.Repo, *node.Subtree)
if err != nil {
debug.Log("unable to load tree %v: %v", node.Subtree.Str(), err)
// a tree in the repository is not readable -> warn the user
@@ -320,7 +321,7 @@ func (arch *Archiver) wrapLoadTreeError(id restic.ID, err error) error {
// saveDir stores a directory in the repo and returns the node. snPath is the
// path within the current snapshot.
func (arch *Archiver) saveDir(ctx context.Context, snPath string, dir string, meta fs.File, previous *restic.Tree, complete fileCompleteFunc) (d futureNode, err error) {
func (arch *Archiver) saveDir(ctx context.Context, snPath string, dir string, meta fs.File, previous *data.Tree, complete fileCompleteFunc) (d futureNode, err error) {
debug.Log("%v %v", snPath, dir)
treeNode, names, err := arch.dirToNodeAndEntries(snPath, dir, meta)
@@ -365,7 +366,7 @@ func (arch *Archiver) saveDir(ctx context.Context, snPath string, dir string, me
return fn, nil
}
func (arch *Archiver) dirToNodeAndEntries(snPath, dir string, meta fs.File) (node *restic.Node, names []string, err error) {
func (arch *Archiver) dirToNodeAndEntries(snPath, dir string, meta fs.File) (node *data.Node, names []string, err error) {
err = meta.MakeReadable()
if err != nil {
return nil, nil, fmt.Errorf("openfile for readdirnames failed: %w", err)
@@ -375,7 +376,7 @@ func (arch *Archiver) dirToNodeAndEntries(snPath, dir string, meta fs.File) (nod
if err != nil {
return nil, nil, err
}
if node.Type != restic.NodeTypeDir {
if node.Type != data.NodeTypeDir {
return nil, nil, fmt.Errorf("directory %q changed type, refusing to archive", snPath)
}
@@ -400,7 +401,7 @@ type futureNode struct {
type futureNodeResult struct {
snPath, target string
node *restic.Node
node *data.Node
stats ItemStats
err error
}
@@ -438,7 +439,7 @@ func (fn *futureNode) take(ctx context.Context) futureNodeResult {
// allBlobsPresent checks if all blobs (contents) of the given node are
// present in the index.
func (arch *Archiver) allBlobsPresent(previous *restic.Node) bool {
func (arch *Archiver) allBlobsPresent(previous *data.Node) bool {
// check if all blobs are contained in index
for _, id := range previous.Content {
if _, ok := arch.Repo.LookupBlobSize(restic.DataBlob, id); !ok {
@@ -455,7 +456,7 @@ func (arch *Archiver) allBlobsPresent(previous *restic.Node) bool {
// Errors and completion needs to be handled by the caller.
//
// snPath is the path within the current snapshot.
func (arch *Archiver) save(ctx context.Context, snPath, target string, previous *restic.Node) (fn futureNode, excluded bool, err error) {
func (arch *Archiver) save(ctx context.Context, snPath, target string, previous *data.Node) (fn futureNode, excluded bool, err error) {
start := time.Now()
debug.Log("%v target %q, previous %v", snPath, target, previous)
@@ -574,7 +575,7 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
arch.StartFile(snPath)
}, func() {
arch.trackItem(snPath, nil, nil, ItemStats{}, 0)
}, func(node *restic.Node, stats ItemStats) {
}, func(node *data.Node, stats ItemStats) {
arch.trackItem(snPath, previous, node, stats, time.Since(start))
})
@@ -591,7 +592,7 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
}
fn, err = arch.saveDir(ctx, snPath, target, meta, oldSubtree,
func(node *restic.Node, stats ItemStats) {
func(node *data.Node, stats ItemStats) {
arch.trackItem(snItem, previous, node, stats, time.Since(start))
})
if err != nil {
@@ -625,11 +626,11 @@ func (arch *Archiver) save(ctx context.Context, snPath, target string, previous
// fileChanged tries to detect whether a file's content has changed compared
// to the contents of node, which describes the same path in the parent backup.
// It should only be run for regular files.
func fileChanged(fi *fs.ExtendedFileInfo, node *restic.Node, ignoreFlags uint) bool {
func fileChanged(fi *fs.ExtendedFileInfo, node *data.Node, ignoreFlags uint) bool {
switch {
case node == nil:
return true
case node.Type != restic.NodeTypeFile:
case node.Type != data.NodeTypeFile:
// We're only called for regular files, so this is a type change.
return true
case uint64(fi.Size) != node.Size:
@@ -658,9 +659,9 @@ func join(elem ...string) string {
// saveTree stores a Tree in the repo, returned is the tree. snPath is the path
// within the current snapshot.
func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree, previous *restic.Tree, complete fileCompleteFunc) (futureNode, int, error) {
func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree, previous *data.Tree, complete fileCompleteFunc) (futureNode, int, error) {
var node *restic.Node
var node *data.Node
if snPath != "/" {
if atree.FileInfoPath == "" {
return futureNode{}, 0, errors.Errorf("FileInfoPath for %v is empty", snPath)
@@ -673,7 +674,7 @@ func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree,
}
} else {
// fake root node
node = &restic.Node{}
node = &data.Node{}
}
debug.Log("%v (%v nodes), parent %v", snPath, len(atree.Nodes), previous)
@@ -721,7 +722,7 @@ func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree,
}
// not a leaf node, archive subtree
fn, _, err := arch.saveTree(ctx, join(snPath, name), &subatree, oldSubtree, func(n *restic.Node, is ItemStats) {
fn, _, err := arch.saveTree(ctx, join(snPath, name), &subatree, oldSubtree, func(n *data.Node, is ItemStats) {
arch.trackItem(snItem, oldNode, n, is, time.Since(start))
})
if err != nil {
@@ -740,7 +741,7 @@ func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree,
return fn, len(nodes), nil
}
func (arch *Archiver) dirPathToNode(snPath, target string) (node *restic.Node, err error) {
func (arch *Archiver) dirPathToNode(snPath, target string) (node *data.Node, err error) {
meta, err := arch.FS.OpenFile(target, 0, true)
if err != nil {
return nil, err
@@ -759,7 +760,7 @@ func (arch *Archiver) dirPathToNode(snPath, target string) (node *restic.Node, e
if err != nil {
return nil, err
}
if node.Type != restic.NodeTypeDir {
if node.Type != data.NodeTypeDir {
return nil, errors.Errorf("path is not a directory: %v", target)
}
return node, err
@@ -802,19 +803,19 @@ func resolveRelativeTargets(filesys fs.FS, targets []string) ([]string, error) {
// SnapshotOptions collect attributes for a new snapshot.
type SnapshotOptions struct {
Tags restic.TagList
Tags data.TagList
Hostname string
Excludes []string
BackupStart time.Time
Time time.Time
ParentSnapshot *restic.Snapshot
ParentSnapshot *data.Snapshot
ProgramVersion string
// SkipIfUnchanged omits the snapshot creation if it is identical to the parent snapshot.
SkipIfUnchanged bool
}
// loadParentTree loads a tree referenced by snapshot id. If id is null, nil is returned.
func (arch *Archiver) loadParentTree(ctx context.Context, sn *restic.Snapshot) *restic.Tree {
func (arch *Archiver) loadParentTree(ctx context.Context, sn *data.Snapshot) *data.Tree {
if sn == nil {
return nil
}
@@ -825,7 +826,7 @@ func (arch *Archiver) loadParentTree(ctx context.Context, sn *restic.Snapshot) *
}
debug.Log("load parent tree %v", *sn.Tree)
tree, err := restic.LoadTree(ctx, arch.Repo, *sn.Tree)
tree, err := data.LoadTree(ctx, arch.Repo, *sn.Tree)
if err != nil {
debug.Log("unable to load tree %v: %v", *sn.Tree, err)
_ = arch.error("/", arch.wrapLoadTreeError(*sn.Tree, err))
@@ -858,7 +859,7 @@ func (arch *Archiver) stopWorkers() {
}
// Snapshot saves several targets and returns a snapshot.
func (arch *Archiver) Snapshot(ctx context.Context, targets []string, opts SnapshotOptions) (*restic.Snapshot, restic.ID, *Summary, error) {
func (arch *Archiver) Snapshot(ctx context.Context, targets []string, opts SnapshotOptions) (*data.Snapshot, restic.ID, *Summary, error) {
arch.summary = &Summary{
BackupStart: opts.BackupStart,
}
@@ -886,7 +887,7 @@ func (arch *Archiver) Snapshot(ctx context.Context, targets []string, opts Snaps
arch.runWorkers(wgCtx, wg)
debug.Log("starting snapshot")
fn, nodeCount, err := arch.saveTree(wgCtx, "/", atree, arch.loadParentTree(wgCtx, opts.ParentSnapshot), func(_ *restic.Node, is ItemStats) {
fn, nodeCount, err := arch.saveTree(wgCtx, "/", atree, arch.loadParentTree(wgCtx, opts.ParentSnapshot), func(_ *data.Node, is ItemStats) {
arch.trackItem("/", nil, nil, is, time.Since(start))
})
if err != nil {
@@ -934,7 +935,7 @@ func (arch *Archiver) Snapshot(ctx context.Context, targets []string, opts Snaps
}
}
sn, err := restic.NewSnapshot(targets, opts.Tags, opts.Hostname, opts.Time)
sn, err := data.NewSnapshot(targets, opts.Tags, opts.Hostname, opts.Time)
if err != nil {
return nil, restic.ID{}, nil, err
}
@@ -946,7 +947,7 @@ func (arch *Archiver) Snapshot(ctx context.Context, targets []string, opts Snaps
}
sn.Tree = &rootTreeID
arch.summary.BackupEnd = time.Now()
sn.Summary = &restic.SnapshotSummary{
sn.Summary = &data.SnapshotSummary{
BackupStart: arch.summary.BackupStart,
BackupEnd: arch.summary.BackupEnd,
@@ -964,7 +965,7 @@ func (arch *Archiver) Snapshot(ctx context.Context, targets []string, opts Snaps
TotalBytesProcessed: arch.summary.ProcessedBytes,
}
id, err := restic.SaveSnapshot(ctx, arch.Repo, sn)
id, err := data.SaveSnapshot(ctx, arch.Repo, sn)
if err != nil {
return nil, restic.ID{}, nil, err
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/restic/restic/internal/backend"
"github.com/restic/restic/internal/backend/mem"
"github.com/restic/restic/internal/checker"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/feature"
"github.com/restic/restic/internal/fs"
@@ -37,7 +38,7 @@ func prepareTempdirRepoSrc(t testing.TB, src TestDir) (string, restic.Repository
return tempdir, repo
}
func saveFile(t testing.TB, repo archiverRepo, filename string, filesystem fs.FS) (*restic.Node, ItemStats) {
func saveFile(t testing.TB, repo archiverRepo, filename string, filesystem fs.FS) (*data.Node, ItemStats) {
wg, ctx := errgroup.WithContext(context.TODO())
repo.StartPackUploader(ctx, wg)
@@ -52,7 +53,7 @@ func saveFile(t testing.TB, repo archiverRepo, filename string, filesystem fs.FS
var (
completeReadingCallback bool
completeCallbackNode *restic.Node
completeCallbackNode *data.Node
completeCallbackStats ItemStats
completeCallback bool
@@ -66,7 +67,7 @@ func saveFile(t testing.TB, repo archiverRepo, filename string, filesystem fs.FS
}
}
complete := func(node *restic.Node, stats ItemStats) {
complete := func(node *data.Node, stats ItemStats) {
completeCallback = true
completeCallbackNode = node
completeCallbackStats = stats
@@ -427,8 +428,8 @@ func (repo *blobCountingRepo) SaveBlob(ctx context.Context, t restic.BlobType, b
return id, exists, size, err
}
func (repo *blobCountingRepo) SaveTree(ctx context.Context, t *restic.Tree) (restic.ID, error) {
id, err := restic.SaveTree(ctx, repo.archiverRepo, t)
func (repo *blobCountingRepo) SaveTree(ctx context.Context, t *data.Tree) (restic.ID, error) {
id, err := data.SaveTree(ctx, repo.archiverRepo, t)
h := restic.BlobHandle{ID: id, Type: restic.TreeBlob}
repo.m.Lock()
repo.saved[h]++
@@ -548,7 +549,7 @@ func rename(t testing.TB, oldname, newname string) {
}
}
func nodeFromFile(t testing.TB, localFs fs.FS, filename string) *restic.Node {
func nodeFromFile(t testing.TB, localFs fs.FS, filename string) *data.Node {
meta, err := localFs.OpenFile(filename, fs.O_NOFOLLOW, true)
rtest.OK(t, err)
node, err := meta.ToNode(false, t.Logf)
@@ -724,7 +725,7 @@ func TestFilChangedSpecialCases(t *testing.T) {
t.Run("type-change", func(t *testing.T) {
fi := lstat(t, filename)
node := nodeFromFile(t, &fs.Local{}, filename)
node.Type = restic.NodeTypeSymlink
node.Type = data.NodeTypeSymlink
if !fileChanged(fi, node, 0) {
t.Fatal("node with changed type detected as unchanged")
}
@@ -865,8 +866,8 @@ func TestArchiverSaveDir(t *testing.T) {
}
node.Name = targetNodeName
tree := &restic.Tree{Nodes: []*restic.Node{node}}
treeID, err := restic.SaveTree(ctx, repo, tree)
tree := &data.Tree{Nodes: []*data.Node{node}}
treeID, err := data.SaveTree(ctx, repo, tree)
if err != nil {
t.Fatal(err)
}
@@ -1679,7 +1680,7 @@ func (f MockFile) Read(p []byte) (int, error) {
return n, err
}
func checkSnapshotStats(t *testing.T, sn *restic.Snapshot, stat Summary) {
func checkSnapshotStats(t *testing.T, sn *data.Snapshot, stat Summary) {
t.Helper()
rtest.Equals(t, stat.BackupStart, sn.Summary.BackupStart, "BackupStart")
// BackupEnd is set to time.Now() and can't be compared to a fixed value
@@ -2219,7 +2220,7 @@ func TestArchiverAbortEarlyOnError(t *testing.T) {
}
}
func snapshot(t testing.TB, repo archiverRepo, fs fs.FS, parent *restic.Snapshot, filename string) (*restic.Snapshot, *restic.Node) {
func snapshot(t testing.TB, repo archiverRepo, fs fs.FS, parent *data.Snapshot, filename string) (*data.Snapshot, *data.Node) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -2234,7 +2235,7 @@ func snapshot(t testing.TB, repo archiverRepo, fs fs.FS, parent *restic.Snapshot
t.Fatal(err)
}
tree, err := restic.LoadTree(ctx, repo, *snapshot.Tree)
tree, err := data.LoadTree(ctx, repo, *snapshot.Tree)
if err != nil {
t.Fatal(err)
}
@@ -2251,7 +2252,7 @@ type overrideFS struct {
fs.FS
overrideFI *fs.ExtendedFileInfo
resetFIOnRead bool
overrideNode *restic.Node
overrideNode *data.Node
overrideErr error
}
@@ -2287,7 +2288,7 @@ func (f overrideFile) MakeReadable() error {
return f.File.MakeReadable()
}
func (f overrideFile) ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*restic.Node, error) {
func (f overrideFile) ToNode(ignoreXattrListError bool, warnf func(format string, args ...any)) (*data.Node, error) {
if f.ofs.overrideNode == nil {
return f.File.ToNode(ignoreXattrListError, warnf)
}
@@ -2328,7 +2329,7 @@ func TestMetadataChanged(t *testing.T) {
fs := &overrideFS{
FS: localFS,
overrideFI: fi,
overrideNode: &restic.Node{},
overrideNode: &data.Node{},
}
*fs.overrideNode = *want
@@ -2451,11 +2452,11 @@ func TestRacyFileTypeSwap(t *testing.T) {
}
type mockToNoder struct {
node *restic.Node
node *data.Node
err error
}
func (m *mockToNoder) ToNode(_ bool, _ func(format string, args ...any)) (*restic.Node, error) {
func (m *mockToNoder) ToNode(_ bool, _ func(format string, args ...any)) (*data.Node, error) {
return m.node, m.err
}
@@ -2474,7 +2475,7 @@ func TestMetadataBackupErrorFiltering(t *testing.T) {
}
nonExistNoder := &mockToNoder{
node: &restic.Node{Type: restic.NodeTypeFile},
node: &data.Node{Type: data.NodeTypeFile},
err: fmt.Errorf("not found"),
}
@@ -2487,7 +2488,7 @@ func TestMetadataBackupErrorFiltering(t *testing.T) {
// check that errors from reading irregular file are not filtered
filteredErr = nil
nonExistNoder = &mockToNoder{
node: &restic.Node{Type: restic.NodeTypeIrregular},
node: &data.Node{Type: data.NodeTypeIrregular},
err: fmt.Errorf(`unsupported file type "irregular"`),
}
node, err = arch.nodeFromFileInfo("file", filename, nonExistNoder, false)
@@ -2515,8 +2516,8 @@ func TestIrregularFile(t *testing.T) {
override := &overrideFS{
FS: fs.Local{},
overrideFI: fi,
overrideNode: &restic.Node{
Type: restic.NodeTypeIrregular,
overrideNode: &data.Node{
Type: data.NodeTypeIrregular,
},
overrideErr: fmt.Errorf(`unsupported file type "irregular"`),
}

View File

@@ -6,13 +6,13 @@ package archiver
import (
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/feature"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func statAndSnapshot(t *testing.T, repo archiverRepo, name string) (*restic.Node, *restic.Node) {
func statAndSnapshot(t *testing.T, repo archiverRepo, name string) (*data.Node, *data.Node) {
want := nodeFromFile(t, &fs.Local{}, name)
_, node := snapshot(t, repo, &fs.Local{}, nil, name)
return want, node

View File

@@ -7,6 +7,7 @@ import (
"sync"
"github.com/restic/chunker"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
@@ -28,7 +29,7 @@ type fileSaver struct {
CompleteBlob func(bytes uint64)
NodeFromFileInfo func(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*restic.Node, error)
NodeFromFileInfo func(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*data.Node, error)
}
// newFileSaver returns a new file saver. A worker pool with fileWorkers is
@@ -64,7 +65,7 @@ func (s *fileSaver) TriggerShutdown() {
}
// fileCompleteFunc is called when the file has been saved.
type fileCompleteFunc func(*restic.Node, ItemStats)
type fileCompleteFunc func(*data.Node, ItemStats)
// Save stores the file f and returns the data once it has been completed. The
// file is closed by Save. completeReading is only called if the file was read
@@ -160,7 +161,7 @@ func (s *fileSaver) saveFile(ctx context.Context, chnker *chunker.Chunker, snPat
return
}
if node.Type != restic.NodeTypeFile {
if node.Type != data.NodeTypeFile {
_ = f.Close()
completeError(errors.Errorf("node type %q is wrong", node.Type))
return

View File

@@ -9,6 +9,7 @@ import (
"testing"
"github.com/restic/chunker"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/test"
@@ -49,7 +50,7 @@ func startFileSaver(ctx context.Context, t testing.TB, _ fs.FS) (*fileSaver, con
}
s := newFileSaver(ctx, wg, saveBlob, pol, workers, workers)
s.NodeFromFileInfo = func(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*restic.Node, error) {
s.NodeFromFileInfo = func(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*data.Node, error) {
return meta.ToNode(ignoreXattrListError, t.Logf)
}
@@ -64,7 +65,7 @@ func TestFileSaver(t *testing.T) {
startFn := func() {}
completeReadingFn := func() {}
completeFn := func(*restic.Node, ItemStats) {}
completeFn := func(*data.Node, ItemStats) {}
testFs := fs.Local{}
s, ctx, wg := startFileSaver(ctx, t, testFs)

View File

@@ -11,13 +11,14 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
)
// TestSnapshot creates a new snapshot of path.
func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *restic.ID) *restic.Snapshot {
func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *restic.ID) *data.Snapshot {
arch := New(repo, fs.Local{}, Options{})
opts := SnapshotOptions{
Time: time.Now(),
@@ -25,7 +26,7 @@ func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *res
Tags: []string{"test"},
}
if parent != nil {
sn, err := restic.LoadSnapshot(context.TODO(), repo, *parent)
sn, err := data.LoadSnapshot(context.TODO(), repo, *parent)
if err != nil {
t.Fatal(err)
}
@@ -232,7 +233,7 @@ func TestEnsureFiles(t testing.TB, target string, dir TestDir) {
}
// TestEnsureFileContent checks if the file in the repo is the same as file.
func TestEnsureFileContent(ctx context.Context, t testing.TB, repo restic.BlobLoader, filename string, node *restic.Node, file TestFile) {
func TestEnsureFileContent(ctx context.Context, t testing.TB, repo restic.BlobLoader, filename string, node *data.Node, file TestFile) {
if int(node.Size) != len(file.Content) {
t.Fatalf("%v: wrong node size: want %d, got %d", filename, node.Size, len(file.Content))
return
@@ -263,7 +264,7 @@ func TestEnsureFileContent(ctx context.Context, t testing.TB, repo restic.BlobLo
func TestEnsureTree(ctx context.Context, t testing.TB, prefix string, repo restic.BlobLoader, treeID restic.ID, dir TestDir) {
t.Helper()
tree, err := restic.LoadTree(ctx, repo, treeID)
tree, err := data.LoadTree(ctx, repo, treeID)
if err != nil {
t.Fatal(err)
return
@@ -289,7 +290,7 @@ func TestEnsureTree(ctx context.Context, t testing.TB, prefix string, repo resti
switch e := entry.(type) {
case TestDir:
if node.Type != restic.NodeTypeDir {
if node.Type != data.NodeTypeDir {
t.Errorf("tree node %v has wrong type %q, want %q", nodePrefix, node.Type, "dir")
return
}
@@ -301,12 +302,12 @@ func TestEnsureTree(ctx context.Context, t testing.TB, prefix string, repo resti
TestEnsureTree(ctx, t, path.Join(prefix, node.Name), repo, *node.Subtree, e)
case TestFile:
if node.Type != restic.NodeTypeFile {
if node.Type != data.NodeTypeFile {
t.Errorf("tree node %v has wrong type %q, want %q", nodePrefix, node.Type, "file")
}
TestEnsureFileContent(ctx, t, repo, nodePrefix, node, e)
case TestSymlink:
if node.Type != restic.NodeTypeSymlink {
if node.Type != data.NodeTypeSymlink {
t.Errorf("tree node %v has wrong type %q, want %q", nodePrefix, node.Type, "symlink")
}
@@ -331,7 +332,7 @@ func TestEnsureSnapshot(t testing.TB, repo restic.Repository, snapshotID restic.
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sn, err := restic.LoadSnapshot(ctx, repo, snapshotID)
sn, err := data.LoadSnapshot(ctx, repo, snapshotID)
if err != nil {
t.Fatal(err)
return

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/restic"
"golang.org/x/sync/errgroup"
@@ -42,7 +43,7 @@ func (s *treeSaver) TriggerShutdown() {
}
// Save stores the dir d and returns the data once it has been completed.
func (s *treeSaver) Save(ctx context.Context, snPath string, target string, node *restic.Node, nodes []futureNode, complete fileCompleteFunc) futureNode {
func (s *treeSaver) Save(ctx context.Context, snPath string, target string, node *data.Node, nodes []futureNode, complete fileCompleteFunc) futureNode {
fn, ch := newFutureNode()
job := saveTreeJob{
snPath: snPath,
@@ -65,22 +66,22 @@ func (s *treeSaver) Save(ctx context.Context, snPath string, target string, node
type saveTreeJob struct {
snPath string
target string
node *restic.Node
node *data.Node
nodes []futureNode
ch chan<- futureNodeResult
complete fileCompleteFunc
}
// save stores the nodes as a tree in the repo.
func (s *treeSaver) save(ctx context.Context, job *saveTreeJob) (*restic.Node, ItemStats, error) {
func (s *treeSaver) save(ctx context.Context, job *saveTreeJob) (*data.Node, ItemStats, error) {
var stats ItemStats
node := job.node
nodes := job.nodes
// allow GC of nodes array once the loop is finished
job.nodes = nil
builder := restic.NewTreeJSONBuilder()
var lastNode *restic.Node
builder := data.NewTreeJSONBuilder()
var lastNode *data.Node
for i, fn := range nodes {
// fn is a copy, so clear the original value explicitly
@@ -110,7 +111,7 @@ func (s *treeSaver) save(ctx context.Context, job *saveTreeJob) (*restic.Node, I
}
err := builder.AddNode(fnr.node)
if err != nil && errors.Is(err, restic.ErrTreeNotOrdered) && lastNode != nil && fnr.node.Equals(*lastNode) {
if err != nil && errors.Is(err, data.ErrTreeNotOrdered) && lastNode != nil && fnr.node.Equals(*lastNode) {
debug.Log("insert %v failed: %v", fnr.node.Name, err)
// ignore error if an _identical_ node already exists, but nevertheless issue a warning
_ = s.errFn(fnr.target, err)

View File

@@ -6,6 +6,7 @@ import (
"runtime"
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/test"
@@ -46,7 +47,7 @@ func TestTreeSaver(t *testing.T) {
var results []futureNode
for i := 0; i < 20; i++ {
node := &restic.Node{
node := &data.Node{
Name: fmt.Sprintf("file-%d", i),
}
@@ -86,11 +87,11 @@ func TestTreeSaverError(t *testing.T) {
var results []futureNode
for i := 0; i < test.trees; i++ {
node := &restic.Node{
node := &data.Node{
Name: fmt.Sprintf("file-%d", i),
}
nodes := []futureNode{
newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
newFutureNodeWithResult(futureNodeResult{node: &data.Node{
Name: fmt.Sprintf("child-%d", i),
}}),
}
@@ -125,20 +126,20 @@ func TestTreeSaverDuplicates(t *testing.T) {
ctx, cancel, b, shutdown := setupTreeSaver()
defer cancel()
node := &restic.Node{
node := &data.Node{
Name: "file",
}
nodes := []futureNode{
newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
newFutureNodeWithResult(futureNodeResult{node: &data.Node{
Name: "child",
}}),
}
if identicalNodes {
nodes = append(nodes, newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
nodes = append(nodes, newFutureNodeWithResult(futureNodeResult{node: &data.Node{
Name: "child",
}}))
} else {
nodes = append(nodes, newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
nodes = append(nodes, newFutureNodeWithResult(futureNodeResult{node: &data.Node{
Name: "child",
Size: 42,
}}))

View File

@@ -8,6 +8,7 @@ import (
"sync"
"github.com/klauspost/compress/zstd"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
@@ -256,7 +257,7 @@ func (e *TreeError) Error() string {
}
// checkTreeWorker checks the trees received and sends out errors to errChan.
func (c *Checker) checkTreeWorker(ctx context.Context, trees <-chan restic.TreeItem, out chan<- error) {
func (c *Checker) checkTreeWorker(ctx context.Context, trees <-chan data.TreeItem, out chan<- error) {
for job := range trees {
debug.Log("check tree %v (tree %v, err %v)", job.ID, job.Tree, job.Error)
@@ -281,7 +282,7 @@ func (c *Checker) checkTreeWorker(ctx context.Context, trees <-chan restic.TreeI
}
func loadSnapshotTreeIDs(ctx context.Context, lister restic.Lister, repo restic.LoaderUnpacked) (ids restic.IDs, errs []error) {
err := restic.ForAllSnapshots(ctx, lister, repo, nil, func(id restic.ID, sn *restic.Snapshot, err error) error {
err := data.ForAllSnapshots(ctx, lister, repo, nil, func(id restic.ID, sn *data.Snapshot, err error) error {
if err != nil {
errs = append(errs, err)
return nil
@@ -315,7 +316,7 @@ func (c *Checker) Structure(ctx context.Context, p *progress.Counter, errChan ch
}
wg, ctx := errgroup.WithContext(ctx)
treeStream := restic.StreamTrees(ctx, wg, c.repo, trees, func(treeID restic.ID) bool {
treeStream := data.StreamTrees(ctx, wg, c.repo, trees, func(treeID restic.ID) bool {
// blobRefs may be accessed in parallel by checkTree
c.blobRefs.Lock()
h := restic.BlobHandle{ID: treeID, Type: restic.TreeBlob}
@@ -344,12 +345,12 @@ func (c *Checker) Structure(ctx context.Context, p *progress.Counter, errChan ch
}
}
func (c *Checker) checkTree(id restic.ID, tree *restic.Tree) (errs []error) {
func (c *Checker) checkTree(id restic.ID, tree *data.Tree) (errs []error) {
debug.Log("checking tree %v", id)
for _, node := range tree.Nodes {
switch node.Type {
case restic.NodeTypeFile:
case data.NodeTypeFile:
if node.Content == nil {
errs = append(errs, &Error{TreeID: id, Err: errors.Errorf("file %q has nil blob list", node.Name)})
}
@@ -385,7 +386,7 @@ func (c *Checker) checkTree(id restic.ID, tree *restic.Tree) (errs []error) {
c.blobRefs.Unlock()
}
case restic.NodeTypeDir:
case data.NodeTypeDir:
if node.Subtree == nil {
errs = append(errs, &Error{TreeID: id, Err: errors.Errorf("dir node %q has no subtree", node.Name)})
continue
@@ -396,7 +397,7 @@ func (c *Checker) checkTree(id restic.ID, tree *restic.Tree) (errs []error) {
continue
}
case restic.NodeTypeSymlink, restic.NodeTypeSocket, restic.NodeTypeCharDev, restic.NodeTypeDev, restic.NodeTypeFifo:
case data.NodeTypeSymlink, data.NodeTypeSocket, data.NodeTypeCharDev, data.NodeTypeDev, data.NodeTypeFifo:
// nothing to check
default:

View File

@@ -16,6 +16,7 @@ import (
"github.com/restic/restic/internal/archiver"
"github.com/restic/restic/internal/backend"
"github.com/restic/restic/internal/checker"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/repository/hashing"
@@ -440,7 +441,7 @@ type loadTreesOnceRepository struct {
DuplicateTree bool
}
func (r *loadTreesOnceRepository) LoadTree(ctx context.Context, id restic.ID) (*restic.Tree, error) {
func (r *loadTreesOnceRepository) LoadTree(ctx context.Context, id restic.ID) (*data.Tree, error) {
r.mutex.Lock()
defer r.mutex.Unlock()
@@ -450,7 +451,7 @@ func (r *loadTreesOnceRepository) LoadTree(ctx context.Context, id restic.ID) (*
return nil, errors.Errorf("trying to load tree with id %v twice", id)
}
r.loadedTrees.Insert(id)
return restic.LoadTree(ctx, r.Repository, id)
return data.LoadTree(ctx, r.Repository, id)
}
func TestCheckerNoDuplicateTreeDecodes(t *testing.T) {
@@ -481,11 +482,11 @@ type delayRepository struct {
Unblocker sync.Once
}
func (r *delayRepository) LoadTree(ctx context.Context, id restic.ID) (*restic.Tree, error) {
func (r *delayRepository) LoadTree(ctx context.Context, id restic.ID) (*data.Tree, error) {
if id == r.DelayTree {
<-r.UnblockChannel
}
return restic.LoadTree(ctx, r.Repository, id)
return data.LoadTree(ctx, r.Repository, id)
}
func (r *delayRepository) LookupBlobSize(t restic.BlobType, id restic.ID) (uint, bool) {
@@ -507,20 +508,20 @@ func TestCheckerBlobTypeConfusion(t *testing.T) {
repo := repository.TestRepository(t)
damagedNode := &restic.Node{
damagedNode := &data.Node{
Name: "damaged",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Mode: 0644,
Size: 42,
Content: restic.IDs{restic.TestParseID("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")},
}
damagedTree := &restic.Tree{
Nodes: []*restic.Node{damagedNode},
damagedTree := &data.Tree{
Nodes: []*data.Node{damagedNode},
}
wg, wgCtx := errgroup.WithContext(ctx)
repo.StartPackUploader(wgCtx, wg)
id, err := restic.SaveTree(ctx, repo, damagedTree)
id, err := data.SaveTree(ctx, repo, damagedTree)
test.OK(t, repo.Flush(ctx))
test.OK(t, err)
@@ -532,35 +533,35 @@ func TestCheckerBlobTypeConfusion(t *testing.T) {
_, _, _, err = repo.SaveBlob(ctx, restic.DataBlob, buf, id, false)
test.OK(t, err)
malNode := &restic.Node{
malNode := &data.Node{
Name: "aaaaa",
Type: restic.NodeTypeFile,
Type: data.NodeTypeFile,
Mode: 0644,
Size: uint64(len(buf)),
Content: restic.IDs{id},
}
dirNode := &restic.Node{
dirNode := &data.Node{
Name: "bbbbb",
Type: restic.NodeTypeDir,
Type: data.NodeTypeDir,
Mode: 0755,
Subtree: &id,
}
rootTree := &restic.Tree{
Nodes: []*restic.Node{malNode, dirNode},
rootTree := &data.Tree{
Nodes: []*data.Node{malNode, dirNode},
}
rootID, err := restic.SaveTree(ctx, repo, rootTree)
rootID, err := data.SaveTree(ctx, repo, rootTree)
test.OK(t, err)
test.OK(t, repo.Flush(ctx))
snapshot, err := restic.NewSnapshot([]string{"/damaged"}, []string{"test"}, "foo", time.Now())
snapshot, err := data.NewSnapshot([]string{"/damaged"}, []string{"test"}, "foo", time.Now())
test.OK(t, err)
snapshot.Tree = &rootID
snapID, err := restic.SaveSnapshot(ctx, repo, snapshot)
snapID, err := data.SaveSnapshot(ctx, repo, snapshot)
test.OK(t, err)
t.Logf("saved snapshot %v", snapID.Str())
@@ -637,7 +638,7 @@ func benchmarkSnapshotScaling(t *testing.B, newSnapshots int) {
defer cleanup()
snID := restic.TestParseID("51d249d28815200d59e4be7b3f21a157b864dc343353df9d8e498220c2499b02")
sn2, err := restic.LoadSnapshot(context.TODO(), repo, snID)
sn2, err := data.LoadSnapshot(context.TODO(), repo, snID)
if err != nil {
t.Fatal(err)
}
@@ -645,13 +646,13 @@ func benchmarkSnapshotScaling(t *testing.B, newSnapshots int) {
treeID := sn2.Tree
for i := 0; i < newSnapshots; i++ {
sn, err := restic.NewSnapshot([]string{"test" + strconv.Itoa(i)}, nil, "", time.Now())
sn, err := data.NewSnapshot([]string{"test" + strconv.Itoa(i)}, nil, "", time.Now())
if err != nil {
t.Fatal(err)
}
sn.Tree = treeID
_, err = restic.SaveSnapshot(context.TODO(), repo, sn)
_, err = data.SaveSnapshot(context.TODO(), repo, sn)
if err != nil {
t.Fatal(err)
}

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"testing"

View File

@@ -1,23 +1,24 @@
package restic
package data
import (
"context"
"sync"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui/progress"
"golang.org/x/sync/errgroup"
)
// FindUsedBlobs traverses the tree ID and adds all seen blobs (trees and data
// blobs) to the set blobs. Already seen tree blobs will not be visited again.
func FindUsedBlobs(ctx context.Context, repo Loader, treeIDs IDs, blobs FindBlobSet, p *progress.Counter) error {
func FindUsedBlobs(ctx context.Context, repo restic.Loader, treeIDs restic.IDs, blobs restic.FindBlobSet, p *progress.Counter) error {
var lock sync.Mutex
wg, ctx := errgroup.WithContext(ctx)
treeStream := StreamTrees(ctx, wg, repo, treeIDs, func(treeID ID) bool {
treeStream := StreamTrees(ctx, wg, repo, treeIDs, func(treeID restic.ID) bool {
// locking is necessary the goroutine below concurrently adds data blobs
lock.Lock()
h := BlobHandle{ID: treeID, Type: TreeBlob}
h := restic.BlobHandle{ID: treeID, Type: restic.TreeBlob}
blobReferenced := blobs.Has(h)
// noop if already referenced
blobs.Insert(h)
@@ -36,7 +37,7 @@ func FindUsedBlobs(ctx context.Context, repo Loader, treeIDs IDs, blobs FindBlob
switch node.Type {
case NodeTypeFile:
for _, blob := range node.Content {
blobs.Insert(BlobHandle{ID: blob, Type: DataBlob})
blobs.Insert(restic.BlobHandle{ID: blob, Type: restic.DataBlob})
}
}
}

View File

@@ -1,4 +1,4 @@
package restic_test
package data_test
import (
"bufio"
@@ -12,6 +12,7 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
@@ -86,9 +87,9 @@ var findTestTime = time.Unix(1469960361, 23)
func TestFindUsedBlobs(t *testing.T) {
repo := repository.TestRepository(t)
var snapshots []*restic.Snapshot
var snapshots []*data.Snapshot
for i := 0; i < findTestSnapshots; i++ {
sn := restic.TestCreateSnapshot(t, repo, findTestTime.Add(time.Duration(i)*time.Second), findTestDepth)
sn := data.TestCreateSnapshot(t, repo, findTestTime.Add(time.Duration(i)*time.Second), findTestDepth)
t.Logf("snapshot %v saved, tree %v", sn.ID().Str(), sn.Tree.Str())
snapshots = append(snapshots, sn)
}
@@ -98,7 +99,7 @@ func TestFindUsedBlobs(t *testing.T) {
for i, sn := range snapshots {
usedBlobs := restic.NewBlobSet()
err := restic.FindUsedBlobs(context.TODO(), repo, restic.IDs{*sn.Tree}, usedBlobs, p)
err := data.FindUsedBlobs(context.TODO(), repo, restic.IDs{*sn.Tree}, usedBlobs, p)
if err != nil {
t.Errorf("FindUsedBlobs returned error: %v", err)
continue
@@ -131,7 +132,7 @@ func TestMultiFindUsedBlobs(t *testing.T) {
var snapshotTrees restic.IDs
for i := 0; i < findTestSnapshots; i++ {
sn := restic.TestCreateSnapshot(t, repo, findTestTime.Add(time.Duration(i)*time.Second), findTestDepth)
sn := data.TestCreateSnapshot(t, repo, findTestTime.Add(time.Duration(i)*time.Second), findTestDepth)
t.Logf("snapshot %v saved, tree %v", sn.ID().Str(), sn.Tree.Str())
snapshotTrees = append(snapshotTrees, *sn.Tree)
}
@@ -148,7 +149,7 @@ func TestMultiFindUsedBlobs(t *testing.T) {
// run twice to check progress bar handling of duplicate tree roots
usedBlobs := restic.NewBlobSet()
for i := 1; i < 3; i++ {
err := restic.FindUsedBlobs(context.TODO(), repo, snapshotTrees, usedBlobs, p)
err := data.FindUsedBlobs(context.TODO(), repo, snapshotTrees, usedBlobs, p)
test.OK(t, err)
v, _ := p.Get()
test.Equals(t, v, uint64(i*len(snapshotTrees)))
@@ -177,16 +178,16 @@ func (r ForbiddenRepo) Connections() uint {
func TestFindUsedBlobsSkipsSeenBlobs(t *testing.T) {
repo := repository.TestRepository(t)
snapshot := restic.TestCreateSnapshot(t, repo, findTestTime, findTestDepth)
snapshot := data.TestCreateSnapshot(t, repo, findTestTime, findTestDepth)
t.Logf("snapshot %v saved, tree %v", snapshot.ID().Str(), snapshot.Tree.Str())
usedBlobs := restic.NewBlobSet()
err := restic.FindUsedBlobs(context.TODO(), repo, restic.IDs{*snapshot.Tree}, usedBlobs, nil)
err := data.FindUsedBlobs(context.TODO(), repo, restic.IDs{*snapshot.Tree}, usedBlobs, nil)
if err != nil {
t.Fatalf("FindUsedBlobs returned error: %v", err)
}
err = restic.FindUsedBlobs(context.TODO(), ForbiddenRepo{}, restic.IDs{*snapshot.Tree}, usedBlobs, nil)
err = data.FindUsedBlobs(context.TODO(), ForbiddenRepo{}, restic.IDs{*snapshot.Tree}, usedBlobs, nil)
if err != nil {
t.Fatalf("FindUsedBlobs returned error: %v", err)
}
@@ -195,13 +196,13 @@ func TestFindUsedBlobsSkipsSeenBlobs(t *testing.T) {
func BenchmarkFindUsedBlobs(b *testing.B) {
repo := repository.TestRepository(b)
sn := restic.TestCreateSnapshot(b, repo, findTestTime, findTestDepth)
sn := data.TestCreateSnapshot(b, repo, findTestTime, findTestDepth)
b.ResetTimer()
for i := 0; i < b.N; i++ {
blobs := restic.NewBlobSet()
err := restic.FindUsedBlobs(context.TODO(), repo, restic.IDs{*sn.Tree}, blobs, nil)
err := data.FindUsedBlobs(context.TODO(), repo, restic.IDs{*sn.Tree}, blobs, nil)
if err != nil {
b.Error(err)
}

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"bytes"
@@ -13,6 +13,7 @@ import (
"unicode/utf8"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/debug"
)
@@ -105,8 +106,8 @@ type Node struct {
ExtendedAttributes []ExtendedAttribute `json:"extended_attributes,omitempty"`
GenericAttributes map[GenericAttributeType]json.RawMessage `json:"generic_attributes,omitempty"`
Device uint64 `json:"device,omitempty"` // in case of Type == "dev", stat.st_rdev
Content IDs `json:"content"`
Subtree *ID `json:"subtree,omitempty"`
Content restic.IDs `json:"content"`
Subtree *restic.ID `json:"subtree,omitempty"`
Error string `json:"error,omitempty"`

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"encoding/json"

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"encoding/json"

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"context"
@@ -9,26 +9,27 @@ import (
"time"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/restic"
)
// Snapshot is the state of a resource at one point in time.
type Snapshot struct {
Time time.Time `json:"time"`
Parent *ID `json:"parent,omitempty"`
Tree *ID `json:"tree"`
Paths []string `json:"paths"`
Hostname string `json:"hostname,omitempty"`
Username string `json:"username,omitempty"`
UID uint32 `json:"uid,omitempty"`
GID uint32 `json:"gid,omitempty"`
Excludes []string `json:"excludes,omitempty"`
Tags []string `json:"tags,omitempty"`
Original *ID `json:"original,omitempty"`
Time time.Time `json:"time"`
Parent *restic.ID `json:"parent,omitempty"`
Tree *restic.ID `json:"tree"`
Paths []string `json:"paths"`
Hostname string `json:"hostname,omitempty"`
Username string `json:"username,omitempty"`
UID uint32 `json:"uid,omitempty"`
GID uint32 `json:"gid,omitempty"`
Excludes []string `json:"excludes,omitempty"`
Tags []string `json:"tags,omitempty"`
Original *restic.ID `json:"original,omitempty"`
ProgramVersion string `json:"program_version,omitempty"`
Summary *SnapshotSummary `json:"summary,omitempty"`
id *ID // plaintext ID, used during restore
id *restic.ID // plaintext ID, used during restore
}
type SnapshotSummary struct {
@@ -79,9 +80,9 @@ func NewSnapshot(paths []string, tags []string, hostname string, time time.Time)
}
// LoadSnapshot loads the snapshot with the id and returns it.
func LoadSnapshot(ctx context.Context, loader LoaderUnpacked, id ID) (*Snapshot, error) {
func LoadSnapshot(ctx context.Context, loader restic.LoaderUnpacked, id restic.ID) (*Snapshot, error) {
sn := &Snapshot{id: &id}
err := LoadJSONUnpacked(ctx, loader, SnapshotFile, id, sn)
err := restic.LoadJSONUnpacked(ctx, loader, restic.SnapshotFile, id, sn)
if err != nil {
return nil, fmt.Errorf("failed to load snapshot %v: %w", id.Str(), err)
}
@@ -90,8 +91,8 @@ func LoadSnapshot(ctx context.Context, loader LoaderUnpacked, id ID) (*Snapshot,
}
// SaveSnapshot saves the snapshot sn and returns its ID.
func SaveSnapshot(ctx context.Context, repo SaverUnpacked[WriteableFileType], sn *Snapshot) (ID, error) {
return SaveJSONUnpacked(ctx, repo, WriteableSnapshotFile, sn)
func SaveSnapshot(ctx context.Context, repo restic.SaverUnpacked[restic.WriteableFileType], sn *Snapshot) (restic.ID, error) {
return restic.SaveJSONUnpacked(ctx, repo, restic.WriteableSnapshotFile, sn)
}
// ForAllSnapshots reads all snapshots in parallel and calls the
@@ -99,11 +100,11 @@ func SaveSnapshot(ctx context.Context, repo SaverUnpacked[WriteableFileType], sn
// If the called function returns an error, this function is cancelled and
// also returns this error.
// If a snapshot ID is in excludeIDs, it will be ignored.
func ForAllSnapshots(ctx context.Context, be Lister, loader LoaderUnpacked, excludeIDs IDSet, fn func(ID, *Snapshot, error) error) error {
func ForAllSnapshots(ctx context.Context, be restic.Lister, loader restic.LoaderUnpacked, excludeIDs restic.IDSet, fn func(restic.ID, *Snapshot, error) error) error {
var m sync.Mutex
// For most snapshots decoding is nearly for free, thus just assume were only limited by IO
return ParallelList(ctx, be, SnapshotFile, loader.Connections(), func(ctx context.Context, id ID, _ int64) error {
return restic.ParallelList(ctx, be, restic.SnapshotFile, loader.Connections(), func(ctx context.Context, id restic.ID, _ int64) error {
if excludeIDs.Has(id) {
return nil
}
@@ -121,7 +122,7 @@ func (sn Snapshot) String() string {
}
// ID returns the snapshot's ID.
func (sn Snapshot) ID() *ID {
func (sn Snapshot) ID() *restic.ID {
return sn.id
}
@@ -133,7 +134,7 @@ func (sn *Snapshot) fillUserInfo() error {
sn.Username = usr.Username
// set userid and groupid
sn.UID, sn.GID, err = uidGidInt(usr)
sn.UID, sn.GID, err = restic.UidGidInt(usr)
return err
}

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"context"
@@ -8,6 +8,7 @@ import (
"time"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
)
// ErrNoSnapshotFound is returned when no snapshot for the given criteria could be found.
@@ -34,7 +35,7 @@ func (f *SnapshotFilter) matches(sn *Snapshot) bool {
// findLatest finds the latest snapshot with optional target/directory,
// tags, hostname, and timestamp filters.
func (f *SnapshotFilter) findLatest(ctx context.Context, be Lister, loader LoaderUnpacked) (*Snapshot, error) {
func (f *SnapshotFilter) findLatest(ctx context.Context, be restic.Lister, loader restic.LoaderUnpacked) (*Snapshot, error) {
var err error
absTargets := make([]string, 0, len(f.Paths))
@@ -51,7 +52,7 @@ func (f *SnapshotFilter) findLatest(ctx context.Context, be Lister, loader Loade
var latest *Snapshot
err = ForAllSnapshots(ctx, be, loader, nil, func(id ID, snapshot *Snapshot, err error) error {
err = ForAllSnapshots(ctx, be, loader, nil, func(id restic.ID, snapshot *Snapshot, err error) error {
if err != nil {
return errors.Errorf("Error loading snapshot %v: %v", id.Str(), err)
}
@@ -90,14 +91,14 @@ func splitSnapshotID(s string) (id, subfolder string) {
// FindSnapshot takes a string and tries to find a snapshot whose ID matches
// the string as closely as possible.
func FindSnapshot(ctx context.Context, be Lister, loader LoaderUnpacked, s string) (*Snapshot, string, error) {
func FindSnapshot(ctx context.Context, be restic.Lister, loader restic.LoaderUnpacked, s string) (*Snapshot, string, error) {
s, subfolder := splitSnapshotID(s)
// no need to list snapshots if `s` is already a full id
id, err := ParseID(s)
id, err := restic.ParseID(s)
if err != nil {
// find snapshot id with prefix
id, err = Find(ctx, be, SnapshotFile, s)
id, err = restic.Find(ctx, be, restic.SnapshotFile, s)
if err != nil {
return nil, "", err
}
@@ -108,7 +109,7 @@ func FindSnapshot(ctx context.Context, be Lister, loader LoaderUnpacked, s strin
// FindLatest returns either the latest of a filtered list of all snapshots
// or a snapshot specified by `snapshotID`.
func (f *SnapshotFilter) FindLatest(ctx context.Context, be Lister, loader LoaderUnpacked, snapshotID string) (*Snapshot, string, error) {
func (f *SnapshotFilter) FindLatest(ctx context.Context, be restic.Lister, loader restic.LoaderUnpacked, snapshotID string) (*Snapshot, string, error) {
id, subfolder := splitSnapshotID(snapshotID)
if id == "latest" {
sn, err := f.findLatest(ctx, be, loader)
@@ -126,12 +127,12 @@ type SnapshotFindCb func(string, *Snapshot, error) error
var ErrInvalidSnapshotSyntax = errors.New("<snapshot>:<subfolder> syntax not allowed")
// FindAll yields Snapshots, either given explicitly by `snapshotIDs` or filtered from the list of all snapshots.
func (f *SnapshotFilter) FindAll(ctx context.Context, be Lister, loader LoaderUnpacked, snapshotIDs []string, fn SnapshotFindCb) error {
func (f *SnapshotFilter) FindAll(ctx context.Context, be restic.Lister, loader restic.LoaderUnpacked, snapshotIDs []string, fn SnapshotFindCb) error {
if len(snapshotIDs) != 0 {
var err error
usedFilter := false
ids := NewIDSet()
ids := restic.NewIDSet()
// Process all snapshot IDs given as arguments.
for _, s := range snapshotIDs {
if ctx.Err() != nil {
@@ -183,7 +184,7 @@ func (f *SnapshotFilter) FindAll(ctx context.Context, be Lister, loader LoaderUn
return nil
}
return ForAllSnapshots(ctx, be, loader, nil, func(id ID, sn *Snapshot, err error) error {
return ForAllSnapshots(ctx, be, loader, nil, func(id restic.ID, sn *Snapshot, err error) error {
if err == nil && !f.matches(sn) {
return nil
}

View File

@@ -1,21 +1,21 @@
package restic_test
package data_test
import (
"context"
"testing"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/test"
)
func TestFindLatestSnapshot(t *testing.T) {
repo := repository.TestRepository(t)
restic.TestCreateSnapshot(t, repo, parseTimeUTC("2015-05-05 05:05:05"), 1)
restic.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
latestSnapshot := restic.TestCreateSnapshot(t, repo, parseTimeUTC("2019-09-09 09:09:09"), 1)
data.TestCreateSnapshot(t, repo, parseTimeUTC("2015-05-05 05:05:05"), 1)
data.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
latestSnapshot := data.TestCreateSnapshot(t, repo, parseTimeUTC("2019-09-09 09:09:09"), 1)
f := restic.SnapshotFilter{Hosts: []string{"foo"}}
f := data.SnapshotFilter{Hosts: []string{"foo"}}
sn, _, err := f.FindLatest(context.TODO(), repo, repo, "latest")
if err != nil {
t.Fatalf("FindLatest returned error: %v", err)
@@ -28,11 +28,11 @@ func TestFindLatestSnapshot(t *testing.T) {
func TestFindLatestSnapshotWithMaxTimestamp(t *testing.T) {
repo := repository.TestRepository(t)
restic.TestCreateSnapshot(t, repo, parseTimeUTC("2015-05-05 05:05:05"), 1)
desiredSnapshot := restic.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
restic.TestCreateSnapshot(t, repo, parseTimeUTC("2019-09-09 09:09:09"), 1)
data.TestCreateSnapshot(t, repo, parseTimeUTC("2015-05-05 05:05:05"), 1)
desiredSnapshot := data.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
data.TestCreateSnapshot(t, repo, parseTimeUTC("2019-09-09 09:09:09"), 1)
sn, _, err := (&restic.SnapshotFilter{
sn, _, err := (&data.SnapshotFilter{
Hosts: []string{"foo"},
TimestampLimit: parseTimeUTC("2018-08-08 08:08:08"),
}).FindLatest(context.TODO(), repo, repo, "latest")
@@ -47,8 +47,8 @@ func TestFindLatestSnapshotWithMaxTimestamp(t *testing.T) {
func TestFindLatestWithSubpath(t *testing.T) {
repo := repository.TestRepository(t)
restic.TestCreateSnapshot(t, repo, parseTimeUTC("2015-05-05 05:05:05"), 1)
desiredSnapshot := restic.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
data.TestCreateSnapshot(t, repo, parseTimeUTC("2015-05-05 05:05:05"), 1)
desiredSnapshot := data.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
for _, exp := range []struct {
query string
@@ -62,7 +62,7 @@ func TestFindLatestWithSubpath(t *testing.T) {
{desiredSnapshot.ID().String() + ":subfolder", "subfolder"},
} {
t.Run("", func(t *testing.T) {
sn, subfolder, err := (&restic.SnapshotFilter{}).FindLatest(context.TODO(), repo, repo, exp.query)
sn, subfolder, err := (&data.SnapshotFilter{}).FindLatest(context.TODO(), repo, repo, exp.query)
if err != nil {
t.Fatalf("FindLatest returned error: %v", err)
}
@@ -75,13 +75,13 @@ func TestFindLatestWithSubpath(t *testing.T) {
func TestFindAllSubpathError(t *testing.T) {
repo := repository.TestRepository(t)
desiredSnapshot := restic.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
desiredSnapshot := data.TestCreateSnapshot(t, repo, parseTimeUTC("2017-07-07 07:07:07"), 1)
count := 0
test.OK(t, (&restic.SnapshotFilter{}).FindAll(context.TODO(), repo, repo,
test.OK(t, (&data.SnapshotFilter{}).FindAll(context.TODO(), repo, repo,
[]string{"latest:subfolder", desiredSnapshot.ID().Str() + ":subfolder"},
func(id string, sn *restic.Snapshot, err error) error {
if err == restic.ErrInvalidSnapshotSyntax {
func(id string, sn *data.Snapshot, err error) error {
if err == data.ErrInvalidSnapshotSyntax {
count++
return nil
}

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"encoding/json"

View File

@@ -1,41 +1,41 @@
package restic_test
package data_test
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/test"
)
func TestGroupByOptions(t *testing.T) {
for _, exp := range []struct {
from string
opts restic.SnapshotGroupByOptions
opts data.SnapshotGroupByOptions
normalized string
}{
{
from: "",
opts: restic.SnapshotGroupByOptions{},
opts: data.SnapshotGroupByOptions{},
normalized: "",
},
{
from: "host,paths",
opts: restic.SnapshotGroupByOptions{Host: true, Path: true},
opts: data.SnapshotGroupByOptions{Host: true, Path: true},
normalized: "host,paths",
},
{
from: "host,path,tag",
opts: restic.SnapshotGroupByOptions{Host: true, Path: true, Tag: true},
opts: data.SnapshotGroupByOptions{Host: true, Path: true, Tag: true},
normalized: "host,paths,tags",
},
{
from: "hosts,paths,tags",
opts: restic.SnapshotGroupByOptions{Host: true, Path: true, Tag: true},
opts: data.SnapshotGroupByOptions{Host: true, Path: true, Tag: true},
normalized: "host,paths,tags",
},
} {
var opts restic.SnapshotGroupByOptions
var opts data.SnapshotGroupByOptions
test.OK(t, opts.Set(exp.from))
if !cmp.Equal(opts, exp.opts) {
t.Errorf("unexpected opts %s", cmp.Diff(opts, exp.opts))
@@ -43,7 +43,7 @@ func TestGroupByOptions(t *testing.T) {
test.Equals(t, opts.String(), exp.normalized)
}
var opts restic.SnapshotGroupByOptions
var opts data.SnapshotGroupByOptions
err := opts.Set("tags,invalid")
test.Assert(t, err != nil, "missing error on invalid tags")
test.Assert(t, !opts.Host && !opts.Path && !opts.Tag, "unexpected opts %s %s %s", opts.Host, opts.Path, opts.Tag)

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package restic_test
package data_test
import (
"encoding/json"
@@ -10,7 +10,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/data"
)
func parseTimeUTC(s string) time.Time {
@@ -24,7 +24,7 @@ func parseTimeUTC(s string) time.Time {
// Returns the maximum number of snapshots to be kept according to this policy.
// If any of the counts is -1 it will return 0.
func policySum(e *restic.ExpirePolicy) int {
func policySum(e *data.ExpirePolicy) int {
if e.Last == -1 || e.Hourly == -1 || e.Daily == -1 || e.Weekly == -1 || e.Monthly == -1 || e.Yearly == -1 {
return 0
}
@@ -36,11 +36,11 @@ func TestExpireSnapshotOps(t *testing.T) {
data := []struct {
expectEmpty bool
expectSum int
p *restic.ExpirePolicy
p *data.ExpirePolicy
}{
{true, 0, &restic.ExpirePolicy{}},
{true, 0, &restic.ExpirePolicy{Tags: []restic.TagList{}}},
{false, 22, &restic.ExpirePolicy{Daily: 7, Weekly: 2, Monthly: 3, Yearly: 10}},
{true, 0, &data.ExpirePolicy{}},
{true, 0, &data.ExpirePolicy{Tags: []data.TagList{}}},
{false, 22, &data.ExpirePolicy{Daily: 7, Weekly: 2, Monthly: 3, Yearly: 10}},
}
for i, d := range data {
isEmpty := d.p.Empty()
@@ -57,8 +57,8 @@ func TestExpireSnapshotOps(t *testing.T) {
// ApplyPolicyResult is used to marshal/unmarshal the golden files for
// TestApplyPolicy.
type ApplyPolicyResult struct {
Keep restic.Snapshots `json:"keep"`
Reasons []restic.KeepReason `json:"reasons,omitempty"`
Keep data.Snapshots `json:"keep"`
Reasons []data.KeepReason `json:"reasons,omitempty"`
}
func loadGoldenFile(t testing.TB, filename string) (res ApplyPolicyResult) {
@@ -75,7 +75,7 @@ func loadGoldenFile(t testing.TB, filename string) (res ApplyPolicyResult) {
return res
}
func saveGoldenFile(t testing.TB, filename string, keep restic.Snapshots, reasons []restic.KeepReason) {
func saveGoldenFile(t testing.TB, filename string, keep data.Snapshots, reasons []data.KeepReason) {
res := ApplyPolicyResult{
Keep: keep,
Reasons: reasons,
@@ -92,7 +92,7 @@ func saveGoldenFile(t testing.TB, filename string, keep restic.Snapshots, reason
}
func TestApplyPolicy(t *testing.T) {
var testExpireSnapshots = restic.Snapshots{
var testExpireSnapshots = data.Snapshots{
{Time: parseTimeUTC("2014-09-01 10:20:30")},
{Time: parseTimeUTC("2014-09-02 10:20:30")},
{Time: parseTimeUTC("2014-09-05 10:20:30")},
@@ -198,7 +198,7 @@ func TestApplyPolicy(t *testing.T) {
{Time: parseTimeUTC("2016-01-18 12:02:03")},
}
var tests = []restic.ExpirePolicy{
var tests = []data.ExpirePolicy{
{},
{Last: 10},
{Last: 15},
@@ -217,29 +217,29 @@ func TestApplyPolicy(t *testing.T) {
{Daily: 2, Weekly: 2, Monthly: 6},
{Yearly: 10},
{Daily: 7, Weekly: 2, Monthly: 3, Yearly: 10},
{Tags: []restic.TagList{{"foo"}}},
{Tags: []restic.TagList{{"foo", "bar"}}},
{Tags: []restic.TagList{{"foo"}, {"bar"}}},
{Within: restic.ParseDurationOrPanic("1d")},
{Within: restic.ParseDurationOrPanic("2d")},
{Within: restic.ParseDurationOrPanic("7d")},
{Within: restic.ParseDurationOrPanic("1m")},
{Within: restic.ParseDurationOrPanic("1m14d")},
{Within: restic.ParseDurationOrPanic("1y1d1m")},
{Within: restic.ParseDurationOrPanic("13d23h")},
{Within: restic.ParseDurationOrPanic("2m2h")},
{Within: restic.ParseDurationOrPanic("1y2m3d3h")},
{WithinHourly: restic.ParseDurationOrPanic("1y2m3d3h")},
{WithinDaily: restic.ParseDurationOrPanic("1y2m3d3h")},
{WithinWeekly: restic.ParseDurationOrPanic("1y2m3d3h")},
{WithinMonthly: restic.ParseDurationOrPanic("1y2m3d3h")},
{WithinYearly: restic.ParseDurationOrPanic("1y2m3d3h")},
{Within: restic.ParseDurationOrPanic("1h"),
WithinHourly: restic.ParseDurationOrPanic("1d"),
WithinDaily: restic.ParseDurationOrPanic("7d"),
WithinWeekly: restic.ParseDurationOrPanic("1m"),
WithinMonthly: restic.ParseDurationOrPanic("1y"),
WithinYearly: restic.ParseDurationOrPanic("9999y")},
{Tags: []data.TagList{{"foo"}}},
{Tags: []data.TagList{{"foo", "bar"}}},
{Tags: []data.TagList{{"foo"}, {"bar"}}},
{Within: data.ParseDurationOrPanic("1d")},
{Within: data.ParseDurationOrPanic("2d")},
{Within: data.ParseDurationOrPanic("7d")},
{Within: data.ParseDurationOrPanic("1m")},
{Within: data.ParseDurationOrPanic("1m14d")},
{Within: data.ParseDurationOrPanic("1y1d1m")},
{Within: data.ParseDurationOrPanic("13d23h")},
{Within: data.ParseDurationOrPanic("2m2h")},
{Within: data.ParseDurationOrPanic("1y2m3d3h")},
{WithinHourly: data.ParseDurationOrPanic("1y2m3d3h")},
{WithinDaily: data.ParseDurationOrPanic("1y2m3d3h")},
{WithinWeekly: data.ParseDurationOrPanic("1y2m3d3h")},
{WithinMonthly: data.ParseDurationOrPanic("1y2m3d3h")},
{WithinYearly: data.ParseDurationOrPanic("1y2m3d3h")},
{Within: data.ParseDurationOrPanic("1h"),
WithinHourly: data.ParseDurationOrPanic("1d"),
WithinDaily: data.ParseDurationOrPanic("7d"),
WithinWeekly: data.ParseDurationOrPanic("1m"),
WithinMonthly: data.ParseDurationOrPanic("1y"),
WithinYearly: data.ParseDurationOrPanic("9999y")},
{Last: -1}, // keep all
{Last: -1, Hourly: -1}, // keep all (Last overrides Hourly)
{Hourly: -1}, // keep all hourlies
@@ -249,7 +249,7 @@ func TestApplyPolicy(t *testing.T) {
for i, p := range tests {
t.Run("", func(t *testing.T) {
keep, remove, reasons := restic.ApplyPolicy(testExpireSnapshots, p)
keep, remove, reasons := data.ApplyPolicy(testExpireSnapshots, p)
if len(keep)+len(remove) != len(testExpireSnapshots) {
t.Errorf("len(keep)+len(remove) = %d != len(testExpireSnapshots) = %d",
@@ -273,7 +273,7 @@ func TestApplyPolicy(t *testing.T) {
want := loadGoldenFile(t, goldenFilename)
cmpOpts := cmpopts.IgnoreUnexported(restic.Snapshot{})
cmpOpts := cmpopts.IgnoreUnexported(data.Snapshot{})
if !cmp.Equal(want.Keep, keep, cmpOpts) {
t.Error(cmp.Diff(want.Keep, keep, cmpOpts))

View File

@@ -1,19 +1,19 @@
package restic_test
package data_test
import (
"context"
"testing"
"time"
"github.com/restic/restic/internal/data"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func TestNewSnapshot(t *testing.T) {
paths := []string{"/home/foobar"}
_, err := restic.NewSnapshot(paths, nil, "foo", time.Now())
_, err := data.NewSnapshot(paths, nil, "foo", time.Now())
rtest.OK(t, err)
}
@@ -21,7 +21,7 @@ func TestTagList(t *testing.T) {
paths := []string{"/home/foobar"}
tags := []string{""}
sn, _ := restic.NewSnapshot(paths, nil, "foo", time.Now())
sn, _ := data.NewSnapshot(paths, nil, "foo", time.Now())
r := sn.HasTags(tags)
rtest.Assert(t, r, "Failed to match untagged snapshot")
@@ -35,15 +35,15 @@ func testLoadJSONUnpacked(t *testing.T, version uint) {
repo, _, _ := repository.TestRepositoryWithVersion(t, version)
// archive a snapshot
sn := restic.Snapshot{}
sn := data.Snapshot{}
sn.Hostname = "foobar"
sn.Username = "test!"
id, err := restic.SaveSnapshot(context.TODO(), repo, &sn)
id, err := data.SaveSnapshot(context.TODO(), repo, &sn)
rtest.OK(t, err)
// restore
sn2, err := restic.LoadSnapshot(context.TODO(), repo, id)
sn2, err := data.LoadSnapshot(context.TODO(), repo, id)
rtest.OK(t, err)
rtest.Equals(t, sn.Hostname, sn2.Hostname)

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package restic
package data
import (
"testing"

Some files were not shown because too many files have changed in this diff Show More