Browse Source

vendor docker/distribution 4e17ab5d319ac5b70b2769442947567a83386fbc

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
Antonio Murdaca 9 years ago
parent
commit
8aa37bdbb7

+ 1 - 1
hack/vendor.sh

@@ -87,7 +87,7 @@ clone git github.com/boltdb/bolt v1.2.1
 clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
 clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
 
 
 # get graph and distribution packages
 # get graph and distribution packages
-clone git github.com/docker/distribution 5bbf65499960b184fe8e0f045397375e1a6722b8
+clone git github.com/docker/distribution 4e17ab5d319ac5b70b2769442947567a83386fbc
 clone git github.com/vbatts/tar-split v0.9.11
 clone git github.com/vbatts/tar-split v0.9.11
 
 
 # get go-zfs packages
 # get go-zfs packages

+ 3 - 1
vendor/src/github.com/docker/distribution/.mailmap

@@ -13,4 +13,6 @@ Sharif Nassar <sharif@mrwacky.com> Sharif Nassar <mrwacky42@users.noreply.github
 Sven Dowideit <SvenDowideit@home.org.au> Sven Dowideit <SvenDowideit@users.noreply.github.com>
 Sven Dowideit <SvenDowideit@home.org.au> Sven Dowideit <SvenDowideit@users.noreply.github.com>
 Vincent Giersch <vincent.giersch@ovh.net> Vincent Giersch <vincent@giersch.fr>
 Vincent Giersch <vincent.giersch@ovh.net> Vincent Giersch <vincent@giersch.fr>
 davidli <wenquan.li@hp.com> davidli <wenquan.li@hpe.com>
 davidli <wenquan.li@hp.com> davidli <wenquan.li@hpe.com>
-Omer Cohen <git@omer.io> Omer Cohen <git@omerc.net>
+Omer Cohen <git@omer.io> Omer Cohen <git@omerc.net>
+Eric Yang <windfarer@gmail.com> Eric Yang <Windfarer@users.noreply.github.com>
+Nikita Tarasov <nikita@mygento.ru> Nikita <luckyraul@users.noreply.github.com>

+ 7 - 0
vendor/src/github.com/docker/distribution/AUTHORS

@@ -6,6 +6,8 @@ Adrian Mouat <adrian.mouat@gmail.com>
 Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
 Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
 Alex Chan <alex.chan@metaswitch.com>
 Alex Chan <alex.chan@metaswitch.com>
 Alex Elman <aelman@indeed.com>
 Alex Elman <aelman@indeed.com>
+Alexey Gladkov <gladkov.alexey@gmail.com>
+allencloud <allen.sun@daocloud.io>
 amitshukla <ashukla73@hotmail.com>
 amitshukla <ashukla73@hotmail.com>
 Amy Lindburg <amy.lindburg@docker.com>
 Amy Lindburg <amy.lindburg@docker.com>
 Andrew Hsu <andrewhsu@acm.org>
 Andrew Hsu <andrewhsu@acm.org>
@@ -30,6 +32,7 @@ Brian Bland <brian.bland@docker.com>
 burnettk <burnettk@gmail.com>
 burnettk <burnettk@gmail.com>
 Carson A <ca@carsonoid.net>
 Carson A <ca@carsonoid.net>
 Chris Dillon <squarism@gmail.com>
 Chris Dillon <squarism@gmail.com>
+cyli <cyli@twistedmatrix.com>
 Daisuke Fujita <dtanshi45@gmail.com>
 Daisuke Fujita <dtanshi45@gmail.com>
 Daniel Huhn <daniel@danielhuhn.de>
 Daniel Huhn <daniel@danielhuhn.de>
 Darren Shepherd <darren@rancher.com>
 Darren Shepherd <darren@rancher.com>
@@ -52,6 +55,7 @@ Felix Yan <felixonmars@archlinux.org>
 Florentin Raud <florentin.raud@gmail.com>
 Florentin Raud <florentin.raud@gmail.com>
 Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
 Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
 gabriell nascimento <gabriell@bluesoft.com.br>
 gabriell nascimento <gabriell@bluesoft.com.br>
+Gleb Schukin <gschukin@ptsecurity.com>
 harche <p.harshal@gmail.com>
 harche <p.harshal@gmail.com>
 Henri Gomez <henri.gomez@gmail.com>
 Henri Gomez <henri.gomez@gmail.com>
 Hu Keping <hukeping@huawei.com>
 Hu Keping <hukeping@huawei.com>
@@ -72,6 +76,7 @@ Jonathan Boulle <jonathanboulle@gmail.com>
 Jordan Liggitt <jliggitt@redhat.com>
 Jordan Liggitt <jliggitt@redhat.com>
 Josh Hawn <josh.hawn@docker.com>
 Josh Hawn <josh.hawn@docker.com>
 Julien Fernandez <julien.fernandez@gmail.com>
 Julien Fernandez <julien.fernandez@gmail.com>
+Ke Xu <leonhartx.k@gmail.com>
 Keerthan Mala <kmala@engineyard.com>
 Keerthan Mala <kmala@engineyard.com>
 Kelsey Hightower <kelsey.hightower@gmail.com>
 Kelsey Hightower <kelsey.hightower@gmail.com>
 Kenneth Lim <kennethlimcp@gmail.com>
 Kenneth Lim <kennethlimcp@gmail.com>
@@ -94,6 +99,7 @@ moxiegirl <mary@docker.com>
 Nathan Sullivan <nathan@nightsys.net>
 Nathan Sullivan <nathan@nightsys.net>
 nevermosby <robolwq@qq.com>
 nevermosby <robolwq@qq.com>
 Nghia Tran <tcnghia@gmail.com>
 Nghia Tran <tcnghia@gmail.com>
+Nikita Tarasov <nikita@mygento.ru>
 Nuutti Kotivuori <nuutti.kotivuori@poplatek.fi>
 Nuutti Kotivuori <nuutti.kotivuori@poplatek.fi>
 Oilbeater <liumengxinfly@gmail.com>
 Oilbeater <liumengxinfly@gmail.com>
 Olivier Gambier <olivier@docker.com>
 Olivier Gambier <olivier@docker.com>
@@ -137,4 +143,5 @@ xg.song <xg.song@venusource.com>
 xiekeyang <xiekeyang@huawei.com>
 xiekeyang <xiekeyang@huawei.com>
 Yann ROBERT <yann.robert@anantaplex.fr>
 Yann ROBERT <yann.robert@anantaplex.fr>
 yuzou <zouyu7@huawei.com>
 yuzou <zouyu7@huawei.com>
+zhouhaibing089 <zhouhaibing089@gmail.com>
 姜继忠 <jizhong.jiangjz@alibaba-inc.com>
 姜继忠 <jizhong.jiangjz@alibaba-inc.com>

+ 119 - 0
vendor/src/github.com/docker/distribution/BUILDING.md

@@ -0,0 +1,119 @@
+
+# Building the registry source
+
+## Use-case
+
+This is useful if you intend to actively work on the registry.
+
+### Alternatives
+
+Most people should use the [official Registry docker image](https://hub.docker.com/r/library/registry/).
+
+People looking for advanced operational use cases might consider rolling their own image with a custom Dockerfile inheriting `FROM registry:2`.
+
+OS X users who want to run natively can do so following [the instructions here](osx-setup-guide.md).
+
+### Gotchas
+
+You are expected to know your way around with go & git.
+
+If you are a casual user with no development experience, and no preliminary knowledge of go, building from source is probably not a good solution for you.
+
+## Build the development environment
+
+The first prerequisite of properly building distribution targets is to have a Go
+development environment setup. Please follow [How to Write Go Code](https://golang.org/doc/code.html)
+for proper setup. If done correctly, you should have a GOROOT and GOPATH set in the
+environment.
+
+If a Go development environment is setup, one can use `go get` to install the
+`registry` command from the current latest:
+
+    go get github.com/docker/distribution/cmd/registry
+
+The above will install the source repository into the `GOPATH`.
+
+Now create the directory for the registry data (this might require you to set permissions properly)
+
+    mkdir -p /var/lib/registry
+
+... or alternatively `export REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/somewhere` if you want to store data into another location.
+
+The `registry`
+binary can then be run with the following:
+
+    $ $GOPATH/bin/registry --version
+    $GOPATH/bin/registry github.com/docker/distribution v2.0.0-alpha.1+unknown
+
+> __NOTE:__ While you do not need to use `go get` to checkout the distribution
+> project, for these build instructions to work, the project must be checked
+> out in the correct location in the `GOPATH`. This should almost always be
+> `$GOPATH/src/github.com/docker/distribution`.
+
+The registry can be run with the default config using the following
+incantation:
+
+    $ $GOPATH/bin/registry serve $GOPATH/src/github.com/docker/distribution/cmd/registry/config-example.yml
+    INFO[0000] endpoint local-5003 disabled, skipping        app.id=34bbec38-a91a-494a-9a3f-b72f9010081f version=v2.0.0-alpha.1+unknown
+    INFO[0000] endpoint local-8083 disabled, skipping        app.id=34bbec38-a91a-494a-9a3f-b72f9010081f version=v2.0.0-alpha.1+unknown
+    INFO[0000] listening on :5000                            app.id=34bbec38-a91a-494a-9a3f-b72f9010081f version=v2.0.0-alpha.1+unknown
+    INFO[0000] debug server listening localhost:5001
+
+If it is working, one should see the above log messages.
+
+### Repeatable Builds
+
+For the full development experience, one should `cd` into
+`$GOPATH/src/github.com/docker/distribution`. From there, the regular `go`
+commands, such as `go test`, should work per package (please see
+[Developing](#developing) if they don't work).
+
+A `Makefile` has been provided as a convenience to support repeatable builds.
+Please install the following into `GOPATH` for it to work:
+
+    go get github.com/tools/godep github.com/golang/lint/golint
+
+**TODO(stevvooe):** Add a `make setup` command to Makefile to run this. Have to think about how to interact with Godeps properly.
+
+Once these commands are available in the `GOPATH`, run `make` to get a full
+build:
+
+    $ make
+    + clean
+    + fmt
+    + vet
+    + lint
+    + build
+    github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar
+    github.com/Sirupsen/logrus
+    github.com/docker/libtrust
+    ...
+    github.com/yvasiyarov/gorelic
+    github.com/docker/distribution/registry/handlers
+    github.com/docker/distribution/cmd/registry
+    + test
+    ...
+    ok    github.com/docker/distribution/digest 7.875s
+    ok    github.com/docker/distribution/manifest 0.028s
+    ok    github.com/docker/distribution/notifications  17.322s
+    ?     github.com/docker/distribution/registry [no test files]
+    ok    github.com/docker/distribution/registry/api/v2  0.101s
+    ?     github.com/docker/distribution/registry/auth  [no test files]
+    ok    github.com/docker/distribution/registry/auth/silly  0.011s
+    ...
+    + /Users/sday/go/src/github.com/docker/distribution/bin/registry
+    + /Users/sday/go/src/github.com/docker/distribution/bin/registry-api-descriptor-template
+    + binaries
+
+The above provides a repeatable build using the contents of the vendored
+Godeps directory. This includes formatting, vetting, linting, building,
+testing and generating tagged binaries. We can verify this worked by running
+the registry binary generated in the "./bin" directory:
+
+    $ ./bin/registry -version
+    ./bin/registry github.com/docker/distribution v2.0.0-alpha.2-80-g16d8b2c.m
+
+### Optional build tags
+
+Optional [build tags](http://golang.org/pkg/go/build/) can be provided using
+the environment variable `DOCKER_BUILDTAGS`.

+ 35 - 0
vendor/src/github.com/docker/distribution/CHANGELOG.md

@@ -0,0 +1,35 @@
+# Changelog
+
+## 2.5.0 (2016-06-14)
+
+### Storage
+- Ensure uploads directory is cleaned after upload is commited
+- Add ability to cap concurrent operations in filesystem driver
+- S3: Add 'us-gov-west-1' to the valid region list
+- Swift: Handle ceph not returning Last-Modified header for HEAD requests
+- Add redirect middleware
+
+#### Registry
+- Add support for blobAccessController middleware
+- Add support for layers from foreign sources
+- Remove signature store
+- Add support for Let's Encrypt
+- Correct yaml key names in configuration
+
+#### Client
+- Add option to get content digest from manifest get
+
+#### Spec
+- Update the auth spec scope grammar to reflect the fact that hostnames are optionally supported
+- Clarify API documentation around catalog fetch behavior
+
+### API
+- Support returning HTTP 429 (Too Many Requests)
+
+### Documentation
+- Update auth documentation examples to show "expires in" as int
+
+### Docker Image
+- Use Alpine Linux as base image
+
+

+ 0 - 5
vendor/src/github.com/docker/distribution/MAINTAINERS

@@ -32,11 +32,6 @@
 	Email = "aaron.lehmann@docker.com"
 	Email = "aaron.lehmann@docker.com"
 	GitHub = "aaronlehmann"
 	GitHub = "aaronlehmann"
 
 
-	[people.brianbland]
-	Name = "Brian Bland"
-	Email = "brian.bland@docker.com"
-	GitHub = "BrianBland"
-
 	[people.dmcgowan]
 	[people.dmcgowan]
 	Name = "Derek McGowan"
 	Name = "Derek McGowan"
 	Email = "derek@mcgstyle.net"
 	Email = "derek@mcgstyle.net"

+ 1 - 1
vendor/src/github.com/docker/distribution/README.md

@@ -83,7 +83,7 @@ created. For more information see [docker/migrator]
 
 
 Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
 Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
 issues, fixes, and patches to this project. If you are contributing code, see
 issues, fixes, and patches to this project. If you are contributing code, see
-the instructions for [building a development environment](docs/building.md).
+the instructions for [building a development environment](docs/recipes/building.md).
 
 
 ## Support
 ## Support
 
 

+ 1 - 1
vendor/src/github.com/docker/distribution/ROADMAP.md

@@ -156,7 +156,7 @@ full and understand the problems behind deletes.
 While, at first glance, implementing deleting seems simple, there are a number
 While, at first glance, implementing deleting seems simple, there are a number
 mitigating factors that make many solutions not ideal or even pathological in
 mitigating factors that make many solutions not ideal or even pathological in
 the context of a registry. The following paragraph discuss the background and
 the context of a registry. The following paragraph discuss the background and
-approaches that could be applied to a arrive at a solution.
+approaches that could be applied to arrive at a solution.
 
 
 The goal of deletes in any system is to remove unused or unneeded data. Only
 The goal of deletes in any system is to remove unused or unneeded data. Only
 data requested for deletion should be removed and no other data. Removing
 data requested for deletion should be removed and no other data. Removing

+ 5 - 0
vendor/src/github.com/docker/distribution/blobs.go

@@ -127,6 +127,11 @@ type BlobDescriptorService interface {
 	Clear(ctx context.Context, dgst digest.Digest) error
 	Clear(ctx context.Context, dgst digest.Digest) error
 }
 }
 
 
+// BlobDescriptorServiceFactory creates middleware for BlobDescriptorService.
+type BlobDescriptorServiceFactory interface {
+	BlobAccessController(svc BlobDescriptorService) BlobDescriptorService
+}
+
 // ReadSeekCloser is the primary reader type for blob data, combining
 // ReadSeekCloser is the primary reader type for blob data, combining
 // io.ReadSeeker with io.Closer.
 // io.ReadSeeker with io.Closer.
 type ReadSeekCloser interface {
 type ReadSeekCloser interface {

+ 3 - 0
vendor/src/github.com/docker/distribution/manifest/schema2/builder.go

@@ -46,6 +46,9 @@ func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
 	m.Config, err = mb.bs.Stat(ctx, configDigest)
 	m.Config, err = mb.bs.Stat(ctx, configDigest)
 	switch err {
 	switch err {
 	case nil:
 	case nil:
+		// Override MediaType, since Put always replaces the specified media
+		// type with application/octet-stream in the descriptor it returns.
+		m.Config.MediaType = MediaTypeConfig
 		return FromStruct(m)
 		return FromStruct(m)
 	case distribution.ErrBlobUnknown:
 	case distribution.ErrBlobUnknown:
 		// nop
 		// nop

+ 0 - 6
vendor/src/github.com/docker/distribution/manifests.go

@@ -61,12 +61,6 @@ type ManifestEnumerator interface {
 	Enumerate(ctx context.Context, ingester func(digest.Digest) error) error
 	Enumerate(ctx context.Context, ingester func(digest.Digest) error) error
 }
 }
 
 
-// SignaturesGetter provides an interface for getting the signatures of a schema1 manifest. If the digest
-// referred to is not a schema1 manifest, an error should be returned.
-type SignaturesGetter interface {
-	GetSignatures(ctx context.Context, manifestDigest digest.Digest) ([]digest.Digest, error)
-}
-
 // Describable is an interface for descriptors
 // Describable is an interface for descriptors
 type Describable interface {
 type Describable interface {
 	Descriptor() Descriptor
 	Descriptor() Descriptor

+ 2 - 5
vendor/src/github.com/docker/distribution/registry/api/errcode/register.go

@@ -55,7 +55,7 @@ var (
 		HTTPStatusCode: http.StatusForbidden,
 		HTTPStatusCode: http.StatusForbidden,
 	})
 	})
 
 
-	// ErrorCodeUnavailable provides a common error to report unavialability
+	// ErrorCodeUnavailable provides a common error to report unavailability
 	// of a service or endpoint.
 	// of a service or endpoint.
 	ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
 	ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
 		Value:          "UNAVAILABLE",
 		Value:          "UNAVAILABLE",
@@ -71,10 +71,7 @@ var (
 		Message: "too many requests",
 		Message: "too many requests",
 		Description: `Returned when a client attempts to contact a
 		Description: `Returned when a client attempts to contact a
 		service too many times`,
 		service too many times`,
-		// FIXME: go1.5 doesn't export http.StatusTooManyRequests while
-		// go1.6 does. Update the hardcoded value to the constant once
-		// Docker updates golang version to 1.6.
-		HTTPStatusCode: 429,
+		HTTPStatusCode: http.StatusTooManyRequests,
 	})
 	})
 )
 )
 
 

+ 2 - 2
vendor/src/github.com/docker/distribution/registry/api/v2/descriptors.go

@@ -1497,8 +1497,8 @@ var routeDescriptors = []RouteDescriptor{
 				Description: "Retrieve a sorted, json list of repositories available in the registry.",
 				Description: "Retrieve a sorted, json list of repositories available in the registry.",
 				Requests: []RequestDescriptor{
 				Requests: []RequestDescriptor{
 					{
 					{
-						Name:        "Catalog Fetch Complete",
-						Description: "Request an unabridged list of repositories available.",
+						Name:        "Catalog Fetch",
+						Description: "Request an unabridged list of repositories available.  The implementation may impose a maximum limit and return a partial set with pagination links.",
 						Successes: []ResponseDescriptor{
 						Successes: []ResponseDescriptor{
 							{
 							{
 								Description: "Returns the unabridged list of repositories as a json response.",
 								Description: "Returns the unabridged list of repositories as a json response.",

+ 2 - 5
vendor/src/github.com/docker/distribution/registry/client/errors.go

@@ -11,7 +11,7 @@ import (
 	"github.com/docker/distribution/registry/api/errcode"
 	"github.com/docker/distribution/registry/api/errcode"
 )
 )
 
 
-// ErrNoErrorsInBody is returned when a HTTP response body parses to an empty
+// ErrNoErrorsInBody is returned when an HTTP response body parses to an empty
 // errcode.Errors slice.
 // errcode.Errors slice.
 var ErrNoErrorsInBody = errors.New("no error details found in HTTP response body")
 var ErrNoErrorsInBody = errors.New("no error details found in HTTP response body")
 
 
@@ -54,10 +54,7 @@ func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
 		switch statusCode {
 		switch statusCode {
 		case http.StatusUnauthorized:
 		case http.StatusUnauthorized:
 			return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details)
 			return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details)
-		// FIXME: go1.5 doesn't export http.StatusTooManyRequests while
-		// go1.6 does. Update the hardcoded value to the constant once
-		// Docker updates golang version to 1.6.
-		case 429:
+		case http.StatusTooManyRequests:
 			return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details)
 			return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details)
 		default:
 		default:
 			return errcode.ErrorCodeUnknown.WithMessage(detailsErr.Details)
 			return errcode.ErrorCodeUnknown.WithMessage(detailsErr.Details)

+ 47 - 16
vendor/src/github.com/docker/distribution/registry/client/repository.go

@@ -10,6 +10,7 @@ import (
 	"net/http"
 	"net/http"
 	"net/url"
 	"net/url"
 	"strconv"
 	"strconv"
+	"strings"
 	"time"
 	"time"
 
 
 	"github.com/docker/distribution"
 	"github.com/docker/distribution"
@@ -213,28 +214,35 @@ func (t *tags) All(ctx context.Context) ([]string, error) {
 		return tags, err
 		return tags, err
 	}
 	}
 
 
-	resp, err := t.client.Get(u)
-	if err != nil {
-		return tags, err
-	}
-	defer resp.Body.Close()
-
-	if SuccessStatus(resp.StatusCode) {
-		b, err := ioutil.ReadAll(resp.Body)
+	for {
+		resp, err := t.client.Get(u)
 		if err != nil {
 		if err != nil {
 			return tags, err
 			return tags, err
 		}
 		}
+		defer resp.Body.Close()
 
 
-		tagsResponse := struct {
-			Tags []string `json:"tags"`
-		}{}
-		if err := json.Unmarshal(b, &tagsResponse); err != nil {
-			return tags, err
+		if SuccessStatus(resp.StatusCode) {
+			b, err := ioutil.ReadAll(resp.Body)
+			if err != nil {
+				return tags, err
+			}
+
+			tagsResponse := struct {
+				Tags []string `json:"tags"`
+			}{}
+			if err := json.Unmarshal(b, &tagsResponse); err != nil {
+				return tags, err
+			}
+			tags = append(tags, tagsResponse.Tags...)
+			if link := resp.Header.Get("Link"); link != "" {
+				u = strings.Trim(strings.Split(link, ";")[0], "<>")
+			} else {
+				return tags, nil
+			}
+		} else {
+			return tags, HandleErrorResponse(resp)
 		}
 		}
-		tags = tagsResponse.Tags
-		return tags, nil
 	}
 	}
-	return tags, HandleErrorResponse(resp)
 }
 }
 
 
 func descriptorFromResponse(response *http.Response) (distribution.Descriptor, error) {
 func descriptorFromResponse(response *http.Response) (distribution.Descriptor, error) {
@@ -394,11 +402,26 @@ func (o etagOption) Apply(ms distribution.ManifestService) error {
 	return fmt.Errorf("etag options is a client-only option")
 	return fmt.Errorf("etag options is a client-only option")
 }
 }
 
 
+// ReturnContentDigest allows a client to set a the content digest on
+// a successful request from the 'Docker-Content-Digest' header. This
+// returned digest is represents the digest which the registry uses
+// to refer to the content and can be used to delete the content.
+func ReturnContentDigest(dgst *digest.Digest) distribution.ManifestServiceOption {
+	return contentDigestOption{dgst}
+}
+
+type contentDigestOption struct{ digest *digest.Digest }
+
+func (o contentDigestOption) Apply(ms distribution.ManifestService) error {
+	return nil
+}
+
 func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
 func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
 	var (
 	var (
 		digestOrTag string
 		digestOrTag string
 		ref         reference.Named
 		ref         reference.Named
 		err         error
 		err         error
+		contentDgst *digest.Digest
 	)
 	)
 
 
 	for _, option := range options {
 	for _, option := range options {
@@ -408,6 +431,8 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
 			if err != nil {
 			if err != nil {
 				return nil, err
 				return nil, err
 			}
 			}
+		} else if opt, ok := option.(contentDigestOption); ok {
+			contentDgst = opt.digest
 		} else {
 		} else {
 			err := option.Apply(ms)
 			err := option.Apply(ms)
 			if err != nil {
 			if err != nil {
@@ -450,6 +475,12 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis
 	if resp.StatusCode == http.StatusNotModified {
 	if resp.StatusCode == http.StatusNotModified {
 		return nil, distribution.ErrManifestNotModified
 		return nil, distribution.ErrManifestNotModified
 	} else if SuccessStatus(resp.StatusCode) {
 	} else if SuccessStatus(resp.StatusCode) {
+		if contentDgst != nil {
+			dgst, err := digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
+			if err == nil {
+				*contentDgst = dgst
+			}
+		}
 		mt := resp.Header.Get("Content-Type")
 		mt := resp.Header.Get("Content-Type")
 		body, err := ioutil.ReadAll(resp.Body)
 		body, err := ioutil.ReadAll(resp.Body)