github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/storage/walk.go (about)

     1  package storage
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sort"
     7  
     8  	"github.com/docker/distribution/context"
     9  	storageDriver "github.com/docker/distribution/registry/storage/driver"
    10  )
    11  
    12  // ErrSkipDir is used as a return value from onFileFunc to indicate that
    13  // the directory named in the call is to be skipped. It is not returned
    14  // as an error by any function.
    15  var ErrSkipDir = errors.New("skip this directory")
    16  
    17  // WalkFn is called once per file by Walk
    18  // If the returned error is ErrSkipDir and fileInfo refers
    19  // to a directory, the directory will not be entered and Walk
    20  // will continue the traversal.  Otherwise Walk will return
    21  type WalkFn func(fileInfo storageDriver.FileInfo) error
    22  
    23  // Walk traverses a filesystem defined within driver, starting
    24  // from the given path, calling f on each file
    25  func Walk(ctx context.Context, driver storageDriver.StorageDriver, from string, f WalkFn) error {
    26  	children, err := driver.List(ctx, from)
    27  	if err != nil {
    28  		return err
    29  	}
    30  	sort.Stable(sort.StringSlice(children))
    31  	for _, child := range children {
    32  		// TODO(stevvooe): Calling driver.Stat for every entry is quite
    33  		// expensive when running against backends with a slow Stat
    34  		// implementation, such as s3. This is very likely a serious
    35  		// performance bottleneck.
    36  		fileInfo, err := driver.Stat(ctx, child)
    37  		if err != nil {
    38  			return err
    39  		}
    40  		err = f(fileInfo)
    41  		skipDir := (err == ErrSkipDir)
    42  		if err != nil && !skipDir {
    43  			return err
    44  		}
    45  
    46  		if fileInfo.IsDir() && !skipDir {
    47  			if err := Walk(ctx, driver, child, f); err != nil {
    48  				return err
    49  			}
    50  		}
    51  	}
    52  	return nil
    53  }
    54  
    55  // pushError formats an error type given a path and an error
    56  // and pushes it to a slice of errors
    57  func pushError(errors []error, path string, err error) []error {
    58  	return append(errors, fmt.Errorf("%s: %s", path, err))
    59  }