mirror of
https://github.com/restic/restic.git
synced 2025-12-11 18:47:50 +00:00
data: split node and snapshot code from restic package
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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})
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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[:]...)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"`),
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
}}))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package restic
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package restic
|
||||
package data
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -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})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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"`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package restic
|
||||
package data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package restic
|
||||
package data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package restic
|
||||
package data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -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)
|
||||
@@ -1,4 +1,4 @@
|
||||
package restic
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
@@ -1,4 +1,4 @@
|
||||
package restic
|
||||
package data
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -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
Reference in New Issue
Block a user