Apply feedback and use SkipNode

This commit is contained in:
Matthew Holt 2018-08-11 15:25:22 -06:00
parent 156d85a29b
commit 00e2fd8b5f

View file

@ -2,12 +2,13 @@ package main
import ( import (
"context" "context"
"path/filepath" "path"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic" "github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/walker" "github.com/restic/restic/internal/walker"
) )
@ -25,9 +26,11 @@ snapshot originating from a certain host only.
File listings can optionally be filtered by directories. Any File listings can optionally be filtered by directories. Any
positional arguments after the snapshot ID are interpreted as positional arguments after the snapshot ID are interpreted as
directory paths, and only files inside those directories will absolute directory paths, and only files inside those directories
be listed. If the --recursive flag is used, then the filter will be listed. If the --recursive flag is used, then the filter
will allow traversing into matching directories' subfolders. will allow traversing into matching directories' subfolders.
Any directory paths specified must be absolute (starting with
a path separator); paths use the forward slash '/' as separator.
`, `,
DisableAutoGenTag: true, DisableAutoGenTag: true,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@ -75,16 +78,17 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
var dirs []string var dirs []string
if len(args) > 1 { if len(args) > 1 {
dirs = args[1:] dirs = args[1:]
for _, dir := range dirs {
if !strings.HasPrefix(dir, "/") {
return errors.Fatal("All path filters must be absolute, starting with a forward slash '/'")
}
}
} }
ctx, cancel := context.WithCancel(gopts.ctx) ctx, cancel := context.WithCancel(gopts.ctx)
defer cancel() defer cancel()
for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args[:1]) { for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args[:1]) {
dirsToPrint := opts.Paths Verbosef("snapshot %s of %v filtered by %v at %s):\n", sn.ID().Str(), sn.Paths, dirs, sn.Time)
if len(dirs) > 0 {
dirsToPrint = dirs
}
Verbosef("snapshot %s of %v at %s):\n", sn.ID().Str(), dirsToPrint, sn.Time)
err := walker.Walk(ctx, repo, *sn.Tree, nil, func(nodepath string, node *restic.Node, err error) (bool, error) { err := walker.Walk(ctx, repo, *sn.Tree, nil, func(nodepath string, node *restic.Node, err error) (bool, error) {
if err != nil { if err != nil {
@ -96,31 +100,40 @@ func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
// apply any directory filters // apply any directory filters
if len(dirs) > 0 { if len(dirs) > 0 {
var nodeDir string // this first iteration ensures we do not traverse branches that
if !opts.Recursive { // are not in matching trees or will not lead us to matching trees
// only needed for exact directory match; i.e. no subfolders var walk bool
nodeDir = filepath.Dir(nodepath) for _, dir := range dirs {
if fs.HasPathPrefix(nodepath, dir) || fs.HasPathPrefix(dir, nodepath) {
// we are either in or approaching the right tree
walk = true
break
}
} }
if !walk {
return false, walker.SkipNode
}
// this second iteration ensures that we get an exact match
// according to the filter and whether we should match subfolders
var match bool var match bool
for _, dir := range dirs { for _, dir := range dirs {
if opts.Recursive { if opts.Recursive && fs.HasPathPrefix(dir, nodepath) {
if strings.HasPrefix(nodepath, dir) { match = true
match = true break
break }
} if !opts.Recursive && path.Dir(nodepath) == dir {
} else { match = true
if nodeDir == dir { break
match = true
break
}
} }
} }
if !match { if !match {
return true, nil return false, nil
} }
} }
Printf("%s\n", formatNode(nodepath, node, lsOptions.ListLong)) Printf("%s\n", formatNode(nodepath, node, lsOptions.ListLong))
return false, nil return false, nil
}) })
if err != nil { if err != nil {