Signed-off-by: Antonio Murdaca <runcom@redhat.com>
| ... | ... |
@@ -87,7 +87,7 @@ clone git github.com/boltdb/bolt v1.2.1 |
| 87 | 87 |
clone git github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7 |
| 88 | 88 |
|
| 89 | 89 |
# get graph and distribution packages |
| 90 |
-clone git github.com/docker/distribution 5bbf65499960b184fe8e0f045397375e1a6722b8 |
|
| 90 |
+clone git github.com/docker/distribution 4e17ab5d319ac5b70b2769442947567a83386fbc |
|
| 91 | 91 |
clone git github.com/vbatts/tar-split v0.9.11 |
| 92 | 92 |
|
| 93 | 93 |
# get go-zfs packages |
| ... | ... |
@@ -13,4 +13,6 @@ Sharif Nassar <sharif@mrwacky.com> Sharif Nassar <mrwacky42@users.noreply.github |
| 13 | 13 |
Sven Dowideit <SvenDowideit@home.org.au> Sven Dowideit <SvenDowideit@users.noreply.github.com> |
| 14 | 14 |
Vincent Giersch <vincent.giersch@ovh.net> Vincent Giersch <vincent@giersch.fr> |
| 15 | 15 |
davidli <wenquan.li@hp.com> davidli <wenquan.li@hpe.com> |
| 16 |
-Omer Cohen <git@omer.io> Omer Cohen <git@omerc.net> |
|
| 17 | 16 |
\ No newline at end of file |
| 17 |
+Omer Cohen <git@omer.io> Omer Cohen <git@omerc.net> |
|
| 18 |
+Eric Yang <windfarer@gmail.com> Eric Yang <Windfarer@users.noreply.github.com> |
|
| 19 |
+Nikita Tarasov <nikita@mygento.ru> Nikita <luckyraul@users.noreply.github.com> |
| ... | ... |
@@ -6,6 +6,8 @@ Adrian Mouat <adrian.mouat@gmail.com> |
| 6 | 6 |
Ahmet Alp Balkan <ahmetalpbalkan@gmail.com> |
| 7 | 7 |
Alex Chan <alex.chan@metaswitch.com> |
| 8 | 8 |
Alex Elman <aelman@indeed.com> |
| 9 |
+Alexey Gladkov <gladkov.alexey@gmail.com> |
|
| 10 |
+allencloud <allen.sun@daocloud.io> |
|
| 9 | 11 |
amitshukla <ashukla73@hotmail.com> |
| 10 | 12 |
Amy Lindburg <amy.lindburg@docker.com> |
| 11 | 13 |
Andrew Hsu <andrewhsu@acm.org> |
| ... | ... |
@@ -30,6 +32,7 @@ Brian Bland <brian.bland@docker.com> |
| 30 | 30 |
burnettk <burnettk@gmail.com> |
| 31 | 31 |
Carson A <ca@carsonoid.net> |
| 32 | 32 |
Chris Dillon <squarism@gmail.com> |
| 33 |
+cyli <cyli@twistedmatrix.com> |
|
| 33 | 34 |
Daisuke Fujita <dtanshi45@gmail.com> |
| 34 | 35 |
Daniel Huhn <daniel@danielhuhn.de> |
| 35 | 36 |
Darren Shepherd <darren@rancher.com> |
| ... | ... |
@@ -52,6 +55,7 @@ Felix Yan <felixonmars@archlinux.org> |
| 52 | 52 |
Florentin Raud <florentin.raud@gmail.com> |
| 53 | 53 |
Frederick F. Kautz IV <fkautz@alumni.cmu.edu> |
| 54 | 54 |
gabriell nascimento <gabriell@bluesoft.com.br> |
| 55 |
+Gleb Schukin <gschukin@ptsecurity.com> |
|
| 55 | 56 |
harche <p.harshal@gmail.com> |
| 56 | 57 |
Henri Gomez <henri.gomez@gmail.com> |
| 57 | 58 |
Hu Keping <hukeping@huawei.com> |
| ... | ... |
@@ -72,6 +76,7 @@ Jonathan Boulle <jonathanboulle@gmail.com> |
| 72 | 72 |
Jordan Liggitt <jliggitt@redhat.com> |
| 73 | 73 |
Josh Hawn <josh.hawn@docker.com> |
| 74 | 74 |
Julien Fernandez <julien.fernandez@gmail.com> |
| 75 |
+Ke Xu <leonhartx.k@gmail.com> |
|
| 75 | 76 |
Keerthan Mala <kmala@engineyard.com> |
| 76 | 77 |
Kelsey Hightower <kelsey.hightower@gmail.com> |
| 77 | 78 |
Kenneth Lim <kennethlimcp@gmail.com> |
| ... | ... |
@@ -94,6 +99,7 @@ moxiegirl <mary@docker.com> |
| 94 | 94 |
Nathan Sullivan <nathan@nightsys.net> |
| 95 | 95 |
nevermosby <robolwq@qq.com> |
| 96 | 96 |
Nghia Tran <tcnghia@gmail.com> |
| 97 |
+Nikita Tarasov <nikita@mygento.ru> |
|
| 97 | 98 |
Nuutti Kotivuori <nuutti.kotivuori@poplatek.fi> |
| 98 | 99 |
Oilbeater <liumengxinfly@gmail.com> |
| 99 | 100 |
Olivier Gambier <olivier@docker.com> |
| ... | ... |
@@ -137,4 +143,5 @@ xg.song <xg.song@venusource.com> |
| 137 | 137 |
xiekeyang <xiekeyang@huawei.com> |
| 138 | 138 |
Yann ROBERT <yann.robert@anantaplex.fr> |
| 139 | 139 |
yuzou <zouyu7@huawei.com> |
| 140 |
+zhouhaibing089 <zhouhaibing089@gmail.com> |
|
| 140 | 141 |
姜继忠 <jizhong.jiangjz@alibaba-inc.com> |
| 141 | 142 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,119 @@ |
| 0 |
+ |
|
| 1 |
+# Building the registry source |
|
| 2 |
+ |
|
| 3 |
+## Use-case |
|
| 4 |
+ |
|
| 5 |
+This is useful if you intend to actively work on the registry. |
|
| 6 |
+ |
|
| 7 |
+### Alternatives |
|
| 8 |
+ |
|
| 9 |
+Most people should use the [official Registry docker image](https://hub.docker.com/r/library/registry/). |
|
| 10 |
+ |
|
| 11 |
+People looking for advanced operational use cases might consider rolling their own image with a custom Dockerfile inheriting `FROM registry:2`. |
|
| 12 |
+ |
|
| 13 |
+OS X users who want to run natively can do so following [the instructions here](osx-setup-guide.md). |
|
| 14 |
+ |
|
| 15 |
+### Gotchas |
|
| 16 |
+ |
|
| 17 |
+You are expected to know your way around with go & git. |
|
| 18 |
+ |
|
| 19 |
+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. |
|
| 20 |
+ |
|
| 21 |
+## Build the development environment |
|
| 22 |
+ |
|
| 23 |
+The first prerequisite of properly building distribution targets is to have a Go |
|
| 24 |
+development environment setup. Please follow [How to Write Go Code](https://golang.org/doc/code.html) |
|
| 25 |
+for proper setup. If done correctly, you should have a GOROOT and GOPATH set in the |
|
| 26 |
+environment. |
|
| 27 |
+ |
|
| 28 |
+If a Go development environment is setup, one can use `go get` to install the |
|
| 29 |
+`registry` command from the current latest: |
|
| 30 |
+ |
|
| 31 |
+ go get github.com/docker/distribution/cmd/registry |
|
| 32 |
+ |
|
| 33 |
+The above will install the source repository into the `GOPATH`. |
|
| 34 |
+ |
|
| 35 |
+Now create the directory for the registry data (this might require you to set permissions properly) |
|
| 36 |
+ |
|
| 37 |
+ mkdir -p /var/lib/registry |
|
| 38 |
+ |
|
| 39 |
+... or alternatively `export REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/somewhere` if you want to store data into another location. |
|
| 40 |
+ |
|
| 41 |
+The `registry` |
|
| 42 |
+binary can then be run with the following: |
|
| 43 |
+ |
|
| 44 |
+ $ $GOPATH/bin/registry --version |
|
| 45 |
+ $GOPATH/bin/registry github.com/docker/distribution v2.0.0-alpha.1+unknown |
|
| 46 |
+ |
|
| 47 |
+> __NOTE:__ While you do not need to use `go get` to checkout the distribution |
|
| 48 |
+> project, for these build instructions to work, the project must be checked |
|
| 49 |
+> out in the correct location in the `GOPATH`. This should almost always be |
|
| 50 |
+> `$GOPATH/src/github.com/docker/distribution`. |
|
| 51 |
+ |
|
| 52 |
+The registry can be run with the default config using the following |
|
| 53 |
+incantation: |
|
| 54 |
+ |
|
| 55 |
+ $ $GOPATH/bin/registry serve $GOPATH/src/github.com/docker/distribution/cmd/registry/config-example.yml |
|
| 56 |
+ INFO[0000] endpoint local-5003 disabled, skipping app.id=34bbec38-a91a-494a-9a3f-b72f9010081f version=v2.0.0-alpha.1+unknown |
|
| 57 |
+ INFO[0000] endpoint local-8083 disabled, skipping app.id=34bbec38-a91a-494a-9a3f-b72f9010081f version=v2.0.0-alpha.1+unknown |
|
| 58 |
+ INFO[0000] listening on :5000 app.id=34bbec38-a91a-494a-9a3f-b72f9010081f version=v2.0.0-alpha.1+unknown |
|
| 59 |
+ INFO[0000] debug server listening localhost:5001 |
|
| 60 |
+ |
|
| 61 |
+If it is working, one should see the above log messages. |
|
| 62 |
+ |
|
| 63 |
+### Repeatable Builds |
|
| 64 |
+ |
|
| 65 |
+For the full development experience, one should `cd` into |
|
| 66 |
+`$GOPATH/src/github.com/docker/distribution`. From there, the regular `go` |
|
| 67 |
+commands, such as `go test`, should work per package (please see |
|
| 68 |
+[Developing](#developing) if they don't work). |
|
| 69 |
+ |
|
| 70 |
+A `Makefile` has been provided as a convenience to support repeatable builds. |
|
| 71 |
+Please install the following into `GOPATH` for it to work: |
|
| 72 |
+ |
|
| 73 |
+ go get github.com/tools/godep github.com/golang/lint/golint |
|
| 74 |
+ |
|
| 75 |
+**TODO(stevvooe):** Add a `make setup` command to Makefile to run this. Have to think about how to interact with Godeps properly. |
|
| 76 |
+ |
|
| 77 |
+Once these commands are available in the `GOPATH`, run `make` to get a full |
|
| 78 |
+build: |
|
| 79 |
+ |
|
| 80 |
+ $ make |
|
| 81 |
+ + clean |
|
| 82 |
+ + fmt |
|
| 83 |
+ + vet |
|
| 84 |
+ + lint |
|
| 85 |
+ + build |
|
| 86 |
+ github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar |
|
| 87 |
+ github.com/Sirupsen/logrus |
|
| 88 |
+ github.com/docker/libtrust |
|
| 89 |
+ ... |
|
| 90 |
+ github.com/yvasiyarov/gorelic |
|
| 91 |
+ github.com/docker/distribution/registry/handlers |
|
| 92 |
+ github.com/docker/distribution/cmd/registry |
|
| 93 |
+ + test |
|
| 94 |
+ ... |
|
| 95 |
+ ok github.com/docker/distribution/digest 7.875s |
|
| 96 |
+ ok github.com/docker/distribution/manifest 0.028s |
|
| 97 |
+ ok github.com/docker/distribution/notifications 17.322s |
|
| 98 |
+ ? github.com/docker/distribution/registry [no test files] |
|
| 99 |
+ ok github.com/docker/distribution/registry/api/v2 0.101s |
|
| 100 |
+ ? github.com/docker/distribution/registry/auth [no test files] |
|
| 101 |
+ ok github.com/docker/distribution/registry/auth/silly 0.011s |
|
| 102 |
+ ... |
|
| 103 |
+ + /Users/sday/go/src/github.com/docker/distribution/bin/registry |
|
| 104 |
+ + /Users/sday/go/src/github.com/docker/distribution/bin/registry-api-descriptor-template |
|
| 105 |
+ + binaries |
|
| 106 |
+ |
|
| 107 |
+The above provides a repeatable build using the contents of the vendored |
|
| 108 |
+Godeps directory. This includes formatting, vetting, linting, building, |
|
| 109 |
+testing and generating tagged binaries. We can verify this worked by running |
|
| 110 |
+the registry binary generated in the "./bin" directory: |
|
| 111 |
+ |
|
| 112 |
+ $ ./bin/registry -version |
|
| 113 |
+ ./bin/registry github.com/docker/distribution v2.0.0-alpha.2-80-g16d8b2c.m |
|
| 114 |
+ |
|
| 115 |
+### Optional build tags |
|
| 116 |
+ |
|
| 117 |
+Optional [build tags](http://golang.org/pkg/go/build/) can be provided using |
|
| 118 |
+the environment variable `DOCKER_BUILDTAGS`. |
| 0 | 119 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,35 @@ |
| 0 |
+# Changelog |
|
| 1 |
+ |
|
| 2 |
+## 2.5.0 (2016-06-14) |
|
| 3 |
+ |
|
| 4 |
+### Storage |
|
| 5 |
+- Ensure uploads directory is cleaned after upload is commited |
|
| 6 |
+- Add ability to cap concurrent operations in filesystem driver |
|
| 7 |
+- S3: Add 'us-gov-west-1' to the valid region list |
|
| 8 |
+- Swift: Handle ceph not returning Last-Modified header for HEAD requests |
|
| 9 |
+- Add redirect middleware |
|
| 10 |
+ |
|
| 11 |
+#### Registry |
|
| 12 |
+- Add support for blobAccessController middleware |
|
| 13 |
+- Add support for layers from foreign sources |
|
| 14 |
+- Remove signature store |
|
| 15 |
+- Add support for Let's Encrypt |
|
| 16 |
+- Correct yaml key names in configuration |
|
| 17 |
+ |
|
| 18 |
+#### Client |
|
| 19 |
+- Add option to get content digest from manifest get |
|
| 20 |
+ |
|
| 21 |
+#### Spec |
|
| 22 |
+- Update the auth spec scope grammar to reflect the fact that hostnames are optionally supported |
|
| 23 |
+- Clarify API documentation around catalog fetch behavior |
|
| 24 |
+ |
|
| 25 |
+### API |
|
| 26 |
+- Support returning HTTP 429 (Too Many Requests) |
|
| 27 |
+ |
|
| 28 |
+### Documentation |
|
| 29 |
+- Update auth documentation examples to show "expires in" as int |
|
| 30 |
+ |
|
| 31 |
+### Docker Image |
|
| 32 |
+- Use Alpine Linux as base image |
|
| 33 |
+ |
|
| 34 |
+ |
| ... | ... |
@@ -32,11 +32,6 @@ |
| 32 | 32 |
Email = "aaron.lehmann@docker.com" |
| 33 | 33 |
GitHub = "aaronlehmann" |
| 34 | 34 |
|
| 35 |
- [people.brianbland] |
|
| 36 |
- Name = "Brian Bland" |
|
| 37 |
- Email = "brian.bland@docker.com" |
|
| 38 |
- GitHub = "BrianBland" |
|
| 39 |
- |
|
| 40 | 35 |
[people.dmcgowan] |
| 41 | 36 |
Name = "Derek McGowan" |
| 42 | 37 |
Email = "derek@mcgstyle.net" |
| ... | ... |
@@ -83,7 +83,7 @@ created. For more information see [docker/migrator] |
| 83 | 83 |
|
| 84 | 84 |
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute |
| 85 | 85 |
issues, fixes, and patches to this project. If you are contributing code, see |
| 86 |
-the instructions for [building a development environment](docs/building.md). |
|
| 86 |
+the instructions for [building a development environment](docs/recipes/building.md). |
|
| 87 | 87 |
|
| 88 | 88 |
## Support |
| 89 | 89 |
|
| ... | ... |
@@ -156,7 +156,7 @@ full and understand the problems behind deletes. |
| 156 | 156 |
While, at first glance, implementing deleting seems simple, there are a number |
| 157 | 157 |
mitigating factors that make many solutions not ideal or even pathological in |
| 158 | 158 |
the context of a registry. The following paragraph discuss the background and |
| 159 |
-approaches that could be applied to a arrive at a solution. |
|
| 159 |
+approaches that could be applied to arrive at a solution. |
|
| 160 | 160 |
|
| 161 | 161 |
The goal of deletes in any system is to remove unused or unneeded data. Only |
| 162 | 162 |
data requested for deletion should be removed and no other data. Removing |
| ... | ... |
@@ -127,6 +127,11 @@ type BlobDescriptorService interface {
|
| 127 | 127 |
Clear(ctx context.Context, dgst digest.Digest) error |
| 128 | 128 |
} |
| 129 | 129 |
|
| 130 |
+// BlobDescriptorServiceFactory creates middleware for BlobDescriptorService. |
|
| 131 |
+type BlobDescriptorServiceFactory interface {
|
|
| 132 |
+ BlobAccessController(svc BlobDescriptorService) BlobDescriptorService |
|
| 133 |
+} |
|
| 134 |
+ |
|
| 130 | 135 |
// ReadSeekCloser is the primary reader type for blob data, combining |
| 131 | 136 |
// io.ReadSeeker with io.Closer. |
| 132 | 137 |
type ReadSeekCloser interface {
|
| ... | ... |
@@ -46,6 +46,9 @@ func (mb *builder) Build(ctx context.Context) (distribution.Manifest, error) {
|
| 46 | 46 |
m.Config, err = mb.bs.Stat(ctx, configDigest) |
| 47 | 47 |
switch err {
|
| 48 | 48 |
case nil: |
| 49 |
+ // Override MediaType, since Put always replaces the specified media |
|
| 50 |
+ // type with application/octet-stream in the descriptor it returns. |
|
| 51 |
+ m.Config.MediaType = MediaTypeConfig |
|
| 49 | 52 |
return FromStruct(m) |
| 50 | 53 |
case distribution.ErrBlobUnknown: |
| 51 | 54 |
// nop |
| ... | ... |
@@ -61,12 +61,6 @@ type ManifestEnumerator interface {
|
| 61 | 61 |
Enumerate(ctx context.Context, ingester func(digest.Digest) error) error |
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 |
-// SignaturesGetter provides an interface for getting the signatures of a schema1 manifest. If the digest |
|
| 65 |
-// referred to is not a schema1 manifest, an error should be returned. |
|
| 66 |
-type SignaturesGetter interface {
|
|
| 67 |
- GetSignatures(ctx context.Context, manifestDigest digest.Digest) ([]digest.Digest, error) |
|
| 68 |
-} |
|
| 69 |
- |
|
| 70 | 64 |
// Describable is an interface for descriptors |
| 71 | 65 |
type Describable interface {
|
| 72 | 66 |
Descriptor() Descriptor |
| ... | ... |
@@ -55,7 +55,7 @@ var ( |
| 55 | 55 |
HTTPStatusCode: http.StatusForbidden, |
| 56 | 56 |
}) |
| 57 | 57 |
|
| 58 |
- // ErrorCodeUnavailable provides a common error to report unavialability |
|
| 58 |
+ // ErrorCodeUnavailable provides a common error to report unavailability |
|
| 59 | 59 |
// of a service or endpoint. |
| 60 | 60 |
ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
|
| 61 | 61 |
Value: "UNAVAILABLE", |
| ... | ... |
@@ -71,10 +71,7 @@ var ( |
| 71 | 71 |
Message: "too many requests", |
| 72 | 72 |
Description: `Returned when a client attempts to contact a |
| 73 | 73 |
service too many times`, |
| 74 |
- // FIXME: go1.5 doesn't export http.StatusTooManyRequests while |
|
| 75 |
- // go1.6 does. Update the hardcoded value to the constant once |
|
| 76 |
- // Docker updates golang version to 1.6. |
|
| 77 |
- HTTPStatusCode: 429, |
|
| 74 |
+ HTTPStatusCode: http.StatusTooManyRequests, |
|
| 78 | 75 |
}) |
| 79 | 76 |
) |
| 80 | 77 |
|
| ... | ... |
@@ -1497,8 +1497,8 @@ var routeDescriptors = []RouteDescriptor{
|
| 1497 | 1497 |
Description: "Retrieve a sorted, json list of repositories available in the registry.", |
| 1498 | 1498 |
Requests: []RequestDescriptor{
|
| 1499 | 1499 |
{
|
| 1500 |
- Name: "Catalog Fetch Complete", |
|
| 1501 |
- Description: "Request an unabridged list of repositories available.", |
|
| 1500 |
+ Name: "Catalog Fetch", |
|
| 1501 |
+ Description: "Request an unabridged list of repositories available. The implementation may impose a maximum limit and return a partial set with pagination links.", |
|
| 1502 | 1502 |
Successes: []ResponseDescriptor{
|
| 1503 | 1503 |
{
|
| 1504 | 1504 |
Description: "Returns the unabridged list of repositories as a json response.", |
| ... | ... |
@@ -11,7 +11,7 @@ import ( |
| 11 | 11 |
"github.com/docker/distribution/registry/api/errcode" |
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 |
-// ErrNoErrorsInBody is returned when a HTTP response body parses to an empty |
|
| 14 |
+// ErrNoErrorsInBody is returned when an HTTP response body parses to an empty |
|
| 15 | 15 |
// errcode.Errors slice. |
| 16 | 16 |
var ErrNoErrorsInBody = errors.New("no error details found in HTTP response body")
|
| 17 | 17 |
|
| ... | ... |
@@ -54,10 +54,7 @@ func parseHTTPErrorResponse(statusCode int, r io.Reader) error {
|
| 54 | 54 |
switch statusCode {
|
| 55 | 55 |
case http.StatusUnauthorized: |
| 56 | 56 |
return errcode.ErrorCodeUnauthorized.WithMessage(detailsErr.Details) |
| 57 |
- // FIXME: go1.5 doesn't export http.StatusTooManyRequests while |
|
| 58 |
- // go1.6 does. Update the hardcoded value to the constant once |
|
| 59 |
- // Docker updates golang version to 1.6. |
|
| 60 |
- case 429: |
|
| 57 |
+ case http.StatusTooManyRequests: |
|
| 61 | 58 |
return errcode.ErrorCodeTooManyRequests.WithMessage(detailsErr.Details) |
| 62 | 59 |
default: |
| 63 | 60 |
return errcode.ErrorCodeUnknown.WithMessage(detailsErr.Details) |
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
"net/http" |
| 11 | 11 |
"net/url" |
| 12 | 12 |
"strconv" |
| 13 |
+ "strings" |
|
| 13 | 14 |
"time" |
| 14 | 15 |
|
| 15 | 16 |
"github.com/docker/distribution" |
| ... | ... |
@@ -213,28 +214,35 @@ func (t *tags) All(ctx context.Context) ([]string, error) {
|
| 213 | 213 |
return tags, err |
| 214 | 214 |
} |
| 215 | 215 |
|
| 216 |
- resp, err := t.client.Get(u) |
|
| 217 |
- if err != nil {
|
|
| 218 |
- return tags, err |
|
| 219 |
- } |
|
| 220 |
- defer resp.Body.Close() |
|
| 221 |
- |
|
| 222 |
- if SuccessStatus(resp.StatusCode) {
|
|
| 223 |
- b, err := ioutil.ReadAll(resp.Body) |
|
| 216 |
+ for {
|
|
| 217 |
+ resp, err := t.client.Get(u) |
|
| 224 | 218 |
if err != nil {
|
| 225 | 219 |
return tags, err |
| 226 | 220 |
} |
| 221 |
+ defer resp.Body.Close() |
|
| 227 | 222 |
|
| 228 |
- tagsResponse := struct {
|
|
| 229 |
- Tags []string `json:"tags"` |
|
| 230 |
- }{}
|
|
| 231 |
- if err := json.Unmarshal(b, &tagsResponse); err != nil {
|
|
| 232 |
- return tags, err |
|
| 223 |
+ if SuccessStatus(resp.StatusCode) {
|
|
| 224 |
+ b, err := ioutil.ReadAll(resp.Body) |
|
| 225 |
+ if err != nil {
|
|
| 226 |
+ return tags, err |
|
| 227 |
+ } |
|
| 228 |
+ |
|
| 229 |
+ tagsResponse := struct {
|
|
| 230 |
+ Tags []string `json:"tags"` |
|
| 231 |
+ }{}
|
|
| 232 |
+ if err := json.Unmarshal(b, &tagsResponse); err != nil {
|
|
| 233 |
+ return tags, err |
|
| 234 |
+ } |
|
| 235 |
+ tags = append(tags, tagsResponse.Tags...) |
|
| 236 |
+ if link := resp.Header.Get("Link"); link != "" {
|
|
| 237 |
+ u = strings.Trim(strings.Split(link, ";")[0], "<>") |
|
| 238 |
+ } else {
|
|
| 239 |
+ return tags, nil |
|
| 240 |
+ } |
|
| 241 |
+ } else {
|
|
| 242 |
+ return tags, HandleErrorResponse(resp) |
|
| 233 | 243 |
} |
| 234 |
- tags = tagsResponse.Tags |
|
| 235 |
- return tags, nil |
|
| 236 | 244 |
} |
| 237 |
- return tags, HandleErrorResponse(resp) |
|
| 238 | 245 |
} |
| 239 | 246 |
|
| 240 | 247 |
func descriptorFromResponse(response *http.Response) (distribution.Descriptor, error) {
|
| ... | ... |
@@ -394,11 +402,26 @@ func (o etagOption) Apply(ms distribution.ManifestService) error {
|
| 394 | 394 |
return fmt.Errorf("etag options is a client-only option")
|
| 395 | 395 |
} |
| 396 | 396 |
|
| 397 |
+// ReturnContentDigest allows a client to set a the content digest on |
|
| 398 |
+// a successful request from the 'Docker-Content-Digest' header. This |
|
| 399 |
+// returned digest is represents the digest which the registry uses |
|
| 400 |
+// to refer to the content and can be used to delete the content. |
|
| 401 |
+func ReturnContentDigest(dgst *digest.Digest) distribution.ManifestServiceOption {
|
|
| 402 |
+ return contentDigestOption{dgst}
|
|
| 403 |
+} |
|
| 404 |
+ |
|
| 405 |
+type contentDigestOption struct{ digest *digest.Digest }
|
|
| 406 |
+ |
|
| 407 |
+func (o contentDigestOption) Apply(ms distribution.ManifestService) error {
|
|
| 408 |
+ return nil |
|
| 409 |
+} |
|
| 410 |
+ |
|
| 397 | 411 |
func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) {
|
| 398 | 412 |
var ( |
| 399 | 413 |
digestOrTag string |
| 400 | 414 |
ref reference.Named |
| 401 | 415 |
err error |
| 416 |
+ contentDgst *digest.Digest |
|
| 402 | 417 |
) |
| 403 | 418 |
|
| 404 | 419 |
for _, option := range options {
|
| ... | ... |
@@ -408,6 +431,8 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis |
| 408 | 408 |
if err != nil {
|
| 409 | 409 |
return nil, err |
| 410 | 410 |
} |
| 411 |
+ } else if opt, ok := option.(contentDigestOption); ok {
|
|
| 412 |
+ contentDgst = opt.digest |
|
| 411 | 413 |
} else {
|
| 412 | 414 |
err := option.Apply(ms) |
| 413 | 415 |
if err != nil {
|
| ... | ... |
@@ -450,6 +475,12 @@ func (ms *manifests) Get(ctx context.Context, dgst digest.Digest, options ...dis |
| 450 | 450 |
if resp.StatusCode == http.StatusNotModified {
|
| 451 | 451 |
return nil, distribution.ErrManifestNotModified |
| 452 | 452 |
} else if SuccessStatus(resp.StatusCode) {
|
| 453 |
+ if contentDgst != nil {
|
|
| 454 |
+ dgst, err := digest.ParseDigest(resp.Header.Get("Docker-Content-Digest"))
|
|
| 455 |
+ if err == nil {
|
|
| 456 |
+ *contentDgst = dgst |
|
| 457 |
+ } |
|
| 458 |
+ } |
|
| 453 | 459 |
mt := resp.Header.Get("Content-Type")
|
| 454 | 460 |
body, err := ioutil.ReadAll(resp.Body) |
| 455 | 461 |
|