github.com/advanderveer/restic@v0.8.1-0.20171209104529-42a8c19aaea6/cmd/restic/cmd_ls.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"path/filepath"
     6  
     7  	"github.com/spf13/cobra"
     8  
     9  	"github.com/restic/restic/internal/errors"
    10  	"github.com/restic/restic/internal/repository"
    11  	"github.com/restic/restic/internal/restic"
    12  )
    13  
    14  var cmdLs = &cobra.Command{
    15  	Use:   "ls [flags] [snapshot-ID ...]",
    16  	Short: "List files in a snapshot",
    17  	Long: `
    18  The "ls" command allows listing files and directories in a snapshot.
    19  
    20  The special snapshot-ID "latest" can be used to list files and directories of the latest snapshot in the repository.
    21  `,
    22  	DisableAutoGenTag: true,
    23  	RunE: func(cmd *cobra.Command, args []string) error {
    24  		return runLs(lsOptions, globalOptions, args)
    25  	},
    26  }
    27  
    28  // LsOptions collects all options for the ls command.
    29  type LsOptions struct {
    30  	ListLong bool
    31  	Host     string
    32  	Tags     restic.TagLists
    33  	Paths    []string
    34  }
    35  
    36  var lsOptions LsOptions
    37  
    38  func init() {
    39  	cmdRoot.AddCommand(cmdLs)
    40  
    41  	flags := cmdLs.Flags()
    42  	flags.BoolVarP(&lsOptions.ListLong, "long", "l", false, "use a long listing format showing size and mode")
    43  
    44  	flags.StringVarP(&lsOptions.Host, "host", "H", "", "only consider snapshots for this `host`, when no snapshot ID is given")
    45  	flags.Var(&lsOptions.Tags, "tag", "only consider snapshots which include this `taglist`, when no snapshot ID is given")
    46  	flags.StringArrayVar(&lsOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`, when no snapshot ID is given")
    47  }
    48  
    49  func printTree(ctx context.Context, repo *repository.Repository, id *restic.ID, prefix string) error {
    50  	tree, err := repo.LoadTree(ctx, *id)
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	for _, entry := range tree.Nodes {
    56  		Printf("%s\n", formatNode(prefix, entry, lsOptions.ListLong))
    57  
    58  		if entry.Type == "dir" && entry.Subtree != nil {
    59  			if err = printTree(ctx, repo, entry.Subtree, filepath.Join(prefix, entry.Name)); err != nil {
    60  				return err
    61  			}
    62  		}
    63  	}
    64  
    65  	return nil
    66  }
    67  
    68  func runLs(opts LsOptions, gopts GlobalOptions, args []string) error {
    69  	if len(args) == 0 && opts.Host == "" && len(opts.Tags) == 0 && len(opts.Paths) == 0 {
    70  		return errors.Fatal("Invalid arguments, either give one or more snapshot IDs or set filters.")
    71  	}
    72  
    73  	repo, err := OpenRepository(gopts)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	if err = repo.LoadIndex(gopts.ctx); err != nil {
    79  		return err
    80  	}
    81  
    82  	ctx, cancel := context.WithCancel(gopts.ctx)
    83  	defer cancel()
    84  	for sn := range FindFilteredSnapshots(ctx, repo, opts.Host, opts.Tags, opts.Paths, args) {
    85  		Verbosef("snapshot %s of %v at %s):\n", sn.ID().Str(), sn.Paths, sn.Time)
    86  
    87  		if err = printTree(gopts.ctx, repo, sn.Tree, string(filepath.Separator)); err != nil {
    88  			return err
    89  		}
    90  	}
    91  	return nil
    92  }