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

     1  // Package base provides a base implementation of the storage driver that can
     2  // be used to implement common checks. The goal is to increase the amount of
     3  // code sharing.
     4  //
     5  // The canonical approach to use this class is to embed in the exported driver
     6  // struct such that calls are proxied through this implementation. First,
     7  // declare the internal driver, as follows:
     8  //
     9  // 	type driver struct { ... internal ...}
    10  //
    11  // The resulting type should implement StorageDriver such that it can be the
    12  // target of a Base struct. The exported type can then be declared as follows:
    13  //
    14  // 	type Driver struct {
    15  // 		Base
    16  // 	}
    17  //
    18  // Because Driver embeds Base, it effectively implements Base. If the driver
    19  // needs to intercept a call, before going to base, Driver should implement
    20  // that method. Effectively, Driver can intercept calls before coming in and
    21  // driver implements the actual logic.
    22  //
    23  // To further shield the embed from other packages, it is recommended to
    24  // employ a private embed struct:
    25  //
    26  // 	type baseEmbed struct {
    27  // 		base.Base
    28  // 	}
    29  //
    30  // Then, declare driver to embed baseEmbed, rather than Base directly:
    31  //
    32  // 	type Driver struct {
    33  // 		baseEmbed
    34  // 	}
    35  //
    36  // The type now implements StorageDriver, proxying through Base, without
    37  // exporting an unnecessary field.
    38  package base
    39  
    40  import (
    41  	"io"
    42  
    43  	"github.com/docker/distribution/context"
    44  	storagedriver "github.com/docker/distribution/registry/storage/driver"
    45  )
    46  
    47  // Base provides a wrapper around a storagedriver implementation that provides
    48  // common path and bounds checking.
    49  type Base struct {
    50  	storagedriver.StorageDriver
    51  }
    52  
    53  // Format errors received from the storage driver
    54  func (base *Base) setDriverName(e error) error {
    55  	switch actual := e.(type) {
    56  	case nil:
    57  		return nil
    58  	case storagedriver.ErrUnsupportedMethod:
    59  		actual.DriverName = base.StorageDriver.Name()
    60  		return actual
    61  	case storagedriver.PathNotFoundError:
    62  		actual.DriverName = base.StorageDriver.Name()
    63  		return actual
    64  	case storagedriver.InvalidPathError:
    65  		actual.DriverName = base.StorageDriver.Name()
    66  		return actual
    67  	case storagedriver.InvalidOffsetError:
    68  		actual.DriverName = base.StorageDriver.Name()
    69  		return actual
    70  	default:
    71  		storageError := storagedriver.Error{
    72  			DriverName: base.StorageDriver.Name(),
    73  			Enclosed:   e,
    74  		}
    75  
    76  		return storageError
    77  	}
    78  }
    79  
    80  // GetContent wraps GetContent of underlying storage driver.
    81  func (base *Base) GetContent(ctx context.Context, path string) ([]byte, error) {
    82  	ctx, done := context.WithTrace(ctx)
    83  	defer done("%s.GetContent(%q)", base.Name(), path)
    84  
    85  	if !storagedriver.PathRegexp.MatchString(path) {
    86  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
    87  	}
    88  
    89  	b, e := base.StorageDriver.GetContent(ctx, path)
    90  	return b, base.setDriverName(e)
    91  }
    92  
    93  // PutContent wraps PutContent of underlying storage driver.
    94  func (base *Base) PutContent(ctx context.Context, path string, content []byte) error {
    95  	ctx, done := context.WithTrace(ctx)
    96  	defer done("%s.PutContent(%q)", base.Name(), path)
    97  
    98  	if !storagedriver.PathRegexp.MatchString(path) {
    99  		return storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   100  	}
   101  
   102  	return base.setDriverName(base.StorageDriver.PutContent(ctx, path, content))
   103  }
   104  
   105  // ReadStream wraps ReadStream of underlying storage driver.
   106  func (base *Base) ReadStream(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
   107  	ctx, done := context.WithTrace(ctx)
   108  	defer done("%s.ReadStream(%q, %d)", base.Name(), path, offset)
   109  
   110  	if offset < 0 {
   111  		return nil, storagedriver.InvalidOffsetError{Path: path, Offset: offset, DriverName: base.StorageDriver.Name()}
   112  	}
   113  
   114  	if !storagedriver.PathRegexp.MatchString(path) {
   115  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   116  	}
   117  
   118  	rc, e := base.StorageDriver.ReadStream(ctx, path, offset)
   119  	return rc, base.setDriverName(e)
   120  }
   121  
   122  // WriteStream wraps WriteStream of underlying storage driver.
   123  func (base *Base) WriteStream(ctx context.Context, path string, offset int64, reader io.Reader) (nn int64, err error) {
   124  	ctx, done := context.WithTrace(ctx)
   125  	defer done("%s.WriteStream(%q, %d)", base.Name(), path, offset)
   126  
   127  	if offset < 0 {
   128  		return 0, storagedriver.InvalidOffsetError{Path: path, Offset: offset, DriverName: base.StorageDriver.Name()}
   129  	}
   130  
   131  	if !storagedriver.PathRegexp.MatchString(path) {
   132  		return 0, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   133  	}
   134  
   135  	i64, e := base.StorageDriver.WriteStream(ctx, path, offset, reader)
   136  	return i64, base.setDriverName(e)
   137  }
   138  
   139  // Stat wraps Stat of underlying storage driver.
   140  func (base *Base) Stat(ctx context.Context, path string) (storagedriver.FileInfo, error) {
   141  	ctx, done := context.WithTrace(ctx)
   142  	defer done("%s.Stat(%q)", base.Name(), path)
   143  
   144  	if !storagedriver.PathRegexp.MatchString(path) {
   145  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   146  	}
   147  
   148  	fi, e := base.StorageDriver.Stat(ctx, path)
   149  	return fi, base.setDriverName(e)
   150  }
   151  
   152  // List wraps List of underlying storage driver.
   153  func (base *Base) List(ctx context.Context, path string) ([]string, error) {
   154  	ctx, done := context.WithTrace(ctx)
   155  	defer done("%s.List(%q)", base.Name(), path)
   156  
   157  	if !storagedriver.PathRegexp.MatchString(path) && path != "/" {
   158  		return nil, storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   159  	}
   160  
   161  	str, e := base.StorageDriver.List(ctx, path)
   162  	return str, base.setDriverName(e)
   163  }
   164  
   165  // Move wraps Move of underlying storage driver.
   166  func (base *Base) Move(ctx context.Context, sourcePath string, destPath string) error {
   167  	ctx, done := context.WithTrace(ctx)
   168  	defer done("%s.Move(%q, %q", base.Name(), sourcePath, destPath)
   169  
   170  	if !storagedriver.PathRegexp.MatchString(sourcePath) {
   171  		return storagedriver.InvalidPathError{Path: sourcePath, DriverName: base.StorageDriver.Name()}
   172  	} else if !storagedriver.PathRegexp.MatchString(destPath) {
   173  		return storagedriver.InvalidPathError{Path: destPath, DriverName: base.StorageDriver.Name()}
   174  	}
   175  
   176  	return base.setDriverName(base.StorageDriver.Move(ctx, sourcePath, destPath))
   177  }
   178  
   179  // Delete wraps Delete of underlying storage driver.
   180  func (base *Base) Delete(ctx context.Context, path string) error {
   181  	ctx, done := context.WithTrace(ctx)
   182  	defer done("%s.Delete(%q)", base.Name(), path)
   183  
   184  	if !storagedriver.PathRegexp.MatchString(path) {
   185  		return storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   186  	}
   187  
   188  	return base.setDriverName(base.StorageDriver.Delete(ctx, path))
   189  }
   190  
   191  // URLFor wraps URLFor of underlying storage driver.
   192  func (base *Base) URLFor(ctx context.Context, path string, options map[string]interface{}) (string, error) {
   193  	ctx, done := context.WithTrace(ctx)
   194  	defer done("%s.URLFor(%q)", base.Name(), path)
   195  
   196  	if !storagedriver.PathRegexp.MatchString(path) {
   197  		return "", storagedriver.InvalidPathError{Path: path, DriverName: base.StorageDriver.Name()}
   198  	}
   199  
   200  	str, e := base.StorageDriver.URLFor(ctx, path, options)
   201  	return str, base.setDriverName(e)
   202  }