Uses new digest package instead of string digests
Also drops extraneous test package and uses testutil insteadmaster
							parent
							
								
									1336ced030
								
							
						
					
					
						commit
						64c8bd29cc
					
				|  | @ -11,6 +11,7 @@ import ( | |||
| 	"strconv" | ||||
| 
 | ||||
| 	"github.com/docker/docker-registry" | ||||
| 	"github.com/docker/docker-registry/digest" | ||||
| ) | ||||
| 
 | ||||
| // Client implements the client interface to the registry http api
 | ||||
|  | @ -33,13 +34,13 @@ type Client interface { | |||
| 	// BlobLength returns the length of the blob stored at the given name,
 | ||||
| 	// digest pair.
 | ||||
| 	// Returns a length value of -1 on error or if the blob does not exist.
 | ||||
| 	BlobLength(name, digest string) (int, error) | ||||
| 	BlobLength(name string, dgst digest.Digest) (int, error) | ||||
| 
 | ||||
| 	// GetBlob returns the blob stored at the given name, digest pair in the
 | ||||
| 	// form of an io.ReadCloser with the length of this blob.
 | ||||
| 	// A nonzero byteOffset can be provided to receive a partial blob beginning
 | ||||
| 	// at the given offset.
 | ||||
| 	GetBlob(name, digest string, byteOffset int) (io.ReadCloser, int, error) | ||||
| 	GetBlob(name string, dgst digest.Digest, byteOffset int) (io.ReadCloser, int, error) | ||||
| 
 | ||||
| 	// InitiateBlobUpload starts a blob upload in the given repository namespace
 | ||||
| 	// and returns a unique location url to use for other blob upload methods.
 | ||||
|  | @ -50,7 +51,7 @@ type Client interface { | |||
| 	GetBlobUploadStatus(location string) (int, int, error) | ||||
| 
 | ||||
| 	// UploadBlob uploads a full blob to the registry.
 | ||||
| 	UploadBlob(location string, blob io.ReadCloser, length int, digest string) error | ||||
| 	UploadBlob(location string, blob io.ReadCloser, length int, dgst digest.Digest) error | ||||
| 
 | ||||
| 	// UploadBlobChunk uploads a blob chunk with a given length and startByte to
 | ||||
| 	// the registry.
 | ||||
|  | @ -59,7 +60,7 @@ type Client interface { | |||
| 
 | ||||
| 	// FinishChunkedBlobUpload completes a chunked blob upload at a given
 | ||||
| 	// location.
 | ||||
| 	FinishChunkedBlobUpload(location string, length int, digest string) error | ||||
| 	FinishChunkedBlobUpload(location string, length int, dgst digest.Digest) error | ||||
| 
 | ||||
| 	// CancelBlobUpload deletes all content at the unfinished blob upload
 | ||||
| 	// location and invalidates any future calls to this blob upload.
 | ||||
|  | @ -222,8 +223,8 @@ func (r *clientImpl) ListImageTags(name string) ([]string, error) { | |||
| 	return tags.Tags, nil | ||||
| } | ||||
| 
 | ||||
| func (r *clientImpl) BlobLength(name, digest string) (int, error) { | ||||
| 	response, err := http.Head(fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, digest)) | ||||
| func (r *clientImpl) BlobLength(name string, dgst digest.Digest) (int, error) { | ||||
| 	response, err := http.Head(fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, dgst)) | ||||
| 	if err != nil { | ||||
| 		return -1, err | ||||
| 	} | ||||
|  | @ -254,9 +255,9 @@ func (r *clientImpl) BlobLength(name, digest string) (int, error) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *clientImpl) GetBlob(name, digest string, byteOffset int) (io.ReadCloser, int, error) { | ||||
| func (r *clientImpl) GetBlob(name string, dgst digest.Digest, byteOffset int) (io.ReadCloser, int, error) { | ||||
| 	getRequest, err := http.NewRequest("GET", | ||||
| 		fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, digest), nil) | ||||
| 		fmt.Sprintf("%s/v2/%s/blob/%s", r.Endpoint, name, dgst), nil) | ||||
| 	if err != nil { | ||||
| 		return nil, 0, err | ||||
| 	} | ||||
|  | @ -278,7 +279,7 @@ func (r *clientImpl) GetBlob(name, digest string, byteOffset int) (io.ReadCloser | |||
| 		return response.Body, int(length), nil | ||||
| 	case response.StatusCode == http.StatusNotFound: | ||||
| 		response.Body.Close() | ||||
| 		return nil, 0, ®istry.BlobNotFoundError{Name: name, Digest: digest} | ||||
| 		return nil, 0, ®istry.BlobNotFoundError{Name: name, Digest: dgst} | ||||
| 	case response.StatusCode >= 400 && response.StatusCode < 500: | ||||
| 		errors := new(registry.Errors) | ||||
| 		decoder := json.NewDecoder(response.Body) | ||||
|  | @ -351,7 +352,7 @@ func (r *clientImpl) GetBlobUploadStatus(location string) (int, int, error) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *clientImpl) UploadBlob(location string, blob io.ReadCloser, length int, digest string) error { | ||||
| func (r *clientImpl) UploadBlob(location string, blob io.ReadCloser, length int, dgst digest.Digest) error { | ||||
| 	defer blob.Close() | ||||
| 
 | ||||
| 	putRequest, err := http.NewRequest("PUT", | ||||
|  | @ -362,7 +363,7 @@ func (r *clientImpl) UploadBlob(location string, blob io.ReadCloser, length int, | |||
| 
 | ||||
| 	queryValues := url.Values{} | ||||
| 	queryValues.Set("length", fmt.Sprint(length)) | ||||
| 	queryValues.Set("digest", digest) | ||||
| 	queryValues.Set("digest", dgst.String()) | ||||
| 	putRequest.URL.RawQuery = queryValues.Encode() | ||||
| 
 | ||||
| 	putRequest.Header.Set("Content-Type", "application/octet-stream") | ||||
|  | @ -444,7 +445,7 @@ func (r *clientImpl) UploadBlobChunk(location string, blobChunk io.ReadCloser, l | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (r *clientImpl) FinishChunkedBlobUpload(location string, length int, digest string) error { | ||||
| func (r *clientImpl) FinishChunkedBlobUpload(location string, length int, dgst digest.Digest) error { | ||||
| 	putRequest, err := http.NewRequest("PUT", | ||||
| 		fmt.Sprintf("%s%s", r.Endpoint, location), nil) | ||||
| 	if err != nil { | ||||
|  | @ -453,7 +454,7 @@ func (r *clientImpl) FinishChunkedBlobUpload(location string, length int, digest | |||
| 
 | ||||
| 	queryValues := new(url.Values) | ||||
| 	queryValues.Set("length", fmt.Sprint(length)) | ||||
| 	queryValues.Set("digest", digest) | ||||
| 	queryValues.Set("digest", dgst.String()) | ||||
| 	putRequest.URL.RawQuery = queryValues.Encode() | ||||
| 
 | ||||
| 	putRequest.Header.Set("Content-Type", "application/octet-stream") | ||||
|  |  | |||
|  | @ -10,11 +10,12 @@ import ( | |||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/docker/docker-registry" | ||||
| 	"github.com/docker/docker-registry/test" | ||||
| 	"github.com/docker/docker-registry/common/testutil" | ||||
| 	"github.com/docker/docker-registry/digest" | ||||
| ) | ||||
| 
 | ||||
| type testBlob struct { | ||||
| 	digest   string | ||||
| 	digest   digest.Digest | ||||
| 	contents []byte | ||||
| } | ||||
| 
 | ||||
|  | @ -42,7 +43,7 @@ func TestPush(t *testing.T) { | |||
| 		// to change at some point.
 | ||||
| 		uploadLocations[i] = fmt.Sprintf("/v2/%s/blob/test-uuid", name) | ||||
| 		blobs[i] = registry.FSLayer{BlobSum: blob.digest} | ||||
| 		history[i] = registry.ManifestHistory{V1Compatibility: blob.digest} | ||||
| 		history[i] = registry.ManifestHistory{V1Compatibility: blob.digest.String()} | ||||
| 	} | ||||
| 
 | ||||
| 	manifest := ®istry.ImageManifest{ | ||||
|  | @ -55,44 +56,44 @@ func TestPush(t *testing.T) { | |||
| 	} | ||||
| 	manifestBytes, err := json.Marshal(manifest) | ||||
| 
 | ||||
| 	blobRequestResponseMappings := make([]test.RequestResponseMapping, 2*len(testBlobs)) | ||||
| 	blobRequestResponseMappings := make([]testutil.RequestResponseMapping, 2*len(testBlobs)) | ||||
| 	for i, blob := range testBlobs { | ||||
| 		blobRequestResponseMappings[2*i] = test.RequestResponseMapping{ | ||||
| 			Request: test.Request{ | ||||
| 		blobRequestResponseMappings[2*i] = testutil.RequestResponseMapping{ | ||||
| 			Request: testutil.Request{ | ||||
| 				Method: "POST", | ||||
| 				Route:  "/v2/" + name + "/blob/upload/", | ||||
| 			}, | ||||
| 			Response: test.Response{ | ||||
| 			Response: testutil.Response{ | ||||
| 				StatusCode: http.StatusAccepted, | ||||
| 				Headers: http.Header(map[string][]string{ | ||||
| 					"Location": {uploadLocations[i]}, | ||||
| 				}), | ||||
| 			}, | ||||
| 		} | ||||
| 		blobRequestResponseMappings[2*i+1] = test.RequestResponseMapping{ | ||||
| 			Request: test.Request{ | ||||
| 		blobRequestResponseMappings[2*i+1] = testutil.RequestResponseMapping{ | ||||
| 			Request: testutil.Request{ | ||||
| 				Method: "PUT", | ||||
| 				Route:  uploadLocations[i], | ||||
| 				QueryParams: map[string][]string{ | ||||
| 					"length": {fmt.Sprint(len(blob.contents))}, | ||||
| 					"digest": {blob.digest}, | ||||
| 					"digest": {blob.digest.String()}, | ||||
| 				}, | ||||
| 				Body: blob.contents, | ||||
| 			}, | ||||
| 			Response: test.Response{ | ||||
| 			Response: testutil.Response{ | ||||
| 				StatusCode: http.StatusCreated, | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	handler := test.NewHandler(append(blobRequestResponseMappings, test.RequestResponseMap{ | ||||
| 		test.RequestResponseMapping{ | ||||
| 			Request: test.Request{ | ||||
| 	handler := testutil.NewHandler(append(blobRequestResponseMappings, testutil.RequestResponseMap{ | ||||
| 		testutil.RequestResponseMapping{ | ||||
| 			Request: testutil.Request{ | ||||
| 				Method: "PUT", | ||||
| 				Route:  "/v2/" + name + "/manifest/" + tag, | ||||
| 				Body:   manifestBytes, | ||||
| 			}, | ||||
| 			Response: test.Response{ | ||||
| 			Response: testutil.Response{ | ||||
| 				StatusCode: http.StatusOK, | ||||
| 			}, | ||||
| 		}, | ||||
|  | @ -102,7 +103,7 @@ func TestPush(t *testing.T) { | |||
| 	objectStore := &memoryObjectStore{ | ||||
| 		mutex:           new(sync.Mutex), | ||||
| 		manifestStorage: make(map[string]*registry.ImageManifest), | ||||
| 		layerStorage:    make(map[string]Layer), | ||||
| 		layerStorage:    make(map[digest.Digest]Layer), | ||||
| 	} | ||||
| 
 | ||||
| 	for _, blob := range testBlobs { | ||||
|  | @ -146,7 +147,7 @@ func TestPull(t *testing.T) { | |||
| 
 | ||||
| 	for i, blob := range testBlobs { | ||||
| 		blobs[i] = registry.FSLayer{BlobSum: blob.digest} | ||||
| 		history[i] = registry.ManifestHistory{V1Compatibility: blob.digest} | ||||
| 		history[i] = registry.ManifestHistory{V1Compatibility: blob.digest.String()} | ||||
| 	} | ||||
| 
 | ||||
| 	manifest := ®istry.ImageManifest{ | ||||
|  | @ -159,27 +160,27 @@ func TestPull(t *testing.T) { | |||
| 	} | ||||
| 	manifestBytes, err := json.Marshal(manifest) | ||||
| 
 | ||||
| 	blobRequestResponseMappings := make([]test.RequestResponseMapping, len(testBlobs)) | ||||
| 	blobRequestResponseMappings := make([]testutil.RequestResponseMapping, len(testBlobs)) | ||||
| 	for i, blob := range testBlobs { | ||||
| 		blobRequestResponseMappings[i] = test.RequestResponseMapping{ | ||||
| 			Request: test.Request{ | ||||
| 		blobRequestResponseMappings[i] = testutil.RequestResponseMapping{ | ||||
| 			Request: testutil.Request{ | ||||
| 				Method: "GET", | ||||
| 				Route:  "/v2/" + name + "/blob/" + blob.digest, | ||||
| 				Route:  "/v2/" + name + "/blob/" + blob.digest.String(), | ||||
| 			}, | ||||
| 			Response: test.Response{ | ||||
| 			Response: testutil.Response{ | ||||
| 				StatusCode: http.StatusOK, | ||||
| 				Body:       blob.contents, | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	handler := test.NewHandler(append(blobRequestResponseMappings, test.RequestResponseMap{ | ||||
| 		test.RequestResponseMapping{ | ||||
| 			Request: test.Request{ | ||||
| 	handler := testutil.NewHandler(append(blobRequestResponseMappings, testutil.RequestResponseMap{ | ||||
| 		testutil.RequestResponseMapping{ | ||||
| 			Request: testutil.Request{ | ||||
| 				Method: "GET", | ||||
| 				Route:  "/v2/" + name + "/manifest/" + tag, | ||||
| 			}, | ||||
| 			Response: test.Response{ | ||||
| 			Response: testutil.Response{ | ||||
| 				StatusCode: http.StatusOK, | ||||
| 				Body:       manifestBytes, | ||||
| 			}, | ||||
|  | @ -190,7 +191,7 @@ func TestPull(t *testing.T) { | |||
| 	objectStore := &memoryObjectStore{ | ||||
| 		mutex:           new(sync.Mutex), | ||||
| 		manifestStorage: make(map[string]*registry.ImageManifest), | ||||
| 		layerStorage:    make(map[string]Layer), | ||||
| 		layerStorage:    make(map[digest.Digest]Layer), | ||||
| 	} | ||||
| 
 | ||||
| 	err = Pull(client, objectStore, name, tag) | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ import ( | |||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/docker/docker-registry" | ||||
| 	"github.com/docker/docker-registry/digest" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
|  | @ -34,7 +35,7 @@ type ObjectStore interface { | |||
| 	WriteManifest(name, tag string, manifest *registry.ImageManifest) error | ||||
| 
 | ||||
| 	// Layer returns a handle to a layer for reading and writing
 | ||||
| 	Layer(blobSum string) (Layer, error) | ||||
| 	Layer(dgst digest.Digest) (Layer, error) | ||||
| } | ||||
| 
 | ||||
| // Layer is a generic image layer interface.
 | ||||
|  | @ -56,7 +57,7 @@ type Layer interface { | |||
| type memoryObjectStore struct { | ||||
| 	mutex           *sync.Mutex | ||||
| 	manifestStorage map[string]*registry.ImageManifest | ||||
| 	layerStorage    map[string]Layer | ||||
| 	layerStorage    map[digest.Digest]Layer | ||||
| } | ||||
| 
 | ||||
| func (objStore *memoryObjectStore) Manifest(name, tag string) (*registry.ImageManifest, error) { | ||||
|  | @ -78,14 +79,14 @@ func (objStore *memoryObjectStore) WriteManifest(name, tag string, manifest *reg | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (objStore *memoryObjectStore) Layer(blobSum string) (Layer, error) { | ||||
| func (objStore *memoryObjectStore) Layer(dgst digest.Digest) (Layer, error) { | ||||
| 	objStore.mutex.Lock() | ||||
| 	defer objStore.mutex.Unlock() | ||||
| 
 | ||||
| 	layer, ok := objStore.layerStorage[blobSum] | ||||
| 	layer, ok := objStore.layerStorage[dgst] | ||||
| 	if !ok { | ||||
| 		layer = &memoryLayer{cond: sync.NewCond(new(sync.Mutex))} | ||||
| 		objStore.layerStorage[blobSum] = layer | ||||
| 		objStore.layerStorage[dgst] = layer | ||||
| 	} | ||||
| 
 | ||||
| 	return layer, nil | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| package test | ||||
| package testutil | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
|  | @ -3,6 +3,8 @@ package registry | |||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/docker/docker-registry/digest" | ||||
| ) | ||||
| 
 | ||||
| // ErrorCode represents the error type. The errors are serialized via strings
 | ||||
|  | @ -228,7 +230,7 @@ func (e *ImageManifestNotFoundError) Error() string { | |||
| // layer that does not exist in the registry.
 | ||||
| type BlobNotFoundError struct { | ||||
| 	Name   string | ||||
| 	Digest string | ||||
| 	Digest digest.Digest | ||||
| } | ||||
| 
 | ||||
| func (e *BlobNotFoundError) Error() string { | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import ( | |||
| 	"encoding/json" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/docker/docker-registry/digest" | ||||
| 	"github.com/gorilla/handlers" | ||||
| ) | ||||
| 
 | ||||
|  | @ -52,7 +53,7 @@ func (m *ImageManifest) UnmarshalJSON(b []byte) error { | |||
| // FSLayer is a container struct for BlobSums defined in an image manifest
 | ||||
| type FSLayer struct { | ||||
| 	// BlobSum is the tarsum of the referenced filesystem image layer
 | ||||
| 	BlobSum string `json:"blobSum"` | ||||
| 	BlobSum digest.Digest `json:"blobSum"` | ||||
| } | ||||
| 
 | ||||
| // ManifestHistory stores unstructured v1 compatibility information
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue