Use TagLists for all commands

This commit is contained in:
Alexander Neumann 2017-07-09 09:47:41 +02:00
parent f5b1c7e5f1
commit 7362569cf5
13 changed files with 61 additions and 18 deletions

View file

@ -392,7 +392,7 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, args []string) error {
// Find last snapshot to set it as parent, if not already set
if !opts.Force && parentSnapshotID == nil {
id, err := restic.FindLatestSnapshot(context.TODO(), repo, target, opts.Tags, opts.Hostname)
id, err := restic.FindLatestSnapshot(context.TODO(), repo, target, []restic.TagList{opts.Tags}, opts.Hostname)
if err == nil {
parentSnapshotID = &id
} else if err != restic.ErrNoSnapshotFound {

View file

@ -50,7 +50,7 @@ func init() {
f.BoolVarP(&findOptions.ListLong, "long", "l", false, "use a long listing format showing size and mode")
f.StringVarP(&findOptions.Host, "host", "H", "", "only consider snapshots for this `host`, when no snapshot ID is given")
f.StringArrayVar(&findOptions.Tags, "tag", nil, "only consider snapshots which include this `tag`, when no snapshot-ID is given")
f.StringArrayVar(&findOptions.Tags, "tag", nil, "only consider snapshots which include the list of `tag,tag,...`, when no snapshot-ID is given")
f.StringArrayVar(&findOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`, when no snapshot-ID is given")
}
@ -290,13 +290,15 @@ func runFind(opts FindOptions, gopts GlobalOptions, args []string) error {
ctx, cancel := context.WithCancel(gopts.ctx)
defer cancel()
tagLists := restic.SplitTagLists(opts.Tags)
f := &Finder{
repo: repo,
pat: pat,
out: statefulOutput{ListLong: opts.ListLong, JSON: globalOptions.JSON},
notfound: restic.NewIDSet(),
}
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, opts.Snapshots) {
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, tagLists, opts.Paths, opts.Snapshots) {
if err = f.findInSnapshot(sn); err != nil {
return err
}

View file

@ -92,7 +92,7 @@ func runForget(opts ForgetOptions, gopts GlobalOptions, args []string) error {
ctx, cancel := context.WithCancel(gopts.ctx)
defer cancel()
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args) {
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, restic.SplitTagLists(opts.Tags), opts.Paths, args) {
if len(args) > 0 {
// When explicit snapshots args are given, remove them immediately.
if !opts.DryRun {

View file

@ -80,7 +80,7 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
ctx, cancel := context.WithCancel(gopts.ctx)
defer cancel()
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args) {
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, restic.SplitTagLists(opts.Tags), opts.Paths, args) {
Verbosef("snapshot %s of %v at %s):\n", sn.ID().Str(), sn.Paths, sn.Time)
if err = printTree(repo, sn.Tree, string(filepath.Separator)); err != nil {

View file

@ -6,6 +6,7 @@ package main
import (
"context"
"os"
"restic"
"github.com/spf13/cobra"
@ -103,7 +104,7 @@ func mount(opts MountOptions, gopts GlobalOptions, mountpoint string) error {
cfg := fuse.Config{
OwnerIsRoot: opts.OwnerRoot,
Host: opts.Host,
Tags: opts.Tags,
Tags: restic.SplitTagLists(opts.Tags),
Paths: opts.Paths,
}
root, err := fuse.NewRoot(context.TODO(), repo, cfg)

View file

@ -89,7 +89,7 @@ func runRestore(opts RestoreOptions, gopts GlobalOptions, args []string) error {
var id restic.ID
if snapshotIDString == "latest" {
id, err = restic.FindLatestSnapshot(ctx, repo, opts.Paths, opts.Tags, opts.Host)
id, err = restic.FindLatestSnapshot(ctx, repo, opts.Paths, restic.SplitTagLists(opts.Tags), opts.Host)
if err != nil {
Exitf(1, "latest snapshot for criteria not found: %v Paths:%v Host:%v", err, opts.Paths, opts.Host)
}

View file

@ -59,7 +59,7 @@ func runSnapshots(opts SnapshotOptions, gopts GlobalOptions, args []string) erro
defer cancel()
var list restic.Snapshots
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args) {
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, restic.SplitTagLists(opts.Tags), opts.Paths, args) {
list = append(list, sn)
}
sort.Sort(sort.Reverse(list))

View file

@ -123,7 +123,7 @@ func runTag(opts TagOptions, gopts GlobalOptions, args []string) error {
changeCnt := 0
ctx, cancel := context.WithCancel(gopts.ctx)
defer cancel()
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args) {
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, restic.SplitTagLists(opts.Tags), opts.Paths, args) {
changed, err := changeTags(repo, sn, opts.SetTags, opts.AddTags, opts.RemoveTags)
if err != nil {
Warnf("unable to modify the tags for snapshot ID %q, ignoring: %v\n", sn.ID(), err)

View file

@ -8,7 +8,7 @@ import (
)
// FindFilteredSnapshots yields Snapshots, either given explicitly by `snapshotIDs` or filtered from the list of all snapshots.
func FindFilteredSnapshots(ctx context.Context, repo *repository.Repository, host string, tags []string, paths []string, snapshotIDs []string) <-chan *restic.Snapshot {
func FindFilteredSnapshots(ctx context.Context, repo *repository.Repository, host string, tags []restic.TagList, paths []string, snapshotIDs []string) <-chan *restic.Snapshot {
out := make(chan *restic.Snapshot)
go func() {
defer close(out)

View file

@ -16,7 +16,7 @@ import (
type Config struct {
OwnerIsRoot bool
Host string
Tags []string
Tags []restic.TagList
Paths []string
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"os/user"
"path/filepath"
"restic/debug"
"time"
)
@ -150,6 +151,25 @@ func (sn *Snapshot) HasTags(l []string) bool {
return true
}
// HasTagList returns true if the snapshot satisfies at least one TagList,
// so there is a TagList in l for which all tags are included in sn.
func (sn *Snapshot) HasTagList(l []TagList) bool {
debug.Log("testing snapshot with tags %v against list: %v", sn.Tags, l)
if len(l) == 0 {
return true
}
for _, tags := range l {
if sn.HasTags(tags) {
debug.Log(" snapshot satisfies %v", tags, l)
return true
}
}
return false
}
func (sn *Snapshot) hasPath(path string) bool {
for _, snPath := range sn.Paths {
if path == snPath {

View file

@ -12,7 +12,7 @@ import (
var ErrNoSnapshotFound = errors.New("no snapshot found")
// FindLatestSnapshot finds latest snapshot with optional target/directory, tags and hostname filters.
func FindLatestSnapshot(ctx context.Context, repo Repository, targets []string, tags []string, hostname string) (ID, error) {
func FindLatestSnapshot(ctx context.Context, repo Repository, targets []string, tagLists []TagList, hostname string) (ID, error) {
var (
latest time.Time
latestID ID
@ -24,11 +24,21 @@ func FindLatestSnapshot(ctx context.Context, repo Repository, targets []string,
if err != nil {
return ID{}, errors.Errorf("Error listing snapshot: %v", err)
}
if snapshot.Time.After(latest) && (hostname == "" || hostname == snapshot.Hostname) && snapshot.HasTags(tags) && snapshot.HasPaths(targets) {
latest = snapshot.Time
latestID = snapshotID
found = true
if snapshot.Time.Before(latest) || (hostname != "" && hostname != snapshot.Hostname) {
continue
}
if !snapshot.HasTagList(tagLists) {
continue
}
if !snapshot.HasPaths(targets) {
continue
}
latest = snapshot.Time
latestID = snapshotID
found = true
}
if !found {
@ -53,7 +63,7 @@ func FindSnapshot(repo Repository, s string) (ID, error) {
// FindFilteredSnapshots yields Snapshots filtered from the list of all
// snapshots.
func FindFilteredSnapshots(ctx context.Context, repo Repository, host string, tags []string, paths []string) Snapshots {
func FindFilteredSnapshots(ctx context.Context, repo Repository, host string, tags []TagList, paths []string) Snapshots {
results := make(Snapshots, 0, 20)
for id := range repo.List(ctx, SnapshotFile) {
@ -62,7 +72,7 @@ func FindFilteredSnapshots(ctx context.Context, repo Repository, host string, ta
fmt.Fprintf(os.Stderr, "could not load snapshot %v: %v\n", id.Str(), err)
continue
}
if (host != "" && host != sn.Hostname) || !sn.HasTags(tags) || !sn.HasPaths(paths) {
if (host != "" && host != sn.Hostname) || !sn.HasTagList(tags) || !sn.HasPaths(paths) {
continue
}

View file

@ -20,6 +20,16 @@ func SplitTagList(s string) (l TagList) {
return l
}
// SplitTagLists splits a slice of strings into a slice of TagLists using
// SplitTagList.
func SplitTagLists(s []string) (l []TagList) {
l = make([]TagList, 0, len(s))
for _, t := range s {
l = append(l, SplitTagList(t))
}
return l
}
// ExpirePolicy configures which snapshots should be automatically removed.
type ExpirePolicy struct {
Last int // keep the last n snapshots