2014-12-07 13:44:01 +00:00
package main
import (
2017-03-08 19:29:31 +00:00
"context"
2017-03-09 15:06:28 +00:00
"encoding/json"
2017-03-07 09:58:09 +00:00
"strings"
2014-12-07 15:30:52 +00:00
"time"
2014-12-07 13:44:01 +00:00
2016-09-17 10:36:05 +00:00
"github.com/spf13/cobra"
2017-07-23 12:21:03 +00:00
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
2018-06-09 16:56:40 +00:00
"github.com/restic/restic/internal/filter"
2017-07-24 15:42:25 +00:00
"github.com/restic/restic/internal/restic"
2018-06-09 16:56:40 +00:00
"github.com/restic/restic/internal/walker"
2014-12-07 13:44:01 +00:00
)
2016-09-17 10:36:05 +00:00
var cmdFind = & cobra . Command {
2018-07-14 20:00:36 +00:00
Use : "find [flags] PATTERN..." ,
2018-05-13 15:28:32 +00:00
Short : "Find a file, a directory or restic IDs" ,
2016-09-17 10:36:05 +00:00
Long : `
The "find" command searches for files or directories in snapshots stored in the
2018-05-13 15:28:32 +00:00
repo .
It can also be used to search for restic blobs or trees for troubleshooting . ` ,
2018-07-14 20:00:36 +00:00
Example : ` restic find config . json
restic find -- json "*.yml" "*.json"
restic find -- json -- blob 420 f620f b46ebe8a ddd38656
restic find -- show - pack - id -- blob 420 f620f
restic find -- tree 577 c2bc9 f81f2e22 a62827a9
2019-11-05 06:03:38 +00:00
restic find -- pack 025 c1d06
EXIT STATUS
== == == == == =
Exit status is 0 if the command was successful , and non - zero if there was any error .
` ,
2017-08-06 19:02:16 +00:00
DisableAutoGenTag : true ,
2016-09-17 10:36:05 +00:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
return runFind ( findOptions , globalOptions , args )
} ,
2014-12-07 13:44:01 +00:00
}
2018-05-13 15:28:32 +00:00
const shortStr = 8 // Length of short IDs: 4 bytes as hex strings
2017-03-08 19:09:24 +00:00
// FindOptions bundles all options for the find command.
2016-09-17 10:36:05 +00:00
type FindOptions struct {
2018-05-13 15:28:32 +00:00
Oldest string
Newest string
Snapshots [ ] string
BlobID , TreeID bool
PackID , ShowPackID bool
CaseInsensitive bool
ListLong bool
2020-02-26 21:17:59 +00:00
Hosts [ ] string
2018-05-13 15:28:32 +00:00
Paths [ ] string
Tags restic . TagLists
2016-09-17 10:36:05 +00:00
}
var findOptions FindOptions
func init ( ) {
cmdRoot . AddCommand ( cmdFind )
f := cmdFind . Flags ( )
2017-04-06 17:14:38 +00:00
f . StringVarP ( & findOptions . Oldest , "oldest" , "O" , "" , "oldest modification date/time" )
f . StringVarP ( & findOptions . Newest , "newest" , "N" , "" , "newest modification date/time" )
2017-07-07 01:19:06 +00:00
f . StringArrayVarP ( & findOptions . Snapshots , "snapshot" , "s" , nil , "snapshot `id` to search in (can be given multiple times)" )
2018-05-13 15:28:32 +00:00
f . BoolVar ( & findOptions . BlobID , "blob" , false , "pattern is a blob-ID" )
f . BoolVar ( & findOptions . TreeID , "tree" , false , "pattern is a tree-ID" )
f . BoolVar ( & findOptions . PackID , "pack" , false , "pattern is a pack-ID" )
2019-03-30 00:23:24 +00:00
f . BoolVar ( & findOptions . ShowPackID , "show-pack-id" , false , "display the pack-ID the blobs belong to (with --blob or --tree)" )
2017-03-07 09:58:09 +00:00
f . BoolVarP ( & findOptions . CaseInsensitive , "ignore-case" , "i" , false , "ignore case for pattern" )
2017-03-08 19:29:31 +00:00
f . BoolVarP ( & findOptions . ListLong , "long" , "l" , false , "use a long listing format showing size and mode" )
2020-02-26 21:17:59 +00:00
f . StringArrayVarP ( & findOptions . Hosts , "host" , "H" , nil , "only consider snapshots for this `host`, when no snapshot ID is given (can be specified multiple times)" )
2017-07-09 10:45:49 +00:00
f . Var ( & findOptions . Tags , "tag" , "only consider snapshots which include this `taglist`, when no snapshot-ID is given" )
2017-07-07 01:19:06 +00:00
f . StringArrayVar ( & findOptions . Paths , "path" , nil , "only consider snapshots which include this (absolute) `path`, when no snapshot-ID is given" )
2016-09-17 10:36:05 +00:00
}
2014-12-07 16:11:01 +00:00
2016-09-17 10:36:05 +00:00
type findPattern struct {
2014-12-07 16:11:01 +00:00
oldest , newest time . Time
2018-07-14 20:00:36 +00:00
pattern [ ] string
2017-03-07 09:58:09 +00:00
ignoreCase bool
2016-09-17 10:36:05 +00:00
}
2014-12-07 16:11:01 +00:00
var timeFormats = [ ] string {
"2006-01-02" ,
"2006-01-02 15:04" ,
"2006-01-02 15:04:05" ,
"2006-01-02 15:04:05 -0700" ,
"2006-01-02 15:04:05 MST" ,
"02.01.2006" ,
"02.01.2006 15:04" ,
"02.01.2006 15:04:05" ,
"02.01.2006 15:04:05 -0700" ,
"02.01.2006 15:04:05 MST" ,
"Mon Jan 2 15:04:05 -0700 MST 2006" ,
2014-12-07 15:30:52 +00:00
}
2014-12-07 16:11:01 +00:00
func parseTime ( str string ) ( time . Time , error ) {
for _ , fmt := range timeFormats {
if t , err := time . ParseInLocation ( fmt , str , time . Local ) ; err == nil {
return t , nil
}
}
2016-09-01 20:17:37 +00:00
return time . Time { } , errors . Fatalf ( "unable to parse time: %q" , str )
2014-12-07 16:11:01 +00:00
}
2017-03-09 15:06:28 +00:00
type statefulOutput struct {
ListLong bool
JSON bool
inuse bool
newsn * restic . Snapshot
oldsn * restic . Snapshot
hits int
}
2018-05-13 15:28:32 +00:00
func ( s * statefulOutput ) PrintPatternJSON ( path string , node * restic . Node ) {
2017-03-09 15:06:28 +00:00
type findNode restic . Node
b , err := json . Marshal ( struct {
// Add these attributes
Path string ` json:"path,omitempty" `
Permissions string ` json:"permissions,omitempty" `
* findNode
// Make the following attributes disappear
Name byte ` json:"name,omitempty" `
Inode byte ` json:"inode,omitempty" `
ExtendedAttributes byte ` json:"extended_attributes,omitempty" `
Device byte ` json:"device,omitempty" `
Content byte ` json:"content,omitempty" `
Subtree byte ` json:"subtree,omitempty" `
} {
2018-06-09 16:56:40 +00:00
Path : path ,
2017-03-09 15:06:28 +00:00
Permissions : node . Mode . String ( ) ,
findNode : ( * findNode ) ( node ) ,
} )
if err != nil {
Warnf ( "Marshall failed: %v\n" , err )
return
}
if ! s . inuse {
Printf ( "[" )
s . inuse = true
}
if s . newsn != s . oldsn {
if s . oldsn != nil {
Printf ( "],\"hits\":%d,\"snapshot\":%q}," , s . hits , s . oldsn . ID ( ) )
}
Printf ( ` { "matches":[ ` )
s . oldsn = s . newsn
s . hits = 0
}
if s . hits > 0 {
Printf ( "," )
}
2019-05-26 19:23:53 +00:00
Print ( string ( b ) )
2017-03-09 15:06:28 +00:00
s . hits ++
}
2018-05-13 15:28:32 +00:00
func ( s * statefulOutput ) PrintPatternNormal ( path string , node * restic . Node ) {
2017-03-09 15:06:28 +00:00
if s . newsn != s . oldsn {
if s . oldsn != nil {
Verbosef ( "\n" )
}
s . oldsn = s . newsn
2019-05-10 15:22:42 +00:00
Verbosef ( "Found matching entries in snapshot %s from %s\n" , s . oldsn . ID ( ) . Str ( ) , s . oldsn . Time . Local ( ) . Format ( TimeFormat ) )
2017-03-09 15:06:28 +00:00
}
2019-05-26 19:23:53 +00:00
Println ( formatNode ( path , node , s . ListLong ) )
2017-03-09 15:06:28 +00:00
}
2018-05-13 15:28:32 +00:00
func ( s * statefulOutput ) PrintPattern ( path string , node * restic . Node ) {
if s . JSON {
s . PrintPatternJSON ( path , node )
} else {
s . PrintPatternNormal ( path , node )
}
}
2018-07-14 16:29:07 +00:00
func ( s * statefulOutput ) PrintObjectJSON ( kind , id , nodepath , treeID string , sn * restic . Snapshot ) {
2018-05-13 15:28:32 +00:00
b , err := json . Marshal ( struct {
// Add these attributes
ObjectType string ` json:"object_type" `
ID string ` json:"id" `
2018-07-14 16:29:07 +00:00
Path string ` json:"path" `
ParentTree string ` json:"parent_tree,omitempty" `
2018-05-13 15:28:32 +00:00
SnapshotID string ` json:"snapshot" `
Time time . Time ` json:"time,omitempty" `
} {
ObjectType : kind ,
ID : id ,
Path : nodepath ,
SnapshotID : sn . ID ( ) . String ( ) ,
2018-07-14 16:29:07 +00:00
ParentTree : treeID ,
2018-05-13 15:28:32 +00:00
Time : sn . Time ,
} )
if err != nil {
Warnf ( "Marshall failed: %v\n" , err )
return
}
if ! s . inuse {
Printf ( "[" )
s . inuse = true
}
if s . hits > 0 {
Printf ( "," )
}
2019-05-26 19:23:53 +00:00
Print ( string ( b ) )
2018-05-13 15:28:32 +00:00
s . hits ++
}
2018-07-14 16:29:07 +00:00
func ( s * statefulOutput ) PrintObjectNormal ( kind , id , nodepath , treeID string , sn * restic . Snapshot ) {
Printf ( "Found %s %s\n" , kind , id )
2018-05-13 15:28:32 +00:00
if kind == "blob" {
2018-07-14 16:29:07 +00:00
Printf ( " ... in file %s\n" , nodepath )
Printf ( " (tree %s)\n" , treeID )
} else {
Printf ( " ... path %s\n" , nodepath )
2018-05-13 15:28:32 +00:00
}
2018-11-02 19:36:15 +00:00
Printf ( " ... in snapshot %s (%s)\n" , sn . ID ( ) . Str ( ) , sn . Time . Local ( ) . Format ( TimeFormat ) )
2018-05-13 15:28:32 +00:00
}
2018-07-14 16:29:07 +00:00
func ( s * statefulOutput ) PrintObject ( kind , id , nodepath , treeID string , sn * restic . Snapshot ) {
2017-03-09 15:06:28 +00:00
if s . JSON {
2018-07-14 16:29:07 +00:00
s . PrintObjectJSON ( kind , id , nodepath , treeID , sn )
2017-03-09 15:06:28 +00:00
} else {
2018-07-14 16:29:07 +00:00
s . PrintObjectNormal ( kind , id , nodepath , treeID , sn )
2017-03-09 15:06:28 +00:00
}
}
func ( s * statefulOutput ) Finish ( ) {
if s . JSON {
// do some finishing up
if s . oldsn != nil {
Printf ( "],\"hits\":%d,\"snapshot\":%q}" , s . hits , s . oldsn . ID ( ) )
}
if s . inuse {
Printf ( "]\n" )
} else {
Printf ( "[]\n" )
}
return
}
}
2017-06-04 09:38:46 +00:00
// Finder bundles information needed to find a file or directory.
type Finder struct {
2018-06-09 16:56:40 +00:00
repo restic . Repository
pat findPattern
out statefulOutput
ignoreTrees restic . IDSet
2018-05-13 15:28:32 +00:00
blobIDs map [ string ] struct { }
treeIDs map [ string ] struct { }
itemsFound int
2017-06-04 09:38:46 +00:00
}
2018-06-09 16:56:40 +00:00
func ( f * Finder ) findInSnapshot ( ctx context . Context , sn * restic . Snapshot ) error {
debug . Log ( "searching in snapshot %s\n for entries within [%s %s]" , sn . ID ( ) , f . pat . oldest , f . pat . newest )
2017-03-08 19:29:31 +00:00
2018-06-09 16:56:40 +00:00
if sn . Tree == nil {
return errors . Errorf ( "snapshot %v has no tree" , sn . ID ( ) . Str ( ) )
2014-12-07 13:44:01 +00:00
}
2018-06-09 16:56:40 +00:00
f . out . newsn = sn
2019-03-30 00:32:18 +00:00
return walker . Walk ( ctx , f . repo , * sn . Tree , f . ignoreTrees , func ( parentTreeID restic . ID , nodepath string , node * restic . Node , err error ) ( bool , error ) {
2018-06-09 16:56:40 +00:00
if err != nil {
2019-03-30 00:32:18 +00:00
debug . Log ( "Error loading tree %v: %v" , parentTreeID , err )
Printf ( "Unable to load tree %s\n ... which belongs to snapshot %s.\n" , parentTreeID , sn . ID ( ) )
2020-07-28 20:32:57 +00:00
return false , walker . ErrSkipNode
2018-06-09 16:56:40 +00:00
}
if node == nil {
return false , nil
}
2014-12-07 16:11:01 +00:00
2018-06-24 17:20:59 +00:00
normalizedNodepath := nodepath
2017-06-04 09:38:46 +00:00
if f . pat . ignoreCase {
2018-06-24 17:20:59 +00:00
normalizedNodepath = strings . ToLower ( nodepath )
2017-03-07 09:58:09 +00:00
}
2018-07-14 20:00:36 +00:00
var foundMatch bool
for _ , pat := range f . pat . pattern {
found , err := filter . Match ( pat , normalizedNodepath )
if err != nil {
return false , err
}
if found {
foundMatch = true
break
}
2014-12-07 13:44:01 +00:00
}
2018-06-09 16:56:40 +00:00
var (
ignoreIfNoMatch = true
errIfNoMatch error
)
2016-09-01 19:20:03 +00:00
if node . Type == "dir" {
2018-07-14 20:00:36 +00:00
var childMayMatch bool
for _ , pat := range f . pat . pattern {
mayMatch , err := filter . ChildMatch ( pat , normalizedNodepath )
if err != nil {
return false , err
}
if mayMatch {
childMayMatch = true
break
}
2018-06-09 16:31:13 +00:00
}
2018-06-09 16:56:40 +00:00
if ! childMayMatch {
ignoreIfNoMatch = true
2020-07-28 20:32:57 +00:00
errIfNoMatch = walker . ErrSkipNode
2018-06-09 16:56:40 +00:00
} else {
ignoreIfNoMatch = false
2014-12-07 13:44:01 +00:00
}
}
2018-06-09 16:56:40 +00:00
if ! foundMatch {
return ignoreIfNoMatch , errIfNoMatch
}
2017-06-04 09:42:40 +00:00
2018-06-09 16:56:40 +00:00
if ! f . pat . oldest . IsZero ( ) && node . ModTime . Before ( f . pat . oldest ) {
debug . Log ( " ModTime is older than %s\n" , f . pat . oldest )
return ignoreIfNoMatch , errIfNoMatch
}
2014-12-07 13:44:01 +00:00
2018-06-09 16:56:40 +00:00
if ! f . pat . newest . IsZero ( ) && node . ModTime . After ( f . pat . newest ) {
debug . Log ( " ModTime is newer than %s\n" , f . pat . newest )
return ignoreIfNoMatch , errIfNoMatch
}
2014-12-07 13:44:01 +00:00
2018-06-09 16:56:40 +00:00
debug . Log ( " found match\n" )
2018-05-13 15:28:32 +00:00
f . out . PrintPattern ( nodepath , node )
2018-06-09 16:56:40 +00:00
return false , nil
} )
2014-12-07 13:44:01 +00:00
}
2018-05-13 15:28:32 +00:00
func ( f * Finder ) findIDs ( ctx context . Context , sn * restic . Snapshot ) error {
debug . Log ( "searching IDs in snapshot %s" , sn . ID ( ) )
if sn . Tree == nil {
return errors . Errorf ( "snapshot %v has no tree" , sn . ID ( ) . Str ( ) )
}
f . out . newsn = sn
2018-08-19 10:28:06 +00:00
return walker . Walk ( ctx , f . repo , * sn . Tree , f . ignoreTrees , func ( parentTreeID restic . ID , nodepath string , node * restic . Node , err error ) ( bool , error ) {
2018-05-13 15:28:32 +00:00
if err != nil {
2019-03-30 00:32:18 +00:00
debug . Log ( "Error loading tree %v: %v" , parentTreeID , err )
Printf ( "Unable to load tree %s\n ... which belongs to snapshot %s.\n" , parentTreeID , sn . ID ( ) )
2020-07-28 20:32:57 +00:00
return false , walker . ErrSkipNode
2018-05-13 15:28:32 +00:00
}
if node == nil {
return false , nil
}
if node . Type == "dir" && f . treeIDs != nil {
treeID := node . Subtree
found := false
if _ , ok := f . treeIDs [ treeID . Str ( ) ] ; ok {
found = true
} else if _ , ok := f . treeIDs [ treeID . String ( ) ] ; ok {
found = true
}
if found {
2018-07-14 16:29:07 +00:00
f . out . PrintObject ( "tree" , treeID . String ( ) , nodepath , "" , sn )
2018-05-13 15:28:32 +00:00
f . itemsFound ++
// Terminate if we have found all trees (and we are not
// looking for blobs)
if f . itemsFound >= len ( f . treeIDs ) && f . blobIDs == nil {
// Return an error to terminate the Walk
return true , errors . New ( "OK" )
}
}
}
if node . Type == "file" && f . blobIDs != nil {
for _ , id := range node . Content {
idStr := id . String ( )
if _ , ok := f . blobIDs [ idStr ] ; ! ok {
// Look for short ID form
if _ , ok := f . blobIDs [ idStr [ : shortStr ] ] ; ! ok {
continue
}
// Replace the short ID with the long one
f . blobIDs [ idStr ] = struct { } { }
delete ( f . blobIDs , idStr [ : shortStr ] )
}
2018-08-19 10:28:06 +00:00
f . out . PrintObject ( "blob" , idStr , nodepath , parentTreeID . String ( ) , sn )
2018-05-13 15:28:32 +00:00
}
}
return false , nil
} )
}
// packsToBlobs converts the list of pack IDs to a list of blob IDs that
// belong to those packs.
func ( f * Finder ) packsToBlobs ( ctx context . Context , packs [ ] string ) error {
packIDs := make ( map [ string ] struct { } )
for _ , p := range packs {
packIDs [ p ] = struct { } { }
}
if f . blobIDs == nil {
f . blobIDs = make ( map [ string ] struct { } )
}
allPacksFound := false
packsFound := 0
debug . Log ( "Looking for packs..." )
2020-08-16 09:16:38 +00:00
err := f . repo . List ( ctx , restic . PackFile , func ( id restic . ID , size int64 ) error {
2018-05-13 15:28:32 +00:00
if allPacksFound {
return nil
}
idStr := id . String ( )
if _ , ok := packIDs [ idStr ] ; ! ok {
// Look for short ID form
if _ , ok := packIDs [ idStr [ : shortStr ] ] ; ! ok {
return nil
}
}
debug . Log ( "Found pack %s" , idStr )
blobs , _ , err := f . repo . ListPack ( ctx , id , size )
if err != nil {
return err
}
for _ , b := range blobs {
f . blobIDs [ b . ID . String ( ) ] = struct { } { }
}
// Stop searching when all packs have been found
packsFound ++
if packsFound >= len ( packIDs ) {
allPacksFound = true
}
return nil
} )
if err != nil {
return err
}
if ! allPacksFound {
return errors . Fatal ( "unable to find all specified pack(s)" )
}
debug . Log ( "%d blobs found" , len ( f . blobIDs ) )
return nil
}
2019-03-30 00:23:24 +00:00
func ( f * Finder ) findObjectPack ( ctx context . Context , id string , t restic . BlobType ) {
2018-05-13 15:28:32 +00:00
idx := f . repo . Index ( )
2019-03-30 00:23:24 +00:00
rid , err := restic . ParseID ( id )
if err != nil {
Printf ( "Note: cannot find pack for object '%s', unable to parse ID: %v\n" , id , err )
return
}
2018-05-13 15:28:32 +00:00
2020-11-05 21:18:00 +00:00
blobs := idx . Lookup ( restic . BlobHandle { ID : rid , Type : t } )
2020-06-14 11:26:10 +00:00
if len ( blobs ) == 0 {
2019-03-30 00:23:24 +00:00
Printf ( "Object %s not found in the index\n" , rid . Str ( ) )
return
}
for _ , b := range blobs {
if b . ID . Equal ( rid ) {
Printf ( "Object belongs to pack %s\n ... Pack %s: %s\n" , b . PackID , b . PackID . Str ( ) , b . String ( ) )
break
2018-05-13 15:28:32 +00:00
}
}
}
2019-03-30 00:23:24 +00:00
func ( f * Finder ) findObjectsPacks ( ctx context . Context ) {
for i := range f . blobIDs {
f . findObjectPack ( ctx , i , restic . DataBlob )
}
for i := range f . treeIDs {
f . findObjectPack ( ctx , i , restic . TreeBlob )
}
}
2016-09-17 10:36:05 +00:00
func runFind ( opts FindOptions , gopts GlobalOptions , args [ ] string ) error {
2018-07-14 20:00:36 +00:00
if len ( args ) == 0 {
2017-02-10 18:39:49 +00:00
return errors . Fatal ( "wrong number of arguments" )
2014-12-07 16:11:01 +00:00
}
2017-03-08 19:29:31 +00:00
var err error
2018-07-14 20:00:36 +00:00
pat := findPattern { pattern : args }
2017-03-08 19:29:31 +00:00
if opts . CaseInsensitive {
2018-07-14 20:00:36 +00:00
for i := range pat . pattern {
pat . pattern [ i ] = strings . ToLower ( pat . pattern [ i ] )
}
2017-03-08 19:29:31 +00:00
pat . ignoreCase = true
}
2014-12-07 16:11:01 +00:00
2016-09-17 10:36:05 +00:00
if opts . Oldest != "" {
2017-03-08 19:29:31 +00:00
if pat . oldest , err = parseTime ( opts . Oldest ) ; err != nil {
2014-12-07 16:11:01 +00:00
return err
}
}
2016-09-17 10:36:05 +00:00
if opts . Newest != "" {
2017-03-08 19:29:31 +00:00
if pat . newest , err = parseTime ( opts . Newest ) ; err != nil {
2014-12-07 16:11:01 +00:00
return err
}
2014-12-07 15:30:52 +00:00
}
2018-05-13 15:28:32 +00:00
// Check at most only one kind of IDs is provided: currently we
// can't mix types
if ( opts . BlobID && opts . TreeID ) ||
( opts . BlobID && opts . PackID ) ||
( opts . TreeID && opts . PackID ) {
return errors . Fatal ( "cannot have several ID types" )
}
2016-09-17 10:36:05 +00:00
repo , err := OpenRepository ( gopts )
2014-12-07 15:30:52 +00:00
if err != nil {
return err
2014-12-07 13:44:01 +00:00
}
2016-09-17 10:36:05 +00:00
if ! gopts . NoLock {
2020-08-09 11:24:47 +00:00
lock , err := lockRepo ( gopts . ctx , repo )
2016-09-17 10:36:05 +00:00
defer unlockRepo ( lock )
if err != nil {
return err
}
2015-06-27 12:40:18 +00:00
}
use global context for check, debug, dump, find, forget, init, key,
list, mount, tag, unlock commands
gh-1434
2017-12-06 12:02:55 +00:00
if err = repo . LoadIndex ( gopts . ctx ) ; err != nil {
2015-08-27 21:21:44 +00:00
return err
}
2017-03-08 19:29:31 +00:00
ctx , cancel := context . WithCancel ( gopts . ctx )
defer cancel ( )
2017-06-04 09:38:46 +00:00
f := & Finder {
2018-06-09 16:56:40 +00:00
repo : repo ,
pat : pat ,
out : statefulOutput { ListLong : opts . ListLong , JSON : globalOptions . JSON } ,
ignoreTrees : restic . NewIDSet ( ) ,
2017-06-04 09:38:46 +00:00
}
2018-05-13 15:28:32 +00:00
if opts . BlobID {
f . blobIDs = make ( map [ string ] struct { } )
2018-07-14 20:00:36 +00:00
for _ , pat := range f . pat . pattern {
f . blobIDs [ pat ] = struct { } { }
}
2018-05-13 15:28:32 +00:00
}
if opts . TreeID {
f . treeIDs = make ( map [ string ] struct { } )
2018-07-14 20:00:36 +00:00
for _ , pat := range f . pat . pattern {
f . treeIDs [ pat ] = struct { } { }
}
2018-05-13 15:28:32 +00:00
}
if opts . PackID {
2021-01-30 16:25:10 +00:00
err := f . packsToBlobs ( ctx , [ ] string { f . pat . pattern [ 0 ] } ) // TODO: support multiple packs
if err != nil {
return err
}
2018-05-13 15:28:32 +00:00
}
2020-02-26 21:17:59 +00:00
for sn := range FindFilteredSnapshots ( ctx , repo , opts . Hosts , opts . Tags , opts . Paths , opts . Snapshots ) {
2018-05-13 15:28:32 +00:00
if f . blobIDs != nil || f . treeIDs != nil {
if err = f . findIDs ( ctx , sn ) ; err != nil && err . Error ( ) != "OK" {
return err
}
continue
}
use global context for check, debug, dump, find, forget, init, key,
list, mount, tag, unlock commands
gh-1434
2017-12-06 12:02:55 +00:00
if err = f . findInSnapshot ( ctx , sn ) ; err != nil {
2014-12-07 13:44:01 +00:00
return err
}
}
2017-06-04 09:38:46 +00:00
f . out . Finish ( )
2014-12-07 13:44:01 +00:00
2019-03-30 00:23:24 +00:00
if opts . ShowPackID && ( f . blobIDs != nil || f . treeIDs != nil ) {
f . findObjectsPacks ( ctx )
2018-05-13 15:28:32 +00:00
}
2014-12-07 13:44:01 +00:00
return nil
}