The "reference" package was moved to a separate module, which was extracted
from https://github.com/distribution/distribution/commit/b9b19409cf458dcb9e1253ff44ba75bd0620faa6
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -3,8 +3,8 @@ package distribution // import "github.com/docker/docker/api/server/router/distr |
| 3 | 3 |
import ( |
| 4 | 4 |
"context" |
| 5 | 5 |
|
| 6 |
+ "github.com/distribution/reference" |
|
| 6 | 7 |
"github.com/docker/distribution" |
| 7 |
- "github.com/docker/distribution/reference" |
|
| 8 | 8 |
"github.com/docker/docker/api/types/registry" |
| 9 | 9 |
) |
| 10 | 10 |
|
| ... | ... |
@@ -5,10 +5,10 @@ import ( |
| 5 | 5 |
"encoding/json" |
| 6 | 6 |
"net/http" |
| 7 | 7 |
|
| 8 |
+ "github.com/distribution/reference" |
|
| 8 | 9 |
"github.com/docker/distribution/manifest/manifestlist" |
| 9 | 10 |
"github.com/docker/distribution/manifest/schema1" |
| 10 | 11 |
"github.com/docker/distribution/manifest/schema2" |
| 11 |
- "github.com/docker/distribution/reference" |
|
| 12 | 12 |
"github.com/docker/docker/api/server/httputils" |
| 13 | 13 |
"github.com/docker/docker/api/types/registry" |
| 14 | 14 |
"github.com/docker/docker/errdefs" |
| ... | ... |
@@ -10,7 +10,7 @@ import ( |
| 10 | 10 |
"time" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/containerd/containerd/platforms" |
| 13 |
- "github.com/docker/distribution/reference" |
|
| 13 |
+ "github.com/distribution/reference" |
|
| 14 | 14 |
"github.com/docker/docker/api/server/httputils" |
| 15 | 15 |
"github.com/docker/docker/api/types" |
| 16 | 16 |
"github.com/docker/docker/api/types/filters" |
| ... | ... |
@@ -20,7 +20,7 @@ import ( |
| 20 | 20 |
"github.com/containerd/containerd/remotes" |
| 21 | 21 |
"github.com/containerd/containerd/remotes/docker" |
| 22 | 22 |
"github.com/containerd/containerd/remotes/docker/schema1" |
| 23 |
- distreference "github.com/docker/distribution/reference" |
|
| 23 |
+ distreference "github.com/distribution/reference" |
|
| 24 | 24 |
dimages "github.com/docker/docker/daemon/images" |
| 25 | 25 |
"github.com/docker/docker/distribution/metadata" |
| 26 | 26 |
"github.com/docker/docker/distribution/xfer" |
| ... | ... |
@@ -8,7 +8,7 @@ import ( |
| 8 | 8 |
"github.com/containerd/containerd/content" |
| 9 | 9 |
"github.com/containerd/containerd/images" |
| 10 | 10 |
"github.com/containerd/containerd/remotes/docker" |
| 11 |
- distreference "github.com/docker/distribution/reference" |
|
| 11 |
+ distreference "github.com/distribution/reference" |
|
| 12 | 12 |
imagestore "github.com/docker/docker/image" |
| 13 | 13 |
"github.com/docker/docker/reference" |
| 14 | 14 |
"github.com/moby/buildkit/cache/remotecache" |
| ... | ... |
@@ -6,7 +6,7 @@ import ( |
| 6 | 6 |
"net/http" |
| 7 | 7 |
|
| 8 | 8 |
"github.com/containerd/containerd/log" |
| 9 |
- "github.com/docker/distribution/reference" |
|
| 9 |
+ "github.com/distribution/reference" |
|
| 10 | 10 |
"github.com/docker/docker/api/types" |
| 11 | 11 |
"github.com/docker/docker/api/types/registry" |
| 12 | 12 |
"github.com/docker/docker/api/types/swarm/runtime" |
| ... | ... |
@@ -9,7 +9,7 @@ import ( |
| 9 | 9 |
"testing" |
| 10 | 10 |
"time" |
| 11 | 11 |
|
| 12 |
- "github.com/docker/distribution/reference" |
|
| 12 |
+ "github.com/distribution/reference" |
|
| 13 | 13 |
"github.com/docker/docker/api/types" |
| 14 | 14 |
"github.com/docker/docker/api/types/registry" |
| 15 | 15 |
"github.com/docker/docker/api/types/swarm/runtime" |
| ... | ... |
@@ -5,8 +5,8 @@ import ( |
| 5 | 5 |
"io" |
| 6 | 6 |
"time" |
| 7 | 7 |
|
| 8 |
+ "github.com/distribution/reference" |
|
| 8 | 9 |
"github.com/docker/distribution" |
| 9 |
- "github.com/docker/distribution/reference" |
|
| 10 | 10 |
"github.com/docker/docker/api/types" |
| 11 | 11 |
"github.com/docker/docker/api/types/backend" |
| 12 | 12 |
"github.com/docker/docker/api/types/container" |
| ... | ... |
@@ -12,7 +12,7 @@ import ( |
| 12 | 12 |
"time" |
| 13 | 13 |
|
| 14 | 14 |
"github.com/containerd/containerd/log" |
| 15 |
- "github.com/docker/distribution/reference" |
|
| 15 |
+ "github.com/distribution/reference" |
|
| 16 | 16 |
"github.com/docker/docker/api/types" |
| 17 | 17 |
"github.com/docker/docker/api/types/backend" |
| 18 | 18 |
containertypes "github.com/docker/docker/api/types/container" |
| ... | ... |
@@ -9,7 +9,7 @@ import ( |
| 9 | 9 |
"strings" |
| 10 | 10 |
|
| 11 | 11 |
"github.com/containerd/containerd/log" |
| 12 |
- "github.com/docker/distribution/reference" |
|
| 12 |
+ "github.com/distribution/reference" |
|
| 13 | 13 |
"github.com/docker/docker/api/types" |
| 14 | 14 |
enginecontainer "github.com/docker/docker/api/types/container" |
| 15 | 15 |
"github.com/docker/docker/api/types/events" |
| ... | ... |
@@ -12,7 +12,7 @@ import ( |
| 12 | 12 |
"time" |
| 13 | 13 |
|
| 14 | 14 |
"github.com/containerd/containerd/log" |
| 15 |
- "github.com/docker/distribution/reference" |
|
| 15 |
+ "github.com/distribution/reference" |
|
| 16 | 16 |
"github.com/docker/docker/api/types" |
| 17 | 17 |
"github.com/docker/docker/api/types/backend" |
| 18 | 18 |
"github.com/docker/docker/api/types/registry" |
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
"strings" |
| 8 | 8 |
"time" |
| 9 | 9 |
|
| 10 |
- "github.com/docker/distribution/reference" |
|
| 10 |
+ "github.com/distribution/reference" |
|
| 11 | 11 |
"github.com/docker/docker/api/types/backend" |
| 12 | 12 |
containertypes "github.com/docker/docker/api/types/container" |
| 13 | 13 |
"github.com/docker/docker/api/types/events" |
| ... | ... |
@@ -13,7 +13,7 @@ import ( |
| 13 | 13 |
containerdimages "github.com/containerd/containerd/images" |
| 14 | 14 |
"github.com/containerd/containerd/log" |
| 15 | 15 |
cplatforms "github.com/containerd/containerd/platforms" |
| 16 |
- "github.com/docker/distribution/reference" |
|
| 16 |
+ "github.com/distribution/reference" |
|
| 17 | 17 |
imagetype "github.com/docker/docker/api/types/image" |
| 18 | 18 |
"github.com/docker/docker/daemon/images" |
| 19 | 19 |
"github.com/docker/docker/errdefs" |
| ... | ... |
@@ -14,7 +14,7 @@ import ( |
| 14 | 14 |
"github.com/containerd/containerd/mount" |
| 15 | 15 |
"github.com/containerd/containerd/platforms" |
| 16 | 16 |
"github.com/containerd/containerd/rootfs" |
| 17 |
- "github.com/docker/distribution/reference" |
|
| 17 |
+ "github.com/distribution/reference" |
|
| 18 | 18 |
"github.com/docker/docker/api/types/backend" |
| 19 | 19 |
imagetypes "github.com/docker/docker/api/types/image" |
| 20 | 20 |
"github.com/docker/docker/api/types/registry" |
| ... | ... |
@@ -8,7 +8,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
"github.com/containerd/containerd/images" |
| 10 | 10 |
"github.com/containerd/containerd/log" |
| 11 |
- "github.com/docker/distribution/reference" |
|
| 11 |
+ "github.com/distribution/reference" |
|
| 12 | 12 |
"github.com/docker/docker/api/types" |
| 13 | 13 |
"github.com/docker/docker/api/types/events" |
| 14 | 14 |
"github.com/docker/docker/container" |
| ... | ... |
@@ -13,7 +13,7 @@ import ( |
| 13 | 13 |
"github.com/containerd/containerd/leases" |
| 14 | 14 |
"github.com/containerd/containerd/log" |
| 15 | 15 |
cplatforms "github.com/containerd/containerd/platforms" |
| 16 |
- "github.com/docker/distribution/reference" |
|
| 16 |
+ "github.com/distribution/reference" |
|
| 17 | 17 |
"github.com/docker/docker/api/types/events" |
| 18 | 18 |
"github.com/docker/docker/container" |
| 19 | 19 |
"github.com/docker/docker/errdefs" |
| ... | ... |
@@ -5,7 +5,7 @@ import ( |
| 5 | 5 |
"sort" |
| 6 | 6 |
|
| 7 | 7 |
cplatforms "github.com/containerd/containerd/platforms" |
| 8 |
- "github.com/docker/distribution/reference" |
|
| 8 |
+ "github.com/distribution/reference" |
|
| 9 | 9 |
imagetype "github.com/docker/docker/api/types/image" |
| 10 | 10 |
"github.com/docker/docker/errdefs" |
| 11 | 11 |
"github.com/docker/docker/pkg/platforms" |
| ... | ... |
@@ -14,7 +14,7 @@ import ( |
| 14 | 14 |
"github.com/containerd/containerd/images" |
| 15 | 15 |
"github.com/containerd/containerd/log" |
| 16 | 16 |
"github.com/containerd/containerd/platforms" |
| 17 |
- "github.com/docker/distribution/reference" |
|
| 17 |
+ "github.com/distribution/reference" |
|
| 18 | 18 |
"github.com/docker/docker/api/types/container" |
| 19 | 19 |
"github.com/docker/docker/api/types/events" |
| 20 | 20 |
"github.com/docker/docker/builder/dockerfile" |
| ... | ... |
@@ -13,7 +13,7 @@ import ( |
| 13 | 13 |
"github.com/containerd/containerd/labels" |
| 14 | 14 |
"github.com/containerd/containerd/log" |
| 15 | 15 |
"github.com/containerd/containerd/snapshots" |
| 16 |
- "github.com/docker/distribution/reference" |
|
| 16 |
+ "github.com/distribution/reference" |
|
| 17 | 17 |
"github.com/docker/docker/api/types" |
| 18 | 18 |
"github.com/docker/docker/api/types/filters" |
| 19 | 19 |
"github.com/docker/docker/api/types/image" |
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
cerrdefs "github.com/containerd/containerd/errdefs" |
| 8 | 8 |
containerdimages "github.com/containerd/containerd/images" |
| 9 | 9 |
"github.com/containerd/containerd/log" |
| 10 |
- "github.com/docker/distribution/reference" |
|
| 10 |
+ "github.com/distribution/reference" |
|
| 11 | 11 |
"github.com/docker/docker/api/types" |
| 12 | 12 |
"github.com/docker/docker/api/types/filters" |
| 13 | 13 |
"github.com/docker/docker/errdefs" |
| ... | ... |
@@ -10,7 +10,7 @@ import ( |
| 10 | 10 |
"github.com/containerd/containerd/log" |
| 11 | 11 |
"github.com/containerd/containerd/pkg/snapshotters" |
| 12 | 12 |
"github.com/containerd/containerd/platforms" |
| 13 |
- "github.com/docker/distribution/reference" |
|
| 13 |
+ "github.com/distribution/reference" |
|
| 14 | 14 |
"github.com/docker/docker/api/types/registry" |
| 15 | 15 |
"github.com/docker/docker/errdefs" |
| 16 | 16 |
"github.com/docker/docker/pkg/streamformatter" |
| ... | ... |
@@ -15,7 +15,7 @@ import ( |
| 15 | 15 |
"github.com/containerd/containerd/platforms" |
| 16 | 16 |
"github.com/containerd/containerd/remotes" |
| 17 | 17 |
"github.com/containerd/containerd/remotes/docker" |
| 18 |
- "github.com/docker/distribution/reference" |
|
| 18 |
+ "github.com/distribution/reference" |
|
| 19 | 19 |
"github.com/docker/docker/api/types/registry" |
| 20 | 20 |
"github.com/docker/docker/errdefs" |
| 21 | 21 |
"github.com/docker/docker/pkg/progress" |
| ... | ... |
@@ -6,7 +6,7 @@ import ( |
| 6 | 6 |
cerrdefs "github.com/containerd/containerd/errdefs" |
| 7 | 7 |
containerdimages "github.com/containerd/containerd/images" |
| 8 | 8 |
"github.com/containerd/containerd/log" |
| 9 |
- "github.com/docker/distribution/reference" |
|
| 9 |
+ "github.com/distribution/reference" |
|
| 10 | 10 |
"github.com/docker/docker/api/types/events" |
| 11 | 11 |
"github.com/docker/docker/errdefs" |
| 12 | 12 |
"github.com/docker/docker/image" |
| ... | ... |
@@ -11,7 +11,7 @@ import ( |
| 11 | 11 |
"github.com/containerd/containerd/plugin" |
| 12 | 12 |
"github.com/containerd/containerd/remotes/docker" |
| 13 | 13 |
"github.com/containerd/containerd/snapshots" |
| 14 |
- "github.com/docker/distribution/reference" |
|
| 14 |
+ "github.com/distribution/reference" |
|
| 15 | 15 |
"github.com/docker/docker/container" |
| 16 | 16 |
daemonevents "github.com/docker/docker/daemon/events" |
| 17 | 17 |
"github.com/docker/docker/daemon/images" |
| ... | ... |
@@ -5,7 +5,7 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
"github.com/containerd/containerd/content" |
| 7 | 7 |
cerrdefs "github.com/containerd/containerd/errdefs" |
| 8 |
- "github.com/docker/distribution/reference" |
|
| 8 |
+ "github.com/distribution/reference" |
|
| 9 | 9 |
"github.com/opencontainers/go-digest" |
| 10 | 10 |
ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| 11 | 11 |
) |
| ... | ... |
@@ -25,8 +25,8 @@ import ( |
| 25 | 25 |
"github.com/containerd/containerd/pkg/dialer" |
| 26 | 26 |
"github.com/containerd/containerd/pkg/userns" |
| 27 | 27 |
"github.com/containerd/containerd/remotes/docker" |
| 28 |
+ "github.com/distribution/reference" |
|
| 28 | 29 |
dist "github.com/docker/distribution" |
| 29 |
- "github.com/docker/distribution/reference" |
|
| 30 | 30 |
"github.com/docker/docker/api/types" |
| 31 | 31 |
containertypes "github.com/docker/docker/api/types/container" |
| 32 | 32 |
registrytypes "github.com/docker/docker/api/types/registry" |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
package events // import "github.com/docker/docker/daemon/events" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "github.com/docker/distribution/reference" |
|
| 4 |
+ "github.com/distribution/reference" |
|
| 5 | 5 |
"github.com/docker/docker/api/types/events" |
| 6 | 6 |
"github.com/docker/docker/api/types/filters" |
| 7 | 7 |
) |
| ... | ... |
@@ -12,7 +12,7 @@ import ( |
| 12 | 12 |
"github.com/containerd/containerd/leases" |
| 13 | 13 |
"github.com/containerd/containerd/log" |
| 14 | 14 |
"github.com/containerd/containerd/platforms" |
| 15 |
- "github.com/docker/distribution/reference" |
|
| 15 |
+ "github.com/distribution/reference" |
|
| 16 | 16 |
imagetypes "github.com/docker/docker/api/types/image" |
| 17 | 17 |
"github.com/docker/docker/errdefs" |
| 18 | 18 |
"github.com/docker/docker/image" |
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/containerd/containerd/log" |
| 9 | 9 |
"github.com/containerd/containerd/platforms" |
| 10 |
- "github.com/docker/distribution/reference" |
|
| 10 |
+ "github.com/distribution/reference" |
|
| 11 | 11 |
"github.com/docker/docker/api/types/backend" |
| 12 | 12 |
imagetypes "github.com/docker/docker/api/types/image" |
| 13 | 13 |
"github.com/docker/docker/api/types/registry" |
| ... | ... |
@@ -6,7 +6,7 @@ import ( |
| 6 | 6 |
"strings" |
| 7 | 7 |
"time" |
| 8 | 8 |
|
| 9 |
- "github.com/docker/distribution/reference" |
|
| 9 |
+ "github.com/distribution/reference" |
|
| 10 | 10 |
"github.com/docker/docker/api/types" |
| 11 | 11 |
"github.com/docker/docker/api/types/events" |
| 12 | 12 |
imagetypes "github.com/docker/docker/api/types/image" |
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
"time" |
| 8 | 8 |
|
| 9 | 9 |
"github.com/containerd/containerd/platforms" |
| 10 |
- "github.com/docker/distribution/reference" |
|
| 10 |
+ "github.com/distribution/reference" |
|
| 11 | 11 |
"github.com/docker/docker/api/types/container" |
| 12 | 12 |
"github.com/docker/docker/api/types/events" |
| 13 | 13 |
"github.com/docker/docker/builder/dockerfile" |
| ... | ... |
@@ -8,7 +8,7 @@ import ( |
| 8 | 8 |
"time" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/containerd/containerd/log" |
| 11 |
- "github.com/docker/distribution/reference" |
|
| 11 |
+ "github.com/distribution/reference" |
|
| 12 | 12 |
"github.com/docker/docker/api/types" |
| 13 | 13 |
"github.com/docker/docker/api/types/events" |
| 14 | 14 |
"github.com/docker/docker/api/types/filters" |
| ... | ... |
@@ -9,7 +9,7 @@ import ( |
| 9 | 9 |
"github.com/containerd/containerd/leases" |
| 10 | 10 |
"github.com/containerd/containerd/log" |
| 11 | 11 |
"github.com/containerd/containerd/namespaces" |
| 12 |
- "github.com/docker/distribution/reference" |
|
| 12 |
+ "github.com/distribution/reference" |
|
| 13 | 13 |
imagetypes "github.com/docker/docker/api/types/image" |
| 14 | 14 |
"github.com/docker/docker/api/types/registry" |
| 15 | 15 |
"github.com/docker/docker/distribution" |
| ... | ... |
@@ -5,8 +5,8 @@ import ( |
| 5 | 5 |
"io" |
| 6 | 6 |
"time" |
| 7 | 7 |
|
| 8 |
+ "github.com/distribution/reference" |
|
| 8 | 9 |
"github.com/docker/distribution/manifest/schema2" |
| 9 |
- "github.com/docker/distribution/reference" |
|
| 10 | 10 |
"github.com/docker/docker/api/types/registry" |
| 11 | 11 |
"github.com/docker/docker/distribution" |
| 12 | 12 |
progressutils "github.com/docker/docker/distribution/utils" |
| ... | ... |
@@ -6,9 +6,9 @@ import ( |
| 6 | 6 |
"io" |
| 7 | 7 |
"runtime" |
| 8 | 8 |
|
| 9 |
+ "github.com/distribution/reference" |
|
| 9 | 10 |
"github.com/docker/distribution" |
| 10 | 11 |
"github.com/docker/distribution/manifest/schema2" |
| 11 |
- "github.com/docker/distribution/reference" |
|
| 12 | 12 |
"github.com/docker/docker/api/types/events" |
| 13 | 13 |
"github.com/docker/docker/api/types/registry" |
| 14 | 14 |
"github.com/docker/docker/distribution/metadata" |
| ... | ... |
@@ -8,8 +8,8 @@ import ( |
| 8 | 8 |
"syscall" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/containerd/containerd/log" |
| 11 |
+ "github.com/distribution/reference" |
|
| 11 | 12 |
"github.com/docker/distribution" |
| 12 |
- "github.com/docker/distribution/reference" |
|
| 13 | 13 |
"github.com/docker/distribution/registry/api/errcode" |
| 14 | 14 |
v2 "github.com/docker/distribution/registry/api/v2" |
| 15 | 15 |
"github.com/docker/distribution/registry/client" |
| ... | ... |
@@ -11,11 +11,11 @@ import ( |
| 11 | 11 |
cerrdefs "github.com/containerd/containerd/errdefs" |
| 12 | 12 |
"github.com/containerd/containerd/log" |
| 13 | 13 |
"github.com/containerd/containerd/remotes" |
| 14 |
+ "github.com/distribution/reference" |
|
| 14 | 15 |
"github.com/docker/distribution" |
| 15 | 16 |
"github.com/docker/distribution/manifest/manifestlist" |
| 16 | 17 |
"github.com/docker/distribution/manifest/schema1" |
| 17 | 18 |
"github.com/docker/distribution/manifest/schema2" |
| 18 |
- "github.com/docker/distribution/reference" |
|
| 19 | 19 |
"github.com/docker/docker/registry" |
| 20 | 20 |
"github.com/opencontainers/go-digest" |
| 21 | 21 |
ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| ... | ... |
@@ -12,12 +12,12 @@ import ( |
| 12 | 12 |
"github.com/containerd/containerd/content/local" |
| 13 | 13 |
cerrdefs "github.com/containerd/containerd/errdefs" |
| 14 | 14 |
"github.com/containerd/containerd/remotes" |
| 15 |
+ "github.com/distribution/reference" |
|
| 15 | 16 |
"github.com/docker/distribution" |
| 16 | 17 |
"github.com/docker/distribution/manifest/manifestlist" |
| 17 | 18 |
"github.com/docker/distribution/manifest/ocischema" |
| 18 | 19 |
"github.com/docker/distribution/manifest/schema1" |
| 19 | 20 |
"github.com/docker/distribution/manifest/schema2" |
| 20 |
- "github.com/docker/distribution/reference" |
|
| 21 | 21 |
"github.com/google/go-cmp/cmp/cmpopts" |
| 22 | 22 |
"github.com/opencontainers/go-digest" |
| 23 | 23 |
ocispec "github.com/opencontainers/image-spec/specs-go/v1" |
| ... | ... |
@@ -5,7 +5,7 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
|
| 7 | 7 |
"github.com/containerd/containerd/log" |
| 8 |
- "github.com/docker/distribution/reference" |
|
| 8 |
+ "github.com/distribution/reference" |
|
| 9 | 9 |
"github.com/docker/docker/api" |
| 10 | 10 |
"github.com/docker/docker/api/types/events" |
| 11 | 11 |
refstore "github.com/docker/docker/reference" |
| ... | ... |
@@ -12,12 +12,12 @@ import ( |
| 12 | 12 |
|
| 13 | 13 |
"github.com/containerd/containerd/log" |
| 14 | 14 |
"github.com/containerd/containerd/platforms" |
| 15 |
+ "github.com/distribution/reference" |
|
| 15 | 16 |
"github.com/docker/distribution" |
| 16 | 17 |
"github.com/docker/distribution/manifest/manifestlist" |
| 17 | 18 |
"github.com/docker/distribution/manifest/ocischema" |
| 18 | 19 |
"github.com/docker/distribution/manifest/schema1" |
| 19 | 20 |
"github.com/docker/distribution/manifest/schema2" |
| 20 |
- "github.com/docker/distribution/reference" |
|
| 21 | 21 |
"github.com/docker/distribution/registry/client/transport" |
| 22 | 22 |
"github.com/docker/docker/distribution/metadata" |
| 23 | 23 |
"github.com/docker/docker/distribution/xfer" |
| ... | ... |
@@ -14,8 +14,8 @@ import ( |
| 14 | 14 |
"sync/atomic" |
| 15 | 15 |
"testing" |
| 16 | 16 |
|
| 17 |
+ "github.com/distribution/reference" |
|
| 17 | 18 |
"github.com/docker/distribution/manifest/schema1" |
| 18 |
- "github.com/docker/distribution/reference" |
|
| 19 | 19 |
registrytypes "github.com/docker/docker/api/types/registry" |
| 20 | 20 |
"github.com/docker/docker/image" |
| 21 | 21 |
"github.com/docker/docker/registry" |
| ... | ... |
@@ -11,10 +11,10 @@ import ( |
| 11 | 11 |
"sync" |
| 12 | 12 |
|
| 13 | 13 |
"github.com/containerd/containerd/log" |
| 14 |
+ "github.com/distribution/reference" |
|
| 14 | 15 |
"github.com/docker/distribution" |
| 15 | 16 |
"github.com/docker/distribution/manifest/schema1" |
| 16 | 17 |
"github.com/docker/distribution/manifest/schema2" |
| 17 |
- "github.com/docker/distribution/reference" |
|
| 18 | 18 |
"github.com/docker/distribution/registry/api/errcode" |
| 19 | 19 |
"github.com/docker/distribution/registry/client" |
| 20 | 20 |
apitypes "github.com/docker/docker/api/types" |
| ... | ... |
@@ -6,9 +6,9 @@ import ( |
| 6 | 6 |
"reflect" |
| 7 | 7 |
"testing" |
| 8 | 8 |
|
| 9 |
+ "github.com/distribution/reference" |
|
| 9 | 10 |
"github.com/docker/distribution" |
| 10 | 11 |
"github.com/docker/distribution/manifest/schema2" |
| 11 |
- "github.com/docker/distribution/reference" |
|
| 12 | 12 |
"github.com/docker/distribution/registry/api/errcode" |
| 13 | 13 |
"github.com/docker/docker/api/types/registry" |
| 14 | 14 |
"github.com/docker/docker/distribution/metadata" |
| ... | ... |
@@ -7,9 +7,9 @@ import ( |
| 7 | 7 |
"net/http" |
| 8 | 8 |
"time" |
| 9 | 9 |
|
| 10 |
+ "github.com/distribution/reference" |
|
| 10 | 11 |
"github.com/docker/distribution" |
| 11 | 12 |
"github.com/docker/distribution/manifest/schema2" |
| 12 |
- "github.com/docker/distribution/reference" |
|
| 13 | 13 |
"github.com/docker/distribution/registry/client" |
| 14 | 14 |
"github.com/docker/distribution/registry/client/auth" |
| 15 | 15 |
"github.com/docker/distribution/registry/client/transport" |
| ... | ... |
@@ -9,7 +9,7 @@ import ( |
| 9 | 9 |
"testing" |
| 10 | 10 |
|
| 11 | 11 |
"github.com/containerd/containerd/log" |
| 12 |
- "github.com/docker/distribution/reference" |
|
| 12 |
+ "github.com/distribution/reference" |
|
| 13 | 13 |
"github.com/docker/docker/api/types/registry" |
| 14 | 14 |
registrypkg "github.com/docker/docker/registry" |
| 15 | 15 |
) |
| ... | ... |
@@ -12,8 +12,8 @@ import ( |
| 12 | 12 |
"runtime" |
| 13 | 13 |
|
| 14 | 14 |
"github.com/containerd/containerd/log" |
| 15 |
+ "github.com/distribution/reference" |
|
| 15 | 16 |
"github.com/docker/distribution" |
| 16 |
- "github.com/docker/distribution/reference" |
|
| 17 | 17 |
"github.com/docker/docker/api/types/events" |
| 18 | 18 |
"github.com/docker/docker/image" |
| 19 | 19 |
v1 "github.com/docker/docker/image/v1" |
| ... | ... |
@@ -10,8 +10,8 @@ import ( |
| 10 | 10 |
"time" |
| 11 | 11 |
|
| 12 | 12 |
"github.com/containerd/containerd/images" |
| 13 |
+ "github.com/distribution/reference" |
|
| 13 | 14 |
"github.com/docker/distribution" |
| 14 |
- "github.com/docker/distribution/reference" |
|
| 15 | 15 |
"github.com/docker/docker/api/types/events" |
| 16 | 16 |
"github.com/docker/docker/image" |
| 17 | 17 |
v1 "github.com/docker/docker/image/v1" |
| ... | ... |
@@ -10,7 +10,7 @@ import ( |
| 10 | 10 |
"sync" |
| 11 | 11 |
"testing" |
| 12 | 12 |
|
| 13 |
- "github.com/docker/distribution/reference" |
|
| 13 |
+ "github.com/distribution/reference" |
|
| 14 | 14 |
"github.com/docker/docker/api/types/versions" |
| 15 | 15 |
"github.com/docker/docker/integration-cli/cli/build" |
| 16 | 16 |
"gotest.tools/v3/assert" |
| ... | ... |
@@ -20,8 +20,8 @@ import ( |
| 20 | 20 |
"github.com/containerd/containerd/platforms" |
| 21 | 21 |
"github.com/containerd/containerd/remotes" |
| 22 | 22 |
"github.com/containerd/containerd/remotes/docker" |
| 23 |
+ "github.com/distribution/reference" |
|
| 23 | 24 |
"github.com/docker/distribution/manifest/schema2" |
| 24 |
- "github.com/docker/distribution/reference" |
|
| 25 | 25 |
"github.com/docker/docker/api/types" |
| 26 | 26 |
"github.com/docker/docker/api/types/events" |
| 27 | 27 |
"github.com/docker/docker/api/types/filters" |
| ... | ... |
@@ -12,7 +12,7 @@ import ( |
| 12 | 12 |
"github.com/containerd/containerd/log" |
| 13 | 13 |
"github.com/containerd/containerd/remotes" |
| 14 | 14 |
"github.com/containerd/containerd/remotes/docker" |
| 15 |
- "github.com/docker/distribution/reference" |
|
| 15 |
+ "github.com/distribution/reference" |
|
| 16 | 16 |
"github.com/docker/docker/api/types/registry" |
| 17 | 17 |
progressutils "github.com/docker/docker/distribution/utils" |
| 18 | 18 |
"github.com/docker/docker/pkg/chrootarchive" |
| ... | ... |
@@ -10,7 +10,7 @@ import ( |
| 10 | 10 |
"github.com/containerd/containerd/log" |
| 11 | 11 |
"github.com/containerd/containerd/remotes" |
| 12 | 12 |
"github.com/containerd/containerd/remotes/docker" |
| 13 |
- "github.com/docker/distribution/reference" |
|
| 13 |
+ "github.com/distribution/reference" |
|
| 14 | 14 |
"github.com/docker/docker/api/types/registry" |
| 15 | 15 |
"github.com/docker/docker/dockerversion" |
| 16 | 16 |
"github.com/pkg/errors" |
| ... | ... |
@@ -6,7 +6,7 @@ import ( |
| 6 | 6 |
"strings" |
| 7 | 7 |
|
| 8 | 8 |
"github.com/containerd/containerd/log" |
| 9 |
- "github.com/docker/distribution/reference" |
|
| 9 |
+ "github.com/distribution/reference" |
|
| 10 | 10 |
"github.com/docker/docker/errdefs" |
| 11 | 11 |
"github.com/docker/docker/pkg/plugingetter" |
| 12 | 12 |
"github.com/docker/docker/pkg/plugins" |
| ... | ... |
@@ -34,6 +34,7 @@ require ( |
| 34 | 34 |
github.com/cpuguy83/tar2go v0.3.1 |
| 35 | 35 |
github.com/creack/pty v1.1.18 |
| 36 | 36 |
github.com/deckarep/golang-set/v2 v2.3.0 |
| 37 |
+ github.com/distribution/reference v0.5.0 |
|
| 37 | 38 |
github.com/docker/distribution v2.8.2+incompatible |
| 38 | 39 |
github.com/docker/go-connections v0.4.0 |
| 39 | 40 |
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c |
| ... | ... |
@@ -484,6 +484,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8 |
| 484 | 484 |
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= |
| 485 | 485 |
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= |
| 486 | 486 |
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= |
| 487 |
+github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= |
|
| 488 |
+github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= |
|
| 487 | 489 |
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= |
| 488 | 490 |
github.com/docker/cli v0.0.0-20190925022749-754388324470/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= |
| 489 | 491 |
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= |
| 0 | 2 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,18 @@ |
| 0 |
+linters: |
|
| 1 |
+ enable: |
|
| 2 |
+ - bodyclose |
|
| 3 |
+ - dupword # Checks for duplicate words in the source code |
|
| 4 |
+ - gofmt |
|
| 5 |
+ - goimports |
|
| 6 |
+ - ineffassign |
|
| 7 |
+ - misspell |
|
| 8 |
+ - revive |
|
| 9 |
+ - staticcheck |
|
| 10 |
+ - unconvert |
|
| 11 |
+ - unused |
|
| 12 |
+ - vet |
|
| 13 |
+ disable: |
|
| 14 |
+ - errcheck |
|
| 15 |
+ |
|
| 16 |
+run: |
|
| 17 |
+ deadline: 2m |
| 0 | 18 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,5 @@ |
| 0 |
+# Code of Conduct |
|
| 1 |
+ |
|
| 2 |
+We follow the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). |
|
| 3 |
+ |
|
| 4 |
+Please contact the [CNCF Code of Conduct Committee](mailto:conduct@cncf.io) in order to report violations of the Code of Conduct. |
| 0 | 5 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,114 @@ |
| 0 |
+# Contributing to the reference library |
|
| 1 |
+ |
|
| 2 |
+## Community help |
|
| 3 |
+ |
|
| 4 |
+If you need help, please ask in the [#distribution](https://cloud-native.slack.com/archives/C01GVR8SY4R) channel on CNCF community slack. |
|
| 5 |
+[Click here for an invite to the CNCF community slack](https://slack.cncf.io/) |
|
| 6 |
+ |
|
| 7 |
+## Reporting security issues |
|
| 8 |
+ |
|
| 9 |
+The maintainers take security seriously. If you discover a security |
|
| 10 |
+issue, please bring it to their attention right away! |
|
| 11 |
+ |
|
| 12 |
+Please **DO NOT** file a public issue, instead send your report privately to |
|
| 13 |
+[cncf-distribution-security@lists.cncf.io](mailto:cncf-distribution-security@lists.cncf.io). |
|
| 14 |
+ |
|
| 15 |
+## Reporting an issue properly |
|
| 16 |
+ |
|
| 17 |
+By following these simple rules you will get better and faster feedback on your issue. |
|
| 18 |
+ |
|
| 19 |
+ - search the bugtracker for an already reported issue |
|
| 20 |
+ |
|
| 21 |
+### If you found an issue that describes your problem: |
|
| 22 |
+ |
|
| 23 |
+ - please read other user comments first, and confirm this is the same issue: a given error condition might be indicative of different problems - you may also find a workaround in the comments |
|
| 24 |
+ - please refrain from adding "same thing here" or "+1" comments |
|
| 25 |
+ - you don't need to comment on an issue to get notified of updates: just hit the "subscribe" button |
|
| 26 |
+ - comment if you have some new, technical and relevant information to add to the case |
|
| 27 |
+ - __DO NOT__ comment on closed issues or merged PRs. If you think you have a related problem, open up a new issue and reference the PR or issue. |
|
| 28 |
+ |
|
| 29 |
+### If you have not found an existing issue that describes your problem: |
|
| 30 |
+ |
|
| 31 |
+ 1. create a new issue, with a succinct title that describes your issue: |
|
| 32 |
+ - bad title: "It doesn't work with my docker" |
|
| 33 |
+ - good title: "Private registry push fail: 400 error with E_INVALID_DIGEST" |
|
| 34 |
+ 2. copy the output of (or similar for other container tools): |
|
| 35 |
+ - `docker version` |
|
| 36 |
+ - `docker info` |
|
| 37 |
+ - `docker exec <registry-container> registry --version` |
|
| 38 |
+ 3. copy the command line you used to launch your Registry |
|
| 39 |
+ 4. restart your docker daemon in debug mode (add `-D` to the daemon launch arguments) |
|
| 40 |
+ 5. reproduce your problem and get your docker daemon logs showing the error |
|
| 41 |
+ 6. if relevant, copy your registry logs that show the error |
|
| 42 |
+ 7. provide any relevant detail about your specific Registry configuration (e.g., storage backend used) |
|
| 43 |
+ 8. indicate if you are using an enterprise proxy, Nginx, or anything else between you and your Registry |
|
| 44 |
+ |
|
| 45 |
+## Contributing Code |
|
| 46 |
+ |
|
| 47 |
+Contributions should be made via pull requests. Pull requests will be reviewed |
|
| 48 |
+by one or more maintainers or reviewers and merged when acceptable. |
|
| 49 |
+ |
|
| 50 |
+You should follow the basic GitHub workflow: |
|
| 51 |
+ |
|
| 52 |
+ 1. Use your own [fork](https://help.github.com/en/articles/about-forks) |
|
| 53 |
+ 2. Create your [change](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#successful-changes) |
|
| 54 |
+ 3. Test your code |
|
| 55 |
+ 4. [Commit](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#commit-messages) your work, always [sign your commits](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#commit-messages) |
|
| 56 |
+ 5. Push your change to your fork and create a [Pull Request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) |
|
| 57 |
+ |
|
| 58 |
+Refer to [containerd's contribution guide](https://github.com/containerd/project/blob/master/CONTRIBUTING.md#successful-changes) |
|
| 59 |
+for tips on creating a successful contribution. |
|
| 60 |
+ |
|
| 61 |
+## Sign your work |
|
| 62 |
+ |
|
| 63 |
+The sign-off is a simple line at the end of the explanation for the patch. Your |
|
| 64 |
+signature certifies that you wrote the patch or otherwise have the right to pass |
|
| 65 |
+it on as an open-source patch. The rules are pretty simple: if you can certify |
|
| 66 |
+the below (from [developercertificate.org](http://developercertificate.org/)): |
|
| 67 |
+ |
|
| 68 |
+``` |
|
| 69 |
+Developer Certificate of Origin |
|
| 70 |
+Version 1.1 |
|
| 71 |
+ |
|
| 72 |
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors. |
|
| 73 |
+660 York Street, Suite 102, |
|
| 74 |
+San Francisco, CA 94110 USA |
|
| 75 |
+ |
|
| 76 |
+Everyone is permitted to copy and distribute verbatim copies of this |
|
| 77 |
+license document, but changing it is not allowed. |
|
| 78 |
+ |
|
| 79 |
+Developer's Certificate of Origin 1.1 |
|
| 80 |
+ |
|
| 81 |
+By making a contribution to this project, I certify that: |
|
| 82 |
+ |
|
| 83 |
+(a) The contribution was created in whole or in part by me and I |
|
| 84 |
+ have the right to submit it under the open source license |
|
| 85 |
+ indicated in the file; or |
|
| 86 |
+ |
|
| 87 |
+(b) The contribution is based upon previous work that, to the best |
|
| 88 |
+ of my knowledge, is covered under an appropriate open source |
|
| 89 |
+ license and I have the right under that license to submit that |
|
| 90 |
+ work with modifications, whether created in whole or in part |
|
| 91 |
+ by me, under the same open source license (unless I am |
|
| 92 |
+ permitted to submit under a different license), as indicated |
|
| 93 |
+ in the file; or |
|
| 94 |
+ |
|
| 95 |
+(c) The contribution was provided directly to me by some other |
|
| 96 |
+ person who certified (a), (b) or (c) and I have not modified |
|
| 97 |
+ it. |
|
| 98 |
+ |
|
| 99 |
+(d) I understand and agree that this project and the contribution |
|
| 100 |
+ are public and that a record of the contribution (including all |
|
| 101 |
+ personal information I submit with it, including my sign-off) is |
|
| 102 |
+ maintained indefinitely and may be redistributed consistent with |
|
| 103 |
+ this project or the open source license(s) involved. |
|
| 104 |
+``` |
|
| 105 |
+ |
|
| 106 |
+Then you just add a line to every git commit message: |
|
| 107 |
+ |
|
| 108 |
+ Signed-off-by: Joe Smith <joe.smith@email.com> |
|
| 109 |
+ |
|
| 110 |
+Use your real name (sorry, no pseudonyms or anonymous contributions.) |
|
| 111 |
+ |
|
| 112 |
+If you set your `user.name` and `user.email` git configs, you can sign your |
|
| 113 |
+commit automatically with `git commit -s`. |
| 0 | 114 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,144 @@ |
| 0 |
+# distribution/reference Project Governance |
|
| 1 |
+ |
|
| 2 |
+Distribution [Code of Conduct](./CODE-OF-CONDUCT.md) can be found here. |
|
| 3 |
+ |
|
| 4 |
+For specific guidance on practical contribution steps please |
|
| 5 |
+see our [CONTRIBUTING.md](./CONTRIBUTING.md) guide. |
|
| 6 |
+ |
|
| 7 |
+## Maintainership |
|
| 8 |
+ |
|
| 9 |
+There are different types of maintainers, with different responsibilities, but |
|
| 10 |
+all maintainers have 3 things in common: |
|
| 11 |
+ |
|
| 12 |
+1) They share responsibility in the project's success. |
|
| 13 |
+2) They have made a long-term, recurring time investment to improve the project. |
|
| 14 |
+3) They spend that time doing whatever needs to be done, not necessarily what |
|
| 15 |
+is the most interesting or fun. |
|
| 16 |
+ |
|
| 17 |
+Maintainers are often under-appreciated, because their work is harder to appreciate. |
|
| 18 |
+It's easy to appreciate a really cool and technically advanced feature. It's harder |
|
| 19 |
+to appreciate the absence of bugs, the slow but steady improvement in stability, |
|
| 20 |
+or the reliability of a release process. But those things distinguish a good |
|
| 21 |
+project from a great one. |
|
| 22 |
+ |
|
| 23 |
+## Reviewers |
|
| 24 |
+ |
|
| 25 |
+A reviewer is a core role within the project. |
|
| 26 |
+They share in reviewing issues and pull requests and their LGTM counts towards the |
|
| 27 |
+required LGTM count to merge a code change into the project. |
|
| 28 |
+ |
|
| 29 |
+Reviewers are part of the organization but do not have write access. |
|
| 30 |
+Becoming a reviewer is a core aspect in the journey to becoming a maintainer. |
|
| 31 |
+ |
|
| 32 |
+## Adding maintainers |
|
| 33 |
+ |
|
| 34 |
+Maintainers are first and foremost contributors that have shown they are |
|
| 35 |
+committed to the long term success of a project. Contributors wanting to become |
|
| 36 |
+maintainers are expected to be deeply involved in contributing code, pull |
|
| 37 |
+request review, and triage of issues in the project for more than three months. |
|
| 38 |
+ |
|
| 39 |
+Just contributing does not make you a maintainer, it is about building trust |
|
| 40 |
+with the current maintainers of the project and being a person that they can |
|
| 41 |
+depend on and trust to make decisions in the best interest of the project. |
|
| 42 |
+ |
|
| 43 |
+Periodically, the existing maintainers curate a list of contributors that have |
|
| 44 |
+shown regular activity on the project over the prior months. From this list, |
|
| 45 |
+maintainer candidates are selected and proposed in a pull request or a |
|
| 46 |
+maintainers communication channel. |
|
| 47 |
+ |
|
| 48 |
+After a candidate has been announced to the maintainers, the existing |
|
| 49 |
+maintainers are given five business days to discuss the candidate, raise |
|
| 50 |
+objections and cast their vote. Votes may take place on the communication |
|
| 51 |
+channel or via pull request comment. Candidates must be approved by at least 66% |
|
| 52 |
+of the current maintainers by adding their vote on the mailing list. The |
|
| 53 |
+reviewer role has the same process but only requires 33% of current maintainers. |
|
| 54 |
+Only maintainers of the repository that the candidate is proposed for are |
|
| 55 |
+allowed to vote. |
|
| 56 |
+ |
|
| 57 |
+If a candidate is approved, a maintainer will contact the candidate to invite |
|
| 58 |
+the candidate to open a pull request that adds the contributor to the |
|
| 59 |
+MAINTAINERS file. The voting process may take place inside a pull request if a |
|
| 60 |
+maintainer has already discussed the candidacy with the candidate and a |
|
| 61 |
+maintainer is willing to be a sponsor by opening the pull request. The candidate |
|
| 62 |
+becomes a maintainer once the pull request is merged. |
|
| 63 |
+ |
|
| 64 |
+## Stepping down policy |
|
| 65 |
+ |
|
| 66 |
+Life priorities, interests, and passions can change. If you're a maintainer but |
|
| 67 |
+feel you must remove yourself from the list, inform other maintainers that you |
|
| 68 |
+intend to step down, and if possible, help find someone to pick up your work. |
|
| 69 |
+At the very least, ensure your work can be continued where you left off. |
|
| 70 |
+ |
|
| 71 |
+After you've informed other maintainers, create a pull request to remove |
|
| 72 |
+yourself from the MAINTAINERS file. |
|
| 73 |
+ |
|
| 74 |
+## Removal of inactive maintainers |
|
| 75 |
+ |
|
| 76 |
+Similar to the procedure for adding new maintainers, existing maintainers can |
|
| 77 |
+be removed from the list if they do not show significant activity on the |
|
| 78 |
+project. Periodically, the maintainers review the list of maintainers and their |
|
| 79 |
+activity over the last three months. |
|
| 80 |
+ |
|
| 81 |
+If a maintainer has shown insufficient activity over this period, a neutral |
|
| 82 |
+person will contact the maintainer to ask if they want to continue being |
|
| 83 |
+a maintainer. If the maintainer decides to step down as a maintainer, they |
|
| 84 |
+open a pull request to be removed from the MAINTAINERS file. |
|
| 85 |
+ |
|
| 86 |
+If the maintainer wants to remain a maintainer, but is unable to perform the |
|
| 87 |
+required duties they can be removed with a vote of at least 66% of the current |
|
| 88 |
+maintainers. In this case, maintainers should first propose the change to |
|
| 89 |
+maintainers via the maintainers communication channel, then open a pull request |
|
| 90 |
+for voting. The voting period is five business days. The voting pull request |
|
| 91 |
+should not come as a surpise to any maintainer and any discussion related to |
|
| 92 |
+performance must not be discussed on the pull request. |
|
| 93 |
+ |
|
| 94 |
+## How are decisions made? |
|
| 95 |
+ |
|
| 96 |
+Docker distribution is an open-source project with an open design philosophy. |
|
| 97 |
+This means that the repository is the source of truth for EVERY aspect of the |
|
| 98 |
+project, including its philosophy, design, road map, and APIs. *If it's part of |
|
| 99 |
+the project, it's in the repo. If it's in the repo, it's part of the project.* |
|
| 100 |
+ |
|
| 101 |
+As a result, all decisions can be expressed as changes to the repository. An |
|
| 102 |
+implementation change is a change to the source code. An API change is a change |
|
| 103 |
+to the API specification. A philosophy change is a change to the philosophy |
|
| 104 |
+manifesto, and so on. |
|
| 105 |
+ |
|
| 106 |
+All decisions affecting distribution, big and small, follow the same 3 steps: |
|
| 107 |
+ |
|
| 108 |
+* Step 1: Open a pull request. Anyone can do this. |
|
| 109 |
+ |
|
| 110 |
+* Step 2: Discuss the pull request. Anyone can do this. |
|
| 111 |
+ |
|
| 112 |
+* Step 3: Merge or refuse the pull request. Who does this depends on the nature |
|
| 113 |
+of the pull request and which areas of the project it affects. |
|
| 114 |
+ |
|
| 115 |
+## Helping contributors with the DCO |
|
| 116 |
+ |
|
| 117 |
+The [DCO or `Sign your work`](./CONTRIBUTING.md#sign-your-work) |
|
| 118 |
+requirement is not intended as a roadblock or speed bump. |
|
| 119 |
+ |
|
| 120 |
+Some contributors are not as familiar with `git`, or have used a web |
|
| 121 |
+based editor, and thus asking them to `git commit --amend -s` is not the best |
|
| 122 |
+way forward. |
|
| 123 |
+ |
|
| 124 |
+In this case, maintainers can update the commits based on clause (c) of the DCO. |
|
| 125 |
+The most trivial way for a contributor to allow the maintainer to do this, is to |
|
| 126 |
+add a DCO signature in a pull requests's comment, or a maintainer can simply |
|
| 127 |
+note that the change is sufficiently trivial that it does not substantially |
|
| 128 |
+change the existing contribution - i.e., a spelling change. |
|
| 129 |
+ |
|
| 130 |
+When you add someone's DCO, please also add your own to keep a log. |
|
| 131 |
+ |
|
| 132 |
+## I'm a maintainer. Should I make pull requests too? |
|
| 133 |
+ |
|
| 134 |
+Yes. Nobody should ever push to master directly. All changes should be |
|
| 135 |
+made through a pull request. |
|
| 136 |
+ |
|
| 137 |
+## Conflict Resolution |
|
| 138 |
+ |
|
| 139 |
+If you have a technical dispute that you feel has reached an impasse with a |
|
| 140 |
+subset of the community, any contributor may open an issue, specifically |
|
| 141 |
+calling for a resolution vote of the current core maintainers to resolve the |
|
| 142 |
+dispute. The same voting quorums required (2/3) for adding and removing |
|
| 143 |
+maintainers will apply to conflict resolution. |
| 0 | 144 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,202 @@ |
| 0 |
+Apache License |
|
| 1 |
+ Version 2.0, January 2004 |
|
| 2 |
+ http://www.apache.org/licenses/ |
|
| 3 |
+ |
|
| 4 |
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|
| 5 |
+ |
|
| 6 |
+ 1. Definitions. |
|
| 7 |
+ |
|
| 8 |
+ "License" shall mean the terms and conditions for use, reproduction, |
|
| 9 |
+ and distribution as defined by Sections 1 through 9 of this document. |
|
| 10 |
+ |
|
| 11 |
+ "Licensor" shall mean the copyright owner or entity authorized by |
|
| 12 |
+ the copyright owner that is granting the License. |
|
| 13 |
+ |
|
| 14 |
+ "Legal Entity" shall mean the union of the acting entity and all |
|
| 15 |
+ other entities that control, are controlled by, or are under common |
|
| 16 |
+ control with that entity. For the purposes of this definition, |
|
| 17 |
+ "control" means (i) the power, direct or indirect, to cause the |
|
| 18 |
+ direction or management of such entity, whether by contract or |
|
| 19 |
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|
| 20 |
+ outstanding shares, or (iii) beneficial ownership of such entity. |
|
| 21 |
+ |
|
| 22 |
+ "You" (or "Your") shall mean an individual or Legal Entity |
|
| 23 |
+ exercising permissions granted by this License. |
|
| 24 |
+ |
|
| 25 |
+ "Source" form shall mean the preferred form for making modifications, |
|
| 26 |
+ including but not limited to software source code, documentation |
|
| 27 |
+ source, and configuration files. |
|
| 28 |
+ |
|
| 29 |
+ "Object" form shall mean any form resulting from mechanical |
|
| 30 |
+ transformation or translation of a Source form, including but |
|
| 31 |
+ not limited to compiled object code, generated documentation, |
|
| 32 |
+ and conversions to other media types. |
|
| 33 |
+ |
|
| 34 |
+ "Work" shall mean the work of authorship, whether in Source or |
|
| 35 |
+ Object form, made available under the License, as indicated by a |
|
| 36 |
+ copyright notice that is included in or attached to the work |
|
| 37 |
+ (an example is provided in the Appendix below). |
|
| 38 |
+ |
|
| 39 |
+ "Derivative Works" shall mean any work, whether in Source or Object |
|
| 40 |
+ form, that is based on (or derived from) the Work and for which the |
|
| 41 |
+ editorial revisions, annotations, elaborations, or other modifications |
|
| 42 |
+ represent, as a whole, an original work of authorship. For the purposes |
|
| 43 |
+ of this License, Derivative Works shall not include works that remain |
|
| 44 |
+ separable from, or merely link (or bind by name) to the interfaces of, |
|
| 45 |
+ the Work and Derivative Works thereof. |
|
| 46 |
+ |
|
| 47 |
+ "Contribution" shall mean any work of authorship, including |
|
| 48 |
+ the original version of the Work and any modifications or additions |
|
| 49 |
+ to that Work or Derivative Works thereof, that is intentionally |
|
| 50 |
+ submitted to Licensor for inclusion in the Work by the copyright owner |
|
| 51 |
+ or by an individual or Legal Entity authorized to submit on behalf of |
|
| 52 |
+ the copyright owner. For the purposes of this definition, "submitted" |
|
| 53 |
+ means any form of electronic, verbal, or written communication sent |
|
| 54 |
+ to the Licensor or its representatives, including but not limited to |
|
| 55 |
+ communication on electronic mailing lists, source code control systems, |
|
| 56 |
+ and issue tracking systems that are managed by, or on behalf of, the |
|
| 57 |
+ Licensor for the purpose of discussing and improving the Work, but |
|
| 58 |
+ excluding communication that is conspicuously marked or otherwise |
|
| 59 |
+ designated in writing by the copyright owner as "Not a Contribution." |
|
| 60 |
+ |
|
| 61 |
+ "Contributor" shall mean Licensor and any individual or Legal Entity |
|
| 62 |
+ on behalf of whom a Contribution has been received by Licensor and |
|
| 63 |
+ subsequently incorporated within the Work. |
|
| 64 |
+ |
|
| 65 |
+ 2. Grant of Copyright License. Subject to the terms and conditions of |
|
| 66 |
+ this License, each Contributor hereby grants to You a perpetual, |
|
| 67 |
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 68 |
+ copyright license to reproduce, prepare Derivative Works of, |
|
| 69 |
+ publicly display, publicly perform, sublicense, and distribute the |
|
| 70 |
+ Work and such Derivative Works in Source or Object form. |
|
| 71 |
+ |
|
| 72 |
+ 3. Grant of Patent License. Subject to the terms and conditions of |
|
| 73 |
+ this License, each Contributor hereby grants to You a perpetual, |
|
| 74 |
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 75 |
+ (except as stated in this section) patent license to make, have made, |
|
| 76 |
+ use, offer to sell, sell, import, and otherwise transfer the Work, |
|
| 77 |
+ where such license applies only to those patent claims licensable |
|
| 78 |
+ by such Contributor that are necessarily infringed by their |
|
| 79 |
+ Contribution(s) alone or by combination of their Contribution(s) |
|
| 80 |
+ with the Work to which such Contribution(s) was submitted. If You |
|
| 81 |
+ institute patent litigation against any entity (including a |
|
| 82 |
+ cross-claim or counterclaim in a lawsuit) alleging that the Work |
|
| 83 |
+ or a Contribution incorporated within the Work constitutes direct |
|
| 84 |
+ or contributory patent infringement, then any patent licenses |
|
| 85 |
+ granted to You under this License for that Work shall terminate |
|
| 86 |
+ as of the date such litigation is filed. |
|
| 87 |
+ |
|
| 88 |
+ 4. Redistribution. You may reproduce and distribute copies of the |
|
| 89 |
+ Work or Derivative Works thereof in any medium, with or without |
|
| 90 |
+ modifications, and in Source or Object form, provided that You |
|
| 91 |
+ meet the following conditions: |
|
| 92 |
+ |
|
| 93 |
+ (a) You must give any other recipients of the Work or |
|
| 94 |
+ Derivative Works a copy of this License; and |
|
| 95 |
+ |
|
| 96 |
+ (b) You must cause any modified files to carry prominent notices |
|
| 97 |
+ stating that You changed the files; and |
|
| 98 |
+ |
|
| 99 |
+ (c) You must retain, in the Source form of any Derivative Works |
|
| 100 |
+ that You distribute, all copyright, patent, trademark, and |
|
| 101 |
+ attribution notices from the Source form of the Work, |
|
| 102 |
+ excluding those notices that do not pertain to any part of |
|
| 103 |
+ the Derivative Works; and |
|
| 104 |
+ |
|
| 105 |
+ (d) If the Work includes a "NOTICE" text file as part of its |
|
| 106 |
+ distribution, then any Derivative Works that You distribute must |
|
| 107 |
+ include a readable copy of the attribution notices contained |
|
| 108 |
+ within such NOTICE file, excluding those notices that do not |
|
| 109 |
+ pertain to any part of the Derivative Works, in at least one |
|
| 110 |
+ of the following places: within a NOTICE text file distributed |
|
| 111 |
+ as part of the Derivative Works; within the Source form or |
|
| 112 |
+ documentation, if provided along with the Derivative Works; or, |
|
| 113 |
+ within a display generated by the Derivative Works, if and |
|
| 114 |
+ wherever such third-party notices normally appear. The contents |
|
| 115 |
+ of the NOTICE file are for informational purposes only and |
|
| 116 |
+ do not modify the License. You may add Your own attribution |
|
| 117 |
+ notices within Derivative Works that You distribute, alongside |
|
| 118 |
+ or as an addendum to the NOTICE text from the Work, provided |
|
| 119 |
+ that such additional attribution notices cannot be construed |
|
| 120 |
+ as modifying the License. |
|
| 121 |
+ |
|
| 122 |
+ You may add Your own copyright statement to Your modifications and |
|
| 123 |
+ may provide additional or different license terms and conditions |
|
| 124 |
+ for use, reproduction, or distribution of Your modifications, or |
|
| 125 |
+ for any such Derivative Works as a whole, provided Your use, |
|
| 126 |
+ reproduction, and distribution of the Work otherwise complies with |
|
| 127 |
+ the conditions stated in this License. |
|
| 128 |
+ |
|
| 129 |
+ 5. Submission of Contributions. Unless You explicitly state otherwise, |
|
| 130 |
+ any Contribution intentionally submitted for inclusion in the Work |
|
| 131 |
+ by You to the Licensor shall be under the terms and conditions of |
|
| 132 |
+ this License, without any additional terms or conditions. |
|
| 133 |
+ Notwithstanding the above, nothing herein shall supersede or modify |
|
| 134 |
+ the terms of any separate license agreement you may have executed |
|
| 135 |
+ with Licensor regarding such Contributions. |
|
| 136 |
+ |
|
| 137 |
+ 6. Trademarks. This License does not grant permission to use the trade |
|
| 138 |
+ names, trademarks, service marks, or product names of the Licensor, |
|
| 139 |
+ except as required for reasonable and customary use in describing the |
|
| 140 |
+ origin of the Work and reproducing the content of the NOTICE file. |
|
| 141 |
+ |
|
| 142 |
+ 7. Disclaimer of Warranty. Unless required by applicable law or |
|
| 143 |
+ agreed to in writing, Licensor provides the Work (and each |
|
| 144 |
+ Contributor provides its Contributions) on an "AS IS" BASIS, |
|
| 145 |
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
| 146 |
+ implied, including, without limitation, any warranties or conditions |
|
| 147 |
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|
| 148 |
+ PARTICULAR PURPOSE. You are solely responsible for determining the |
|
| 149 |
+ appropriateness of using or redistributing the Work and assume any |
|
| 150 |
+ risks associated with Your exercise of permissions under this License. |
|
| 151 |
+ |
|
| 152 |
+ 8. Limitation of Liability. In no event and under no legal theory, |
|
| 153 |
+ whether in tort (including negligence), contract, or otherwise, |
|
| 154 |
+ unless required by applicable law (such as deliberate and grossly |
|
| 155 |
+ negligent acts) or agreed to in writing, shall any Contributor be |
|
| 156 |
+ liable to You for damages, including any direct, indirect, special, |
|
| 157 |
+ incidental, or consequential damages of any character arising as a |
|
| 158 |
+ result of this License or out of the use or inability to use the |
|
| 159 |
+ Work (including but not limited to damages for loss of goodwill, |
|
| 160 |
+ work stoppage, computer failure or malfunction, or any and all |
|
| 161 |
+ other commercial damages or losses), even if such Contributor |
|
| 162 |
+ has been advised of the possibility of such damages. |
|
| 163 |
+ |
|
| 164 |
+ 9. Accepting Warranty or Additional Liability. While redistributing |
|
| 165 |
+ the Work or Derivative Works thereof, You may choose to offer, |
|
| 166 |
+ and charge a fee for, acceptance of support, warranty, indemnity, |
|
| 167 |
+ or other liability obligations and/or rights consistent with this |
|
| 168 |
+ License. However, in accepting such obligations, You may act only |
|
| 169 |
+ on Your own behalf and on Your sole responsibility, not on behalf |
|
| 170 |
+ of any other Contributor, and only if You agree to indemnify, |
|
| 171 |
+ defend, and hold each Contributor harmless for any liability |
|
| 172 |
+ incurred by, or claims asserted against, such Contributor by reason |
|
| 173 |
+ of your accepting any such warranty or additional liability. |
|
| 174 |
+ |
|
| 175 |
+ END OF TERMS AND CONDITIONS |
|
| 176 |
+ |
|
| 177 |
+ APPENDIX: How to apply the Apache License to your work. |
|
| 178 |
+ |
|
| 179 |
+ To apply the Apache License to your work, attach the following |
|
| 180 |
+ boilerplate notice, with the fields enclosed by brackets "{}"
|
|
| 181 |
+ replaced with your own identifying information. (Don't include |
|
| 182 |
+ the brackets!) The text should be enclosed in the appropriate |
|
| 183 |
+ comment syntax for the file format. We also recommend that a |
|
| 184 |
+ file or class name and description of purpose be included on the |
|
| 185 |
+ same "printed page" as the copyright notice for easier |
|
| 186 |
+ identification within third-party archives. |
|
| 187 |
+ |
|
| 188 |
+ Copyright {yyyy} {name of copyright owner}
|
|
| 189 |
+ |
|
| 190 |
+ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 191 |
+ you may not use this file except in compliance with the License. |
|
| 192 |
+ You may obtain a copy of the License at |
|
| 193 |
+ |
|
| 194 |
+ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 195 |
+ |
|
| 196 |
+ Unless required by applicable law or agreed to in writing, software |
|
| 197 |
+ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 198 |
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 199 |
+ See the License for the specific language governing permissions and |
|
| 200 |
+ limitations under the License. |
|
| 201 |
+ |
| 0 | 202 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,26 @@ |
| 0 |
+# Distribution project maintainers & reviewers |
|
| 1 |
+# |
|
| 2 |
+# See GOVERNANCE.md for maintainer versus reviewer roles |
|
| 3 |
+# |
|
| 4 |
+# MAINTAINERS (cncf-distribution-maintainers@lists.cncf.io) |
|
| 5 |
+# GitHub ID, Name, Email address |
|
| 6 |
+"chrispat","Chris Patterson","chrispat@github.com" |
|
| 7 |
+"clarkbw","Bryan Clark","clarkbw@github.com" |
|
| 8 |
+"corhere","Cory Snider","csnider@mirantis.com" |
|
| 9 |
+"deleteriousEffect","Hayley Swimelar","hswimelar@gitlab.com" |
|
| 10 |
+"heww","He Weiwei","hweiwei@vmware.com" |
|
| 11 |
+"joaodrp","João Pereira","jpereira@gitlab.com" |
|
| 12 |
+"justincormack","Justin Cormack","justin.cormack@docker.com" |
|
| 13 |
+"squizzi","Kyle Squizzato","ksquizzato@mirantis.com" |
|
| 14 |
+"milosgajdos","Milos Gajdos","milosthegajdos@gmail.com" |
|
| 15 |
+"sargun","Sargun Dhillon","sargun@sargun.me" |
|
| 16 |
+"wy65701436","Wang Yan","wangyan@vmware.com" |
|
| 17 |
+"stevelasker","Steve Lasker","steve.lasker@microsoft.com" |
|
| 18 |
+# |
|
| 19 |
+# REVIEWERS |
|
| 20 |
+# GitHub ID, Name, Email address |
|
| 21 |
+"dmcgowan","Derek McGowan","derek@mcgstyle.net" |
|
| 22 |
+"stevvooe","Stephen Day","stevvooe@gmail.com" |
|
| 23 |
+"thajeztah","Sebastiaan van Stijn","github@gone.nl" |
|
| 24 |
+"DavidSpek", "David van der Spek", "vanderspek.david@gmail.com" |
|
| 25 |
+"Jamstah", "James Hewitt", "james.hewitt@gmail.com" |
| 0 | 26 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,25 @@ |
| 0 |
+# Project packages. |
|
| 1 |
+PACKAGES=$(shell go list ./...) |
|
| 2 |
+ |
|
| 3 |
+# Flags passed to `go test` |
|
| 4 |
+BUILDFLAGS ?= |
|
| 5 |
+TESTFLAGS ?= |
|
| 6 |
+ |
|
| 7 |
+.PHONY: all build test coverage |
|
| 8 |
+.DEFAULT: all |
|
| 9 |
+ |
|
| 10 |
+all: build |
|
| 11 |
+ |
|
| 12 |
+build: ## no binaries to build, so just check compilation suceeds |
|
| 13 |
+ go build ${BUILDFLAGS} ./...
|
|
| 14 |
+ |
|
| 15 |
+test: ## run tests |
|
| 16 |
+ go test ${TESTFLAGS} ./...
|
|
| 17 |
+ |
|
| 18 |
+coverage: ## generate coverprofiles from the unit tests |
|
| 19 |
+ rm -f coverage.txt |
|
| 20 |
+ go test ${TESTFLAGS} -cover -coverprofile=cover.out ./...
|
|
| 21 |
+ |
|
| 22 |
+.PHONY: help |
|
| 23 |
+help: |
|
| 24 |
+ @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_\/%-]+:.*?##/ { printf " \033[36m%-27s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
| 0 | 25 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,30 @@ |
| 0 |
+# Distribution reference |
|
| 1 |
+ |
|
| 2 |
+Go library to handle references to container images. |
|
| 3 |
+ |
|
| 4 |
+<img src="/distribution-logo.svg" width="200px" /> |
|
| 5 |
+ |
|
| 6 |
+[](https://github.com/distribution/reference/actions?query=workflow%3ACI) |
|
| 7 |
+[](https://pkg.go.dev/github.com/distribution/reference) |
|
| 8 |
+[](LICENSE) |
|
| 9 |
+[](https://codecov.io/gh/distribution/reference) |
|
| 10 |
+[](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fdistribution%2Freference?ref=badge_shield) |
|
| 11 |
+ |
|
| 12 |
+This repository contains a library for handling refrences to container images held in container registries. Please see [godoc](https://pkg.go.dev/github.com/distribution/reference) for details. |
|
| 13 |
+ |
|
| 14 |
+## Contribution |
|
| 15 |
+ |
|
| 16 |
+Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute |
|
| 17 |
+issues, fixes, and patches to this project. |
|
| 18 |
+ |
|
| 19 |
+## Communication |
|
| 20 |
+ |
|
| 21 |
+For async communication and long running discussions please use issues and pull requests on the github repo. |
|
| 22 |
+This will be the best place to discuss design and implementation. |
|
| 23 |
+ |
|
| 24 |
+For sync communication we have a #distribution channel in the [CNCF Slack](https://slack.cncf.io/) |
|
| 25 |
+that everyone is welcome to join and chat about development. |
|
| 26 |
+ |
|
| 27 |
+## Licenses |
|
| 28 |
+ |
|
| 29 |
+The distribution codebase is released under the [Apache 2.0 license](LICENSE). |
| 0 | 30 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,7 @@ |
| 0 |
+# Security Policy |
|
| 1 |
+ |
|
| 2 |
+## Reporting a Vulnerability |
|
| 3 |
+ |
|
| 4 |
+The maintainers take security seriously. If you discover a security issue, please bring it to their attention right away! |
|
| 5 |
+ |
|
| 6 |
+Please DO NOT file a public issue, instead send your report privately to cncf-distribution-security@lists.cncf.io. |
| 0 | 7 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1 @@ |
| 0 |
+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 564.27793 654.82002"><defs><style>.cls-1{fill:#416ba9;}.cls-2{fill:#74c3d5;}</style></defs><path class="cls-1" d="M17.48582,567.55941c0-3.66375,2.2168-4.91716,4.91609-4.91716H36.66877c18.70153,0,28.24476,9.06127,28.24476,33.64387,0,22.26771-7.51889,35.57065-27.95526,35.57065H22.40191c-2.69929,0-4.91609-1.25341-4.91609-4.91609Zm20.33987,49.741c7.61539,0,10.60365-6.94043,10.60365-20.72586,0-15.13429-3.85568-19.376-10.70015-19.376H33.97v40.10182Z"/><path class="cls-1" d="M72.43613,567.55941c0-3.66375,2.21681-4.91716,4.9161-4.91716h6.36251c2.69876,0,4.91609,1.25341,4.91609,4.91716v59.38127c0,3.66268-2.21733,4.91609-4.91609,4.91609H77.35223c-2.69929,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M99.718,613.05875l5.78405-1.06042c4.33764-.77092,4.53063,1.15692,5.78352,3.85674a6.70953,6.70953,0,0,0,6.5555,3.95218c3.56672,0,6.26548-1.83134,6.26548-5.59158,0-12.82046-27.6663-11.08561-27.6663-34.31724,0-10.79718,7.80839-18.1236,20.43637-18.1236,11.08614,0,16.96615,4.8196,20.05091,12.918.96445,2.31277,1.44641,4.7231-2.98826,5.59052l-5.20559,1.06042c-3.95218.77092-4.33764-1.06042-6.073-3.66269a6.39679,6.39679,0,0,0-5.49456-3.08475c-3.18125,0-5.20559,1.83134-5.20559,4.7231,0,12.24252,27.56981,10.60418,27.56981,33.73931,0,12.532-8.77231,19.66545-22.36422,19.66545-11.47159,0-17.93007-4.43467-20.82236-14.07387C95.57286,616.24,95.1874,613.92617,99.718,613.05875Z"/><path class="cls-1" d="M154.86187,576.62068h-8.09735c-3.66321,0-4.91662-2.21734-4.91662-4.91716v-4.14411c0-2.69983,1.25341-4.91716,4.91662-4.91716H179.058c3.66321,0,4.91609,2.21733,4.91609,4.91716v4.14411c0,2.69982-1.25288,4.91716-4.91609,4.91716h-8.09788v50.32c0,3.66268-2.21681,4.91609-4.9161,4.91609h-6.266c-2.69876,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M189.76022,567.55941c0-3.66375,2.21681-4.91716,4.9161-4.91716h16.2912c15.13481,0,23.03969,5.68808,23.03969,20.05144,0,8.38684-3.27775,13.68787-8.29034,16.77369l9.35076,27.76173c1.34938,4.04974-.96445,4.62766-3.37425,4.62766h-8.67581c-2.89176,0-4.53063-1.92783-5.30208-4.7231L211.546,605.92532h-5.68755v21.01536c0,3.66268-2.2168,4.91609-4.91609,4.91609h-6.266c-2.69929,0-4.9161-1.25341-4.9161-4.91609Zm20.14688,25.35246c4.14517,0,7.61592-1.6394,7.61592-8.57984,0-7.61486-3.37425-8.19384-7.22993-8.19384h-4.43467v16.77368Z"/><path class="cls-1" d="M241.91422,567.55941c0-3.66375,2.2168-4.91716,4.91609-4.91716h6.36251c2.69876,0,4.9161,1.25341,4.9161,4.91716v59.38127c0,3.66268-2.21734,4.91609-4.9161,4.91609h-6.36251c-2.69929,0-4.91609-1.25341-4.91609-4.91609Z"/><path class="cls-1" d="M267.75024,567.55941c0-3.66375,2.2168-4.91716,4.91609-4.91716h14.94182c16.77316,0,24.09958,5.49508,24.09958,18.31659,0,6.94044-3.08475,11.953-8.96477,14.5553v.193c6.74744,2.31384,10.41065,7.13343,10.41065,15.80977,0,16.58069-11.3751,20.33987-25.449,20.33987H272.66633c-2.69929,0-4.91609-1.25341-4.91609-4.91609Zm20.72533,22.5572c4.33817,0,6.84447-2.12083,6.84447-7.32642,0-4.91716-2.79579-6.36251-6.84447-6.36251h-4.9161v13.68893Zm.386,27.95473c5.88,0,7.90436-2.40926,7.90436-7.80785,0-5.88-3.18126-7.80786-7.80839-7.80786h-5.39806v15.61571Z"/><path class="cls-1" d="M320.09776,567.55941c0-3.66375,2.21733-4.91716,4.91662-4.91716h6.362c2.69929,0,4.91663,1.25341,4.91663,4.91716v43.282c0,5.78457,2.3133,8.38684,6.748,8.38684,4.43413,0,7.13343-2.60227,7.13343-8.38684v-43.282c0-3.66375,2.21733-4.91716,4.91609-4.91716H361.26c2.6993,0,4.91663,1.25341,4.91663,4.91716v41.06573c0,15.80871-7.13343,24.00256-23.42516,24.00256-16.0982,0-22.6537-8.19385-22.6537-24.00256Z"/><path class="cls-1" d="M384.59236,576.62068H376.495c-3.66322,0-4.91663-2.21734-4.91663-4.91716v-4.14411c0-2.69983,1.25341-4.91716,4.91663-4.91716h32.29343c3.66321,0,4.91609,2.21733,4.91609,4.91716v4.14411c0,2.69982-1.25288,4.91716-4.91609,4.91716H400.6911v50.32c0,3.66268-2.21734,4.91609-4.91663,4.91609h-6.266c-2.69929,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M419.49071,567.55941c0-3.66375,2.21681-4.91716,4.9161-4.91716h6.36251c2.69876,0,4.91609,1.25341,4.91609,4.91716v59.38127c0,3.66268-2.21733,4.91609-4.91609,4.91609h-6.36251c-2.69929,0-4.9161-1.25341-4.9161-4.91609Z"/><path class="cls-1" d="M443.20536,597.34654c0-21.30485,5.59106-35.57171,24.48505-35.57171s24.48505,14.26686,24.48505,35.57171c0,22.07472-6.84394,35.37766-24.485,35.37766S443.20536,619.42126,443.20536,597.34654Zm32.48643,0c0-16.29226-2.12083-22.26877-8.00138-22.26877-5.88,0-8.00085,5.97651-8.00085,22.26877,0,17.06212,2.4098,22.17121,8.00085,22.17121C473.378,619.51775,475.69179,614.40866,475.69179,597.34654Z"/><path class="cls-1" d="M499.69859,567.55941c0-3.66375,2.2168-4.91716,4.9161-4.91716h6.941a7.56728,7.56728,0,0,1,6.84394,4.43467l13.207,29.88363h.19247V567.55941c0-3.66375,2.21733-4.91716,4.91662-4.91716h4.62714c2.69876,0,4.91609,1.25341,4.91609,4.91716v59.38127c0,3.66268-2.21733,4.91609-4.91609,4.91609h-5.68756c-2.98878,0-4.72363-1.83134-5.977-4.43466L514.15792,593.5863h-.19247v33.35438c0,3.66268-2.21733,4.91609-4.91663,4.91609h-4.43413c-2.6993,0-4.9161-1.25341-4.9161-4.91609Z"/><g id="F1L4Xu"><path class="cls-2" d="M461.28162,365.26377c14.626-14.99573,31.51073-27.88581,43.901-45.3001,23.6055-33.17709,21.5881-53.98611-9.08528-79.89549-5.54727-4.68571-8.18237-7.96252-5.187-15.251,2.57641-6.26934,3.76528-13.21711,4.83156-19.981,5.90314-37.44659-11.00082-60.70078-48.64828-63.33267-13.137-.91842-16.45015-5.43062-19.21754-16.935-9.30387-38.67663-34.59038-53.67167-74.13662-44.585-10.18443,2.3401-17.05741,2.2529-24.8593-6.77926-30.175-34.93317-59.58084-35.22646-91.95222-.348-9.64337,10.39025-15.6225,11.83918-28.62783,5.4055-32.90341-16.27713-59.8387-3.10046-69.78437,35.47712-4.6848,18.17164-11.36854,26.3489-30.24471,30.1582-31.33028,6.32259-44.78933,33.5759-35.57532,69.531,3.76252,14.68215,4.6826,23.43655-10.28992,33.26423-22.74913,14.93216-25.22052,35.33713-11.0953,59.39875a163.06863,163.06863,0,0,0,18.46085,24.68707c6.40258,7.28037,13.94521,13.55817,19.80434,21.482C65.25053,338.04809,43.116,321.28746,27.8598,297.29993c-17.05057-26.80876-13.40609-48.15088,13.33187-65.26212,13.64688-8.73344,14.87507-15.92347,10.65871-30.93464-12.7269-45.31048,5.12054-71.29348,52.09339-78.34017,9.12234-1.36851,13.24368-4.37134,14.93358-13.09156a120.37358,120.37358,0,0,1,6.91928-23.66458C140.26672,51.59355,166.89048,40.64934,200.93587,56.76c12.995,6.14933,20.16447,5.77862,30.68022-5.2998C268.21035,12.90788,301.23887,13.957,336.089,53.95609c7.03437,8.07364,13.32723,7.58749,21.51782,5.54845,49.26567-12.26462,82.34232,9.66738,86.80352,52.02378.85563,8.12375,4.89151,12.49189,13.59822,11.06745a9.08058,9.08058,0,0,1,2.06083.01162c48.42775,3.32745,67.90447,29.37216,55.65225,76.28488-3.68675,14.11627-5.266,23.35647,9.83168,33.3918,24.025,15.96919,26.43605,40.908,10.89058,67.22194C523.519,321.384,492.3391,349.49056,461.28162,365.26377Z"/><path class="cls-2" d="M222.21166,412.15994c-43.3335,8.71069-88.628,7.98395-130.77907,28.38523,94.59324,34.57588,265.86321,39.32494,381.28659.87883-20.80256-13.03877-43.25235-15.46757-64.96771-19.52875-21.46582-4.01455-43.21049-6.53754-65.22855-9.773,2.32155-9.0906,5.71941-13.26155,14.6818-11.53506,34.9755,6.73747,70.6065,10.43856,104.30053,22.96341,8.18218,3.04152,18.89124,4.40911,19.86455,15.15614,1.09622,12.10448-6.10692,24.09739-16.79915,25.67409-30.25013,4.46064-56.38559,26.36212-84.9133,26.506-28.47048.14371-52.82989-.52977-79.492,14.17476-20.18156,11.13047-46.332,2.83194-64.16335-15.45408-6.83775-7.01216-11.13794-6.37864-19.02114-2.85829-23.91278,10.67842-47.24546,8.5124-67.31614-8.79886-7.10279-6.12627-13.27536-7.629-22.06165-6.68907a44.08867,44.08867,0,0,1-27.74743-5.86122C89.8179,459.38315,82.0507,451.437,82.898,439.18832c.77048-11.13889,11.49627-12.35089,19.55689-15.40536,33.62848-12.74306,69.18754-16.82889,104.26785-23.14551C215.75685,399.01074,219.15407,403.38339,222.21166,412.15994Z"/></g><rect class="cls-1" x="157.9184" y="278.28554" width="63.75238" height="63.75238"/><rect class="cls-1" x="241.008" y="278.28554" width="63.75238" height="63.75238"/><rect class="cls-1" x="157.9184" y="361.37514" width="63.75238" height="63.75238"/><rect class="cls-1" x="367.09657" y="153.06724" width="63.75176" height="63.75177" transform="translate(-13.91822 336.28471) rotate(-45)"/><polygon class="cls-1" points="239.799 221.785 239.799 222.389 296.3 250.79 325.004 193.987 268.201 165.284 239.799 221.785"/><rect class="cls-1" x="341.49858" y="264.8759" width="63.75384" height="63.75383" transform="translate(-59.8512 496.2174) rotate(-63.19922)"/><rect class="cls-1" x="157.9184" y="195.19594" width="63.75238" height="63.75238"/><rect class="cls-1" x="241.008" y="361.37514" width="63.75238" height="63.75238"/><rect class="cls-1" x="324.39973" y="361.37514" width="63.75238" height="63.75238"/></svg>
|
|
| 0 | 1 |
\ No newline at end of file |
| 1 | 2 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,42 @@ |
| 0 |
+package reference |
|
| 1 |
+ |
|
| 2 |
+import "path" |
|
| 3 |
+ |
|
| 4 |
+// IsNameOnly returns true if reference only contains a repo name. |
|
| 5 |
+func IsNameOnly(ref Named) bool {
|
|
| 6 |
+ if _, ok := ref.(NamedTagged); ok {
|
|
| 7 |
+ return false |
|
| 8 |
+ } |
|
| 9 |
+ if _, ok := ref.(Canonical); ok {
|
|
| 10 |
+ return false |
|
| 11 |
+ } |
|
| 12 |
+ return true |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+// FamiliarName returns the familiar name string |
|
| 16 |
+// for the given named, familiarizing if needed. |
|
| 17 |
+func FamiliarName(ref Named) string {
|
|
| 18 |
+ if nn, ok := ref.(normalizedNamed); ok {
|
|
| 19 |
+ return nn.Familiar().Name() |
|
| 20 |
+ } |
|
| 21 |
+ return ref.Name() |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+// FamiliarString returns the familiar string representation |
|
| 25 |
+// for the given reference, familiarizing if needed. |
|
| 26 |
+func FamiliarString(ref Reference) string {
|
|
| 27 |
+ if nn, ok := ref.(normalizedNamed); ok {
|
|
| 28 |
+ return nn.Familiar().String() |
|
| 29 |
+ } |
|
| 30 |
+ return ref.String() |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+// FamiliarMatch reports whether ref matches the specified pattern. |
|
| 34 |
+// See [path.Match] for supported patterns. |
|
| 35 |
+func FamiliarMatch(pattern string, ref Reference) (bool, error) {
|
|
| 36 |
+ matched, err := path.Match(pattern, FamiliarString(ref)) |
|
| 37 |
+ if namedRef, isNamed := ref.(Named); isNamed && !matched {
|
|
| 38 |
+ matched, _ = path.Match(pattern, FamiliarName(namedRef)) |
|
| 39 |
+ } |
|
| 40 |
+ return matched, err |
|
| 41 |
+} |
| 0 | 42 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,224 @@ |
| 0 |
+package reference |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/opencontainers/go-digest" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+const ( |
|
| 10 |
+ // legacyDefaultDomain is the legacy domain for Docker Hub (which was |
|
| 11 |
+ // originally named "the Docker Index"). This domain is still used for |
|
| 12 |
+ // authentication and image search, which were part of the "v1" Docker |
|
| 13 |
+ // registry specification. |
|
| 14 |
+ // |
|
| 15 |
+ // This domain will continue to be supported, but there are plans to consolidate |
|
| 16 |
+ // legacy domains to new "canonical" domains. Once those domains are decided |
|
| 17 |
+ // on, we must update the normalization functions, but preserve compatibility |
|
| 18 |
+ // with existing installs, clients, and user configuration. |
|
| 19 |
+ legacyDefaultDomain = "index.docker.io" |
|
| 20 |
+ |
|
| 21 |
+ // defaultDomain is the default domain used for images on Docker Hub. |
|
| 22 |
+ // It is used to normalize "familiar" names to canonical names, for example, |
|
| 23 |
+ // to convert "ubuntu" to "docker.io/library/ubuntu:latest". |
|
| 24 |
+ // |
|
| 25 |
+ // Note that actual domain of Docker Hub's registry is registry-1.docker.io. |
|
| 26 |
+ // This domain will continue to be supported, but there are plans to consolidate |
|
| 27 |
+ // legacy domains to new "canonical" domains. Once those domains are decided |
|
| 28 |
+ // on, we must update the normalization functions, but preserve compatibility |
|
| 29 |
+ // with existing installs, clients, and user configuration. |
|
| 30 |
+ defaultDomain = "docker.io" |
|
| 31 |
+ |
|
| 32 |
+ // officialRepoPrefix is the namespace used for official images on Docker Hub. |
|
| 33 |
+ // It is used to normalize "familiar" names to canonical names, for example, |
|
| 34 |
+ // to convert "ubuntu" to "docker.io/library/ubuntu:latest". |
|
| 35 |
+ officialRepoPrefix = "library/" |
|
| 36 |
+ |
|
| 37 |
+ // defaultTag is the default tag if no tag is provided. |
|
| 38 |
+ defaultTag = "latest" |
|
| 39 |
+) |
|
| 40 |
+ |
|
| 41 |
+// normalizedNamed represents a name which has been |
|
| 42 |
+// normalized and has a familiar form. A familiar name |
|
| 43 |
+// is what is used in Docker UI. An example normalized |
|
| 44 |
+// name is "docker.io/library/ubuntu" and corresponding |
|
| 45 |
+// familiar name of "ubuntu". |
|
| 46 |
+type normalizedNamed interface {
|
|
| 47 |
+ Named |
|
| 48 |
+ Familiar() Named |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+// ParseNormalizedNamed parses a string into a named reference |
|
| 52 |
+// transforming a familiar name from Docker UI to a fully |
|
| 53 |
+// qualified reference. If the value may be an identifier |
|
| 54 |
+// use ParseAnyReference. |
|
| 55 |
+func ParseNormalizedNamed(s string) (Named, error) {
|
|
| 56 |
+ if ok := anchoredIdentifierRegexp.MatchString(s); ok {
|
|
| 57 |
+ return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
|
|
| 58 |
+ } |
|
| 59 |
+ domain, remainder := splitDockerDomain(s) |
|
| 60 |
+ var remote string |
|
| 61 |
+ if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 {
|
|
| 62 |
+ remote = remainder[:tagSep] |
|
| 63 |
+ } else {
|
|
| 64 |
+ remote = remainder |
|
| 65 |
+ } |
|
| 66 |
+ if strings.ToLower(remote) != remote {
|
|
| 67 |
+ return nil, fmt.Errorf("invalid reference format: repository name (%s) must be lowercase", remote)
|
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 70 |
+ ref, err := Parse(domain + "/" + remainder) |
|
| 71 |
+ if err != nil {
|
|
| 72 |
+ return nil, err |
|
| 73 |
+ } |
|
| 74 |
+ named, isNamed := ref.(Named) |
|
| 75 |
+ if !isNamed {
|
|
| 76 |
+ return nil, fmt.Errorf("reference %s has no name", ref.String())
|
|
| 77 |
+ } |
|
| 78 |
+ return named, nil |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+// namedTaggedDigested is a reference that has both a tag and a digest. |
|
| 82 |
+type namedTaggedDigested interface {
|
|
| 83 |
+ NamedTagged |
|
| 84 |
+ Digested |
|
| 85 |
+} |
|
| 86 |
+ |
|
| 87 |
+// ParseDockerRef normalizes the image reference following the docker convention, |
|
| 88 |
+// which allows for references to contain both a tag and a digest. It returns a |
|
| 89 |
+// reference that is either tagged or digested. For references containing both |
|
| 90 |
+// a tag and a digest, it returns a digested reference. For example, the following |
|
| 91 |
+// reference: |
|
| 92 |
+// |
|
| 93 |
+// docker.io/library/busybox:latest@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa |
|
| 94 |
+// |
|
| 95 |
+// Is returned as a digested reference (with the ":latest" tag removed): |
|
| 96 |
+// |
|
| 97 |
+// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa |
|
| 98 |
+// |
|
| 99 |
+// References that are already "tagged" or "digested" are returned unmodified: |
|
| 100 |
+// |
|
| 101 |
+// // Already a digested reference |
|
| 102 |
+// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa |
|
| 103 |
+// |
|
| 104 |
+// // Already a named reference |
|
| 105 |
+// docker.io/library/busybox:latest |
|
| 106 |
+func ParseDockerRef(ref string) (Named, error) {
|
|
| 107 |
+ named, err := ParseNormalizedNamed(ref) |
|
| 108 |
+ if err != nil {
|
|
| 109 |
+ return nil, err |
|
| 110 |
+ } |
|
| 111 |
+ if canonical, ok := named.(namedTaggedDigested); ok {
|
|
| 112 |
+ // The reference is both tagged and digested; only return digested. |
|
| 113 |
+ newNamed, err := WithName(canonical.Name()) |
|
| 114 |
+ if err != nil {
|
|
| 115 |
+ return nil, err |
|
| 116 |
+ } |
|
| 117 |
+ return WithDigest(newNamed, canonical.Digest()) |
|
| 118 |
+ } |
|
| 119 |
+ return TagNameOnly(named), nil |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+// splitDockerDomain splits a repository name to domain and remote-name. |
|
| 123 |
+// If no valid domain is found, the default domain is used. Repository name |
|
| 124 |
+// needs to be already validated before. |
|
| 125 |
+func splitDockerDomain(name string) (domain, remainder string) {
|
|
| 126 |
+ i := strings.IndexRune(name, '/') |
|
| 127 |
+ if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != localhost && strings.ToLower(name[:i]) == name[:i]) {
|
|
| 128 |
+ domain, remainder = defaultDomain, name |
|
| 129 |
+ } else {
|
|
| 130 |
+ domain, remainder = name[:i], name[i+1:] |
|
| 131 |
+ } |
|
| 132 |
+ if domain == legacyDefaultDomain {
|
|
| 133 |
+ domain = defaultDomain |
|
| 134 |
+ } |
|
| 135 |
+ if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
|
|
| 136 |
+ remainder = officialRepoPrefix + remainder |
|
| 137 |
+ } |
|
| 138 |
+ return |
|
| 139 |
+} |
|
| 140 |
+ |
|
| 141 |
+// familiarizeName returns a shortened version of the name familiar |
|
| 142 |
+// to the Docker UI. Familiar names have the default domain |
|
| 143 |
+// "docker.io" and "library/" repository prefix removed. |
|
| 144 |
+// For example, "docker.io/library/redis" will have the familiar |
|
| 145 |
+// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp". |
|
| 146 |
+// Returns a familiarized named only reference. |
|
| 147 |
+func familiarizeName(named namedRepository) repository {
|
|
| 148 |
+ repo := repository{
|
|
| 149 |
+ domain: named.Domain(), |
|
| 150 |
+ path: named.Path(), |
|
| 151 |
+ } |
|
| 152 |
+ |
|
| 153 |
+ if repo.domain == defaultDomain {
|
|
| 154 |
+ repo.domain = "" |
|
| 155 |
+ // Handle official repositories which have the pattern "library/<official repo name>" |
|
| 156 |
+ if strings.HasPrefix(repo.path, officialRepoPrefix) {
|
|
| 157 |
+ // TODO(thaJeztah): this check may be too strict, as it assumes the |
|
| 158 |
+ // "library/" namespace does not have nested namespaces. While this |
|
| 159 |
+ // is true (currently), technically it would be possible for Docker |
|
| 160 |
+ // Hub to use those (e.g. "library/distros/ubuntu:latest"). |
|
| 161 |
+ // See https://github.com/distribution/distribution/pull/3769#issuecomment-1302031785. |
|
| 162 |
+ if remainder := strings.TrimPrefix(repo.path, officialRepoPrefix); !strings.ContainsRune(remainder, '/') {
|
|
| 163 |
+ repo.path = remainder |
|
| 164 |
+ } |
|
| 165 |
+ } |
|
| 166 |
+ } |
|
| 167 |
+ return repo |
|
| 168 |
+} |
|
| 169 |
+ |
|
| 170 |
+func (r reference) Familiar() Named {
|
|
| 171 |
+ return reference{
|
|
| 172 |
+ namedRepository: familiarizeName(r.namedRepository), |
|
| 173 |
+ tag: r.tag, |
|
| 174 |
+ digest: r.digest, |
|
| 175 |
+ } |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+func (r repository) Familiar() Named {
|
|
| 179 |
+ return familiarizeName(r) |
|
| 180 |
+} |
|
| 181 |
+ |
|
| 182 |
+func (t taggedReference) Familiar() Named {
|
|
| 183 |
+ return taggedReference{
|
|
| 184 |
+ namedRepository: familiarizeName(t.namedRepository), |
|
| 185 |
+ tag: t.tag, |
|
| 186 |
+ } |
|
| 187 |
+} |
|
| 188 |
+ |
|
| 189 |
+func (c canonicalReference) Familiar() Named {
|
|
| 190 |
+ return canonicalReference{
|
|
| 191 |
+ namedRepository: familiarizeName(c.namedRepository), |
|
| 192 |
+ digest: c.digest, |
|
| 193 |
+ } |
|
| 194 |
+} |
|
| 195 |
+ |
|
| 196 |
+// TagNameOnly adds the default tag "latest" to a reference if it only has |
|
| 197 |
+// a repo name. |
|
| 198 |
+func TagNameOnly(ref Named) Named {
|
|
| 199 |
+ if IsNameOnly(ref) {
|
|
| 200 |
+ namedTagged, err := WithTag(ref, defaultTag) |
|
| 201 |
+ if err != nil {
|
|
| 202 |
+ // Default tag must be valid, to create a NamedTagged |
|
| 203 |
+ // type with non-validated input the WithTag function |
|
| 204 |
+ // should be used instead |
|
| 205 |
+ panic(err) |
|
| 206 |
+ } |
|
| 207 |
+ return namedTagged |
|
| 208 |
+ } |
|
| 209 |
+ return ref |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+// ParseAnyReference parses a reference string as a possible identifier, |
|
| 213 |
+// full digest, or familiar name. |
|
| 214 |
+func ParseAnyReference(ref string) (Reference, error) {
|
|
| 215 |
+ if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
|
|
| 216 |
+ return digestReference("sha256:" + ref), nil
|
|
| 217 |
+ } |
|
| 218 |
+ if dgst, err := digest.Parse(ref); err == nil {
|
|
| 219 |
+ return digestReference(dgst), nil |
|
| 220 |
+ } |
|
| 221 |
+ |
|
| 222 |
+ return ParseNormalizedNamed(ref) |
|
| 223 |
+} |
| 0 | 224 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,436 @@ |
| 0 |
+// Package reference provides a general type to represent any way of referencing images within the registry. |
|
| 1 |
+// Its main purpose is to abstract tags and digests (content-addressable hash). |
|
| 2 |
+// |
|
| 3 |
+// Grammar |
|
| 4 |
+// |
|
| 5 |
+// reference := name [ ":" tag ] [ "@" digest ] |
|
| 6 |
+// name := [domain '/'] remote-name |
|
| 7 |
+// domain := host [':' port-number] |
|
| 8 |
+// host := domain-name | IPv4address | \[ IPv6address \] ; rfc3986 appendix-A |
|
| 9 |
+// domain-name := domain-component ['.' domain-component]* |
|
| 10 |
+// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ |
|
| 11 |
+// port-number := /[0-9]+/ |
|
| 12 |
+// path-component := alpha-numeric [separator alpha-numeric]* |
|
| 13 |
+// path (or "remote-name") := path-component ['/' path-component]* |
|
| 14 |
+// alpha-numeric := /[a-z0-9]+/ |
|
| 15 |
+// separator := /[_.]|__|[-]*/ |
|
| 16 |
+// |
|
| 17 |
+// tag := /[\w][\w.-]{0,127}/
|
|
| 18 |
+// |
|
| 19 |
+// digest := digest-algorithm ":" digest-hex |
|
| 20 |
+// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]* |
|
| 21 |
+// digest-algorithm-separator := /[+.-_]/ |
|
| 22 |
+// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ |
|
| 23 |
+// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
|
| 24 |
+// |
|
| 25 |
+// identifier := /[a-f0-9]{64}/
|
|
| 26 |
+package reference |
|
| 27 |
+ |
|
| 28 |
+import ( |
|
| 29 |
+ "errors" |
|
| 30 |
+ "fmt" |
|
| 31 |
+ "strings" |
|
| 32 |
+ |
|
| 33 |
+ "github.com/opencontainers/go-digest" |
|
| 34 |
+) |
|
| 35 |
+ |
|
| 36 |
+const ( |
|
| 37 |
+ // NameTotalLengthMax is the maximum total number of characters in a repository name. |
|
| 38 |
+ NameTotalLengthMax = 255 |
|
| 39 |
+) |
|
| 40 |
+ |
|
| 41 |
+var ( |
|
| 42 |
+ // ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference. |
|
| 43 |
+ ErrReferenceInvalidFormat = errors.New("invalid reference format")
|
|
| 44 |
+ |
|
| 45 |
+ // ErrTagInvalidFormat represents an error while trying to parse a string as a tag. |
|
| 46 |
+ ErrTagInvalidFormat = errors.New("invalid tag format")
|
|
| 47 |
+ |
|
| 48 |
+ // ErrDigestInvalidFormat represents an error while trying to parse a string as a tag. |
|
| 49 |
+ ErrDigestInvalidFormat = errors.New("invalid digest format")
|
|
| 50 |
+ |
|
| 51 |
+ // ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters. |
|
| 52 |
+ ErrNameContainsUppercase = errors.New("repository name must be lowercase")
|
|
| 53 |
+ |
|
| 54 |
+ // ErrNameEmpty is returned for empty, invalid repository names. |
|
| 55 |
+ ErrNameEmpty = errors.New("repository name must have at least one component")
|
|
| 56 |
+ |
|
| 57 |
+ // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. |
|
| 58 |
+ ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
|
|
| 59 |
+ |
|
| 60 |
+ // ErrNameNotCanonical is returned when a name is not canonical. |
|
| 61 |
+ ErrNameNotCanonical = errors.New("repository name must be canonical")
|
|
| 62 |
+) |
|
| 63 |
+ |
|
| 64 |
+// Reference is an opaque object reference identifier that may include |
|
| 65 |
+// modifiers such as a hostname, name, tag, and digest. |
|
| 66 |
+type Reference interface {
|
|
| 67 |
+ // String returns the full reference |
|
| 68 |
+ String() string |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+// Field provides a wrapper type for resolving correct reference types when |
|
| 72 |
+// working with encoding. |
|
| 73 |
+type Field struct {
|
|
| 74 |
+ reference Reference |
|
| 75 |
+} |
|
| 76 |
+ |
|
| 77 |
+// AsField wraps a reference in a Field for encoding. |
|
| 78 |
+func AsField(reference Reference) Field {
|
|
| 79 |
+ return Field{reference}
|
|
| 80 |
+} |
|
| 81 |
+ |
|
| 82 |
+// Reference unwraps the reference type from the field to |
|
| 83 |
+// return the Reference object. This object should be |
|
| 84 |
+// of the appropriate type to further check for different |
|
| 85 |
+// reference types. |
|
| 86 |
+func (f Field) Reference() Reference {
|
|
| 87 |
+ return f.reference |
|
| 88 |
+} |
|
| 89 |
+ |
|
| 90 |
+// MarshalText serializes the field to byte text which |
|
| 91 |
+// is the string of the reference. |
|
| 92 |
+func (f Field) MarshalText() (p []byte, err error) {
|
|
| 93 |
+ return []byte(f.reference.String()), nil |
|
| 94 |
+} |
|
| 95 |
+ |
|
| 96 |
+// UnmarshalText parses text bytes by invoking the |
|
| 97 |
+// reference parser to ensure the appropriately |
|
| 98 |
+// typed reference object is wrapped by field. |
|
| 99 |
+func (f *Field) UnmarshalText(p []byte) error {
|
|
| 100 |
+ r, err := Parse(string(p)) |
|
| 101 |
+ if err != nil {
|
|
| 102 |
+ return err |
|
| 103 |
+ } |
|
| 104 |
+ |
|
| 105 |
+ f.reference = r |
|
| 106 |
+ return nil |
|
| 107 |
+} |
|
| 108 |
+ |
|
| 109 |
+// Named is an object with a full name |
|
| 110 |
+type Named interface {
|
|
| 111 |
+ Reference |
|
| 112 |
+ Name() string |
|
| 113 |
+} |
|
| 114 |
+ |
|
| 115 |
+// Tagged is an object which has a tag |
|
| 116 |
+type Tagged interface {
|
|
| 117 |
+ Reference |
|
| 118 |
+ Tag() string |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+// NamedTagged is an object including a name and tag. |
|
| 122 |
+type NamedTagged interface {
|
|
| 123 |
+ Named |
|
| 124 |
+ Tag() string |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+// Digested is an object which has a digest |
|
| 128 |
+// in which it can be referenced by |
|
| 129 |
+type Digested interface {
|
|
| 130 |
+ Reference |
|
| 131 |
+ Digest() digest.Digest |
|
| 132 |
+} |
|
| 133 |
+ |
|
| 134 |
+// Canonical reference is an object with a fully unique |
|
| 135 |
+// name including a name with domain and digest |
|
| 136 |
+type Canonical interface {
|
|
| 137 |
+ Named |
|
| 138 |
+ Digest() digest.Digest |
|
| 139 |
+} |
|
| 140 |
+ |
|
| 141 |
+// namedRepository is a reference to a repository with a name. |
|
| 142 |
+// A namedRepository has both domain and path components. |
|
| 143 |
+type namedRepository interface {
|
|
| 144 |
+ Named |
|
| 145 |
+ Domain() string |
|
| 146 |
+ Path() string |
|
| 147 |
+} |
|
| 148 |
+ |
|
| 149 |
+// Domain returns the domain part of the [Named] reference. |
|
| 150 |
+func Domain(named Named) string {
|
|
| 151 |
+ if r, ok := named.(namedRepository); ok {
|
|
| 152 |
+ return r.Domain() |
|
| 153 |
+ } |
|
| 154 |
+ domain, _ := splitDomain(named.Name()) |
|
| 155 |
+ return domain |
|
| 156 |
+} |
|
| 157 |
+ |
|
| 158 |
+// Path returns the name without the domain part of the [Named] reference. |
|
| 159 |
+func Path(named Named) (name string) {
|
|
| 160 |
+ if r, ok := named.(namedRepository); ok {
|
|
| 161 |
+ return r.Path() |
|
| 162 |
+ } |
|
| 163 |
+ _, path := splitDomain(named.Name()) |
|
| 164 |
+ return path |
|
| 165 |
+} |
|
| 166 |
+ |
|
| 167 |
+func splitDomain(name string) (string, string) {
|
|
| 168 |
+ match := anchoredNameRegexp.FindStringSubmatch(name) |
|
| 169 |
+ if len(match) != 3 {
|
|
| 170 |
+ return "", name |
|
| 171 |
+ } |
|
| 172 |
+ return match[1], match[2] |
|
| 173 |
+} |
|
| 174 |
+ |
|
| 175 |
+// SplitHostname splits a named reference into a |
|
| 176 |
+// hostname and name string. If no valid hostname is |
|
| 177 |
+// found, the hostname is empty and the full value |
|
| 178 |
+// is returned as name |
|
| 179 |
+// |
|
| 180 |
+// Deprecated: Use [Domain] or [Path]. |
|
| 181 |
+func SplitHostname(named Named) (string, string) {
|
|
| 182 |
+ if r, ok := named.(namedRepository); ok {
|
|
| 183 |
+ return r.Domain(), r.Path() |
|
| 184 |
+ } |
|
| 185 |
+ return splitDomain(named.Name()) |
|
| 186 |
+} |
|
| 187 |
+ |
|
| 188 |
+// Parse parses s and returns a syntactically valid Reference. |
|
| 189 |
+// If an error was encountered it is returned, along with a nil Reference. |
|
| 190 |
+func Parse(s string) (Reference, error) {
|
|
| 191 |
+ matches := ReferenceRegexp.FindStringSubmatch(s) |
|
| 192 |
+ if matches == nil {
|
|
| 193 |
+ if s == "" {
|
|
| 194 |
+ return nil, ErrNameEmpty |
|
| 195 |
+ } |
|
| 196 |
+ if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil {
|
|
| 197 |
+ return nil, ErrNameContainsUppercase |
|
| 198 |
+ } |
|
| 199 |
+ return nil, ErrReferenceInvalidFormat |
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 202 |
+ if len(matches[1]) > NameTotalLengthMax {
|
|
| 203 |
+ return nil, ErrNameTooLong |
|
| 204 |
+ } |
|
| 205 |
+ |
|
| 206 |
+ var repo repository |
|
| 207 |
+ |
|
| 208 |
+ nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) |
|
| 209 |
+ if len(nameMatch) == 3 {
|
|
| 210 |
+ repo.domain = nameMatch[1] |
|
| 211 |
+ repo.path = nameMatch[2] |
|
| 212 |
+ } else {
|
|
| 213 |
+ repo.domain = "" |
|
| 214 |
+ repo.path = matches[1] |
|
| 215 |
+ } |
|
| 216 |
+ |
|
| 217 |
+ ref := reference{
|
|
| 218 |
+ namedRepository: repo, |
|
| 219 |
+ tag: matches[2], |
|
| 220 |
+ } |
|
| 221 |
+ if matches[3] != "" {
|
|
| 222 |
+ var err error |
|
| 223 |
+ ref.digest, err = digest.Parse(matches[3]) |
|
| 224 |
+ if err != nil {
|
|
| 225 |
+ return nil, err |
|
| 226 |
+ } |
|
| 227 |
+ } |
|
| 228 |
+ |
|
| 229 |
+ r := getBestReferenceType(ref) |
|
| 230 |
+ if r == nil {
|
|
| 231 |
+ return nil, ErrNameEmpty |
|
| 232 |
+ } |
|
| 233 |
+ |
|
| 234 |
+ return r, nil |
|
| 235 |
+} |
|
| 236 |
+ |
|
| 237 |
+// ParseNamed parses s and returns a syntactically valid reference implementing |
|
| 238 |
+// the Named interface. The reference must have a name and be in the canonical |
|
| 239 |
+// form, otherwise an error is returned. |
|
| 240 |
+// If an error was encountered it is returned, along with a nil Reference. |
|
| 241 |
+func ParseNamed(s string) (Named, error) {
|
|
| 242 |
+ named, err := ParseNormalizedNamed(s) |
|
| 243 |
+ if err != nil {
|
|
| 244 |
+ return nil, err |
|
| 245 |
+ } |
|
| 246 |
+ if named.String() != s {
|
|
| 247 |
+ return nil, ErrNameNotCanonical |
|
| 248 |
+ } |
|
| 249 |
+ return named, nil |
|
| 250 |
+} |
|
| 251 |
+ |
|
| 252 |
+// WithName returns a named object representing the given string. If the input |
|
| 253 |
+// is invalid ErrReferenceInvalidFormat will be returned. |
|
| 254 |
+func WithName(name string) (Named, error) {
|
|
| 255 |
+ if len(name) > NameTotalLengthMax {
|
|
| 256 |
+ return nil, ErrNameTooLong |
|
| 257 |
+ } |
|
| 258 |
+ |
|
| 259 |
+ match := anchoredNameRegexp.FindStringSubmatch(name) |
|
| 260 |
+ if match == nil || len(match) != 3 {
|
|
| 261 |
+ return nil, ErrReferenceInvalidFormat |
|
| 262 |
+ } |
|
| 263 |
+ return repository{
|
|
| 264 |
+ domain: match[1], |
|
| 265 |
+ path: match[2], |
|
| 266 |
+ }, nil |
|
| 267 |
+} |
|
| 268 |
+ |
|
| 269 |
+// WithTag combines the name from "name" and the tag from "tag" to form a |
|
| 270 |
+// reference incorporating both the name and the tag. |
|
| 271 |
+func WithTag(name Named, tag string) (NamedTagged, error) {
|
|
| 272 |
+ if !anchoredTagRegexp.MatchString(tag) {
|
|
| 273 |
+ return nil, ErrTagInvalidFormat |
|
| 274 |
+ } |
|
| 275 |
+ var repo repository |
|
| 276 |
+ if r, ok := name.(namedRepository); ok {
|
|
| 277 |
+ repo.domain = r.Domain() |
|
| 278 |
+ repo.path = r.Path() |
|
| 279 |
+ } else {
|
|
| 280 |
+ repo.path = name.Name() |
|
| 281 |
+ } |
|
| 282 |
+ if canonical, ok := name.(Canonical); ok {
|
|
| 283 |
+ return reference{
|
|
| 284 |
+ namedRepository: repo, |
|
| 285 |
+ tag: tag, |
|
| 286 |
+ digest: canonical.Digest(), |
|
| 287 |
+ }, nil |
|
| 288 |
+ } |
|
| 289 |
+ return taggedReference{
|
|
| 290 |
+ namedRepository: repo, |
|
| 291 |
+ tag: tag, |
|
| 292 |
+ }, nil |
|
| 293 |
+} |
|
| 294 |
+ |
|
| 295 |
+// WithDigest combines the name from "name" and the digest from "digest" to form |
|
| 296 |
+// a reference incorporating both the name and the digest. |
|
| 297 |
+func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
|
|
| 298 |
+ if !anchoredDigestRegexp.MatchString(digest.String()) {
|
|
| 299 |
+ return nil, ErrDigestInvalidFormat |
|
| 300 |
+ } |
|
| 301 |
+ var repo repository |
|
| 302 |
+ if r, ok := name.(namedRepository); ok {
|
|
| 303 |
+ repo.domain = r.Domain() |
|
| 304 |
+ repo.path = r.Path() |
|
| 305 |
+ } else {
|
|
| 306 |
+ repo.path = name.Name() |
|
| 307 |
+ } |
|
| 308 |
+ if tagged, ok := name.(Tagged); ok {
|
|
| 309 |
+ return reference{
|
|
| 310 |
+ namedRepository: repo, |
|
| 311 |
+ tag: tagged.Tag(), |
|
| 312 |
+ digest: digest, |
|
| 313 |
+ }, nil |
|
| 314 |
+ } |
|
| 315 |
+ return canonicalReference{
|
|
| 316 |
+ namedRepository: repo, |
|
| 317 |
+ digest: digest, |
|
| 318 |
+ }, nil |
|
| 319 |
+} |
|
| 320 |
+ |
|
| 321 |
+// TrimNamed removes any tag or digest from the named reference. |
|
| 322 |
+func TrimNamed(ref Named) Named {
|
|
| 323 |
+ repo := repository{}
|
|
| 324 |
+ if r, ok := ref.(namedRepository); ok {
|
|
| 325 |
+ repo.domain, repo.path = r.Domain(), r.Path() |
|
| 326 |
+ } else {
|
|
| 327 |
+ repo.domain, repo.path = splitDomain(ref.Name()) |
|
| 328 |
+ } |
|
| 329 |
+ return repo |
|
| 330 |
+} |
|
| 331 |
+ |
|
| 332 |
+func getBestReferenceType(ref reference) Reference {
|
|
| 333 |
+ if ref.Name() == "" {
|
|
| 334 |
+ // Allow digest only references |
|
| 335 |
+ if ref.digest != "" {
|
|
| 336 |
+ return digestReference(ref.digest) |
|
| 337 |
+ } |
|
| 338 |
+ return nil |
|
| 339 |
+ } |
|
| 340 |
+ if ref.tag == "" {
|
|
| 341 |
+ if ref.digest != "" {
|
|
| 342 |
+ return canonicalReference{
|
|
| 343 |
+ namedRepository: ref.namedRepository, |
|
| 344 |
+ digest: ref.digest, |
|
| 345 |
+ } |
|
| 346 |
+ } |
|
| 347 |
+ return ref.namedRepository |
|
| 348 |
+ } |
|
| 349 |
+ if ref.digest == "" {
|
|
| 350 |
+ return taggedReference{
|
|
| 351 |
+ namedRepository: ref.namedRepository, |
|
| 352 |
+ tag: ref.tag, |
|
| 353 |
+ } |
|
| 354 |
+ } |
|
| 355 |
+ |
|
| 356 |
+ return ref |
|
| 357 |
+} |
|
| 358 |
+ |
|
| 359 |
+type reference struct {
|
|
| 360 |
+ namedRepository |
|
| 361 |
+ tag string |
|
| 362 |
+ digest digest.Digest |
|
| 363 |
+} |
|
| 364 |
+ |
|
| 365 |
+func (r reference) String() string {
|
|
| 366 |
+ return r.Name() + ":" + r.tag + "@" + r.digest.String() |
|
| 367 |
+} |
|
| 368 |
+ |
|
| 369 |
+func (r reference) Tag() string {
|
|
| 370 |
+ return r.tag |
|
| 371 |
+} |
|
| 372 |
+ |
|
| 373 |
+func (r reference) Digest() digest.Digest {
|
|
| 374 |
+ return r.digest |
|
| 375 |
+} |
|
| 376 |
+ |
|
| 377 |
+type repository struct {
|
|
| 378 |
+ domain string |
|
| 379 |
+ path string |
|
| 380 |
+} |
|
| 381 |
+ |
|
| 382 |
+func (r repository) String() string {
|
|
| 383 |
+ return r.Name() |
|
| 384 |
+} |
|
| 385 |
+ |
|
| 386 |
+func (r repository) Name() string {
|
|
| 387 |
+ if r.domain == "" {
|
|
| 388 |
+ return r.path |
|
| 389 |
+ } |
|
| 390 |
+ return r.domain + "/" + r.path |
|
| 391 |
+} |
|
| 392 |
+ |
|
| 393 |
+func (r repository) Domain() string {
|
|
| 394 |
+ return r.domain |
|
| 395 |
+} |
|
| 396 |
+ |
|
| 397 |
+func (r repository) Path() string {
|
|
| 398 |
+ return r.path |
|
| 399 |
+} |
|
| 400 |
+ |
|
| 401 |
+type digestReference digest.Digest |
|
| 402 |
+ |
|
| 403 |
+func (d digestReference) String() string {
|
|
| 404 |
+ return digest.Digest(d).String() |
|
| 405 |
+} |
|
| 406 |
+ |
|
| 407 |
+func (d digestReference) Digest() digest.Digest {
|
|
| 408 |
+ return digest.Digest(d) |
|
| 409 |
+} |
|
| 410 |
+ |
|
| 411 |
+type taggedReference struct {
|
|
| 412 |
+ namedRepository |
|
| 413 |
+ tag string |
|
| 414 |
+} |
|
| 415 |
+ |
|
| 416 |
+func (t taggedReference) String() string {
|
|
| 417 |
+ return t.Name() + ":" + t.tag |
|
| 418 |
+} |
|
| 419 |
+ |
|
| 420 |
+func (t taggedReference) Tag() string {
|
|
| 421 |
+ return t.tag |
|
| 422 |
+} |
|
| 423 |
+ |
|
| 424 |
+type canonicalReference struct {
|
|
| 425 |
+ namedRepository |
|
| 426 |
+ digest digest.Digest |
|
| 427 |
+} |
|
| 428 |
+ |
|
| 429 |
+func (c canonicalReference) String() string {
|
|
| 430 |
+ return c.Name() + "@" + c.digest.String() |
|
| 431 |
+} |
|
| 432 |
+ |
|
| 433 |
+func (c canonicalReference) Digest() digest.Digest {
|
|
| 434 |
+ return c.digest |
|
| 435 |
+} |
| 0 | 436 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,163 @@ |
| 0 |
+package reference |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "regexp" |
|
| 4 |
+ "strings" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// DigestRegexp matches well-formed digests, including algorithm (e.g. "sha256:<encoded>"). |
|
| 8 |
+var DigestRegexp = regexp.MustCompile(digestPat) |
|
| 9 |
+ |
|
| 10 |
+// DomainRegexp matches hostname or IP-addresses, optionally including a port |
|
| 11 |
+// number. It defines the structure of potential domain components that may be |
|
| 12 |
+// part of image names. This is purposely a subset of what is allowed by DNS to |
|
| 13 |
+// ensure backwards compatibility with Docker image names. It may be a subset of |
|
| 14 |
+// DNS domain name, an IPv4 address in decimal format, or an IPv6 address between |
|
| 15 |
+// square brackets (excluding zone identifiers as defined by [RFC 6874] or special |
|
| 16 |
+// addresses such as IPv4-Mapped). |
|
| 17 |
+// |
|
| 18 |
+// [RFC 6874]: https://www.rfc-editor.org/rfc/rfc6874. |
|
| 19 |
+var DomainRegexp = regexp.MustCompile(domainAndPort) |
|
| 20 |
+ |
|
| 21 |
+// IdentifierRegexp is the format for string identifier used as a |
|
| 22 |
+// content addressable identifier using sha256. These identifiers |
|
| 23 |
+// are like digests without the algorithm, since sha256 is used. |
|
| 24 |
+var IdentifierRegexp = regexp.MustCompile(identifier) |
|
| 25 |
+ |
|
| 26 |
+// NameRegexp is the format for the name component of references, including |
|
| 27 |
+// an optional domain and port, but without tag or digest suffix. |
|
| 28 |
+var NameRegexp = regexp.MustCompile(namePat) |
|
| 29 |
+ |
|
| 30 |
+// ReferenceRegexp is the full supported format of a reference. The regexp |
|
| 31 |
+// is anchored and has capturing groups for name, tag, and digest |
|
| 32 |
+// components. |
|
| 33 |
+var ReferenceRegexp = regexp.MustCompile(referencePat) |
|
| 34 |
+ |
|
| 35 |
+// TagRegexp matches valid tag names. From [docker/docker:graph/tags.go]. |
|
| 36 |
+// |
|
| 37 |
+// [docker/docker:graph/tags.go]: https://github.com/moby/moby/blob/v1.6.0/graph/tags.go#L26-L28 |
|
| 38 |
+var TagRegexp = regexp.MustCompile(tag) |
|
| 39 |
+ |
|
| 40 |
+const ( |
|
| 41 |
+ // alphanumeric defines the alphanumeric atom, typically a |
|
| 42 |
+ // component of names. This only allows lower case characters and digits. |
|
| 43 |
+ alphanumeric = `[a-z0-9]+` |
|
| 44 |
+ |
|
| 45 |
+ // separator defines the separators allowed to be embedded in name |
|
| 46 |
+ // components. This allows one period, one or two underscore and multiple |
|
| 47 |
+ // dashes. Repeated dashes and underscores are intentionally treated |
|
| 48 |
+ // differently. In order to support valid hostnames as name components, |
|
| 49 |
+ // supporting repeated dash was added. Additionally double underscore is |
|
| 50 |
+ // now allowed as a separator to loosen the restriction for previously |
|
| 51 |
+ // supported names. |
|
| 52 |
+ separator = `(?:[._]|__|[-]+)` |
|
| 53 |
+ |
|
| 54 |
+ // localhost is treated as a special value for domain-name. Any other |
|
| 55 |
+ // domain-name without a "." or a ":port" are considered a path component. |
|
| 56 |
+ localhost = `localhost` |
|
| 57 |
+ |
|
| 58 |
+ // domainNameComponent restricts the registry domain component of a |
|
| 59 |
+ // repository name to start with a component as defined by DomainRegexp. |
|
| 60 |
+ domainNameComponent = `(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])` |
|
| 61 |
+ |
|
| 62 |
+ // optionalPort matches an optional port-number including the port separator |
|
| 63 |
+ // (e.g. ":80"). |
|
| 64 |
+ optionalPort = `(?::[0-9]+)?` |
|
| 65 |
+ |
|
| 66 |
+ // tag matches valid tag names. From docker/docker:graph/tags.go. |
|
| 67 |
+ tag = `[\w][\w.-]{0,127}`
|
|
| 68 |
+ |
|
| 69 |
+ // digestPat matches well-formed digests, including algorithm (e.g. "sha256:<encoded>"). |
|
| 70 |
+ // |
|
| 71 |
+ // TODO(thaJeztah): this should follow the same rules as https://pkg.go.dev/github.com/opencontainers/go-digest@v1.0.0#DigestRegexp |
|
| 72 |
+ // so that go-digest defines the canonical format. Note that the go-digest is |
|
| 73 |
+ // more relaxed: |
|
| 74 |
+ // - it allows multiple algorithms (e.g. "sha256+b64:<encoded>") to allow |
|
| 75 |
+ // future expansion of supported algorithms. |
|
| 76 |
+ // - it allows the "<encoded>" value to use urlsafe base64 encoding as defined |
|
| 77 |
+ // in [rfc4648, section 5]. |
|
| 78 |
+ // |
|
| 79 |
+ // [rfc4648, section 5]: https://www.rfc-editor.org/rfc/rfc4648#section-5. |
|
| 80 |
+ digestPat = `[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`
|
|
| 81 |
+ |
|
| 82 |
+ // identifier is the format for a content addressable identifier using sha256. |
|
| 83 |
+ // These identifiers are like digests without the algorithm, since sha256 is used. |
|
| 84 |
+ identifier = `([a-f0-9]{64})`
|
|
| 85 |
+ |
|
| 86 |
+ // ipv6address are enclosed between square brackets and may be represented |
|
| 87 |
+ // in many ways, see rfc5952. Only IPv6 in compressed or uncompressed format |
|
| 88 |
+ // are allowed, IPv6 zone identifiers (rfc6874) or Special addresses such as |
|
| 89 |
+ // IPv4-Mapped are deliberately excluded. |
|
| 90 |
+ ipv6address = `\[(?:[a-fA-F0-9:]+)\]` |
|
| 91 |
+) |
|
| 92 |
+ |
|
| 93 |
+var ( |
|
| 94 |
+ // domainName defines the structure of potential domain components |
|
| 95 |
+ // that may be part of image names. This is purposely a subset of what is |
|
| 96 |
+ // allowed by DNS to ensure backwards compatibility with Docker image |
|
| 97 |
+ // names. This includes IPv4 addresses on decimal format. |
|
| 98 |
+ domainName = domainNameComponent + anyTimes(`\.`+domainNameComponent) |
|
| 99 |
+ |
|
| 100 |
+ // host defines the structure of potential domains based on the URI |
|
| 101 |
+ // Host subcomponent on rfc3986. It may be a subset of DNS domain name, |
|
| 102 |
+ // or an IPv4 address in decimal format, or an IPv6 address between square |
|
| 103 |
+ // brackets (excluding zone identifiers as defined by rfc6874 or special |
|
| 104 |
+ // addresses such as IPv4-Mapped). |
|
| 105 |
+ host = `(?:` + domainName + `|` + ipv6address + `)` |
|
| 106 |
+ |
|
| 107 |
+ // allowed by the URI Host subcomponent on rfc3986 to ensure backwards |
|
| 108 |
+ // compatibility with Docker image names. |
|
| 109 |
+ domainAndPort = host + optionalPort |
|
| 110 |
+ |
|
| 111 |
+ // anchoredTagRegexp matches valid tag names, anchored at the start and |
|
| 112 |
+ // end of the matched string. |
|
| 113 |
+ anchoredTagRegexp = regexp.MustCompile(anchored(tag)) |
|
| 114 |
+ |
|
| 115 |
+ // anchoredDigestRegexp matches valid digests, anchored at the start and |
|
| 116 |
+ // end of the matched string. |
|
| 117 |
+ anchoredDigestRegexp = regexp.MustCompile(anchored(digestPat)) |
|
| 118 |
+ |
|
| 119 |
+ // pathComponent restricts path-components to start with an alphanumeric |
|
| 120 |
+ // character, with following parts able to be separated by a separator |
|
| 121 |
+ // (one period, one or two underscore and multiple dashes). |
|
| 122 |
+ pathComponent = alphanumeric + anyTimes(separator+alphanumeric) |
|
| 123 |
+ |
|
| 124 |
+ // remoteName matches the remote-name of a repository. It consists of one |
|
| 125 |
+ // or more forward slash (/) delimited path-components: |
|
| 126 |
+ // |
|
| 127 |
+ // pathComponent[[/pathComponent] ...] // e.g., "library/ubuntu" |
|
| 128 |
+ remoteName = pathComponent + anyTimes(`/`+pathComponent) |
|
| 129 |
+ namePat = optional(domainAndPort+`/`) + remoteName |
|
| 130 |
+ |
|
| 131 |
+ // anchoredNameRegexp is used to parse a name value, capturing the |
|
| 132 |
+ // domain and trailing components. |
|
| 133 |
+ anchoredNameRegexp = regexp.MustCompile(anchored(optional(capture(domainAndPort), `/`), capture(remoteName))) |
|
| 134 |
+ |
|
| 135 |
+ referencePat = anchored(capture(namePat), optional(`:`, capture(tag)), optional(`@`, capture(digestPat))) |
|
| 136 |
+ |
|
| 137 |
+ // anchoredIdentifierRegexp is used to check or match an |
|
| 138 |
+ // identifier value, anchored at start and end of string. |
|
| 139 |
+ anchoredIdentifierRegexp = regexp.MustCompile(anchored(identifier)) |
|
| 140 |
+) |
|
| 141 |
+ |
|
| 142 |
+// optional wraps the expression in a non-capturing group and makes the |
|
| 143 |
+// production optional. |
|
| 144 |
+func optional(res ...string) string {
|
|
| 145 |
+ return `(?:` + strings.Join(res, "") + `)?` |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 148 |
+// anyTimes wraps the expression in a non-capturing group that can occur |
|
| 149 |
+// any number of times. |
|
| 150 |
+func anyTimes(res ...string) string {
|
|
| 151 |
+ return `(?:` + strings.Join(res, "") + `)*` |
|
| 152 |
+} |
|
| 153 |
+ |
|
| 154 |
+// capture wraps the expression in a capturing group. |
|
| 155 |
+func capture(res ...string) string {
|
|
| 156 |
+ return `(` + strings.Join(res, "") + `)` |
|
| 157 |
+} |
|
| 158 |
+ |
|
| 159 |
+// anchored anchors the regular expression by adding start and end delimiters. |
|
| 160 |
+func anchored(res ...string) string {
|
|
| 161 |
+ return `^` + strings.Join(res, "") + `$` |
|
| 162 |
+} |
| 0 | 163 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,75 @@ |
| 0 |
+/* |
|
| 1 |
+ Copyright The containerd Authors. |
|
| 2 |
+ |
|
| 3 |
+ Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 4 |
+ you may not use this file except in compliance with the License. |
|
| 5 |
+ You may obtain a copy of the License at |
|
| 6 |
+ |
|
| 7 |
+ http://www.apache.org/licenses/LICENSE-2.0 |
|
| 8 |
+ |
|
| 9 |
+ Unless required by applicable law or agreed to in writing, software |
|
| 10 |
+ distributed under the License is distributed on an "AS IS" BASIS, |
|
| 11 |
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 12 |
+ See the License for the specific language governing permissions and |
|
| 13 |
+ limitations under the License. |
|
| 14 |
+*/ |
|
| 15 |
+ |
|
| 16 |
+package reference |
|
| 17 |
+ |
|
| 18 |
+import ( |
|
| 19 |
+ "sort" |
|
| 20 |
+) |
|
| 21 |
+ |
|
| 22 |
+// Sort sorts string references preferring higher information references. |
|
| 23 |
+// |
|
| 24 |
+// The precedence is as follows: |
|
| 25 |
+// |
|
| 26 |
+// 1. [Named] + [Tagged] + [Digested] (e.g., "docker.io/library/busybox:latest@sha256:<digest>") |
|
| 27 |
+// 2. [Named] + [Tagged] (e.g., "docker.io/library/busybox:latest") |
|
| 28 |
+// 3. [Named] + [Digested] (e.g., "docker.io/library/busybo@sha256:<digest>") |
|
| 29 |
+// 4. [Named] (e.g., "docker.io/library/busybox") |
|
| 30 |
+// 5. [Digested] (e.g., "docker.io@sha256:<digest>") |
|
| 31 |
+// 6. Parse error |
|
| 32 |
+func Sort(references []string) []string {
|
|
| 33 |
+ var prefs []Reference |
|
| 34 |
+ var bad []string |
|
| 35 |
+ |
|
| 36 |
+ for _, ref := range references {
|
|
| 37 |
+ pref, err := ParseAnyReference(ref) |
|
| 38 |
+ if err != nil {
|
|
| 39 |
+ bad = append(bad, ref) |
|
| 40 |
+ } else {
|
|
| 41 |
+ prefs = append(prefs, pref) |
|
| 42 |
+ } |
|
| 43 |
+ } |
|
| 44 |
+ sort.Slice(prefs, func(a, b int) bool {
|
|
| 45 |
+ ar := refRank(prefs[a]) |
|
| 46 |
+ br := refRank(prefs[b]) |
|
| 47 |
+ if ar == br {
|
|
| 48 |
+ return prefs[a].String() < prefs[b].String() |
|
| 49 |
+ } |
|
| 50 |
+ return ar < br |
|
| 51 |
+ }) |
|
| 52 |
+ sort.Strings(bad) |
|
| 53 |
+ var refs []string |
|
| 54 |
+ for _, pref := range prefs {
|
|
| 55 |
+ refs = append(refs, pref.String()) |
|
| 56 |
+ } |
|
| 57 |
+ return append(refs, bad...) |
|
| 58 |
+} |
|
| 59 |
+ |
|
| 60 |
+func refRank(ref Reference) uint8 {
|
|
| 61 |
+ if _, ok := ref.(Named); ok {
|
|
| 62 |
+ if _, ok = ref.(Tagged); ok {
|
|
| 63 |
+ if _, ok = ref.(Digested); ok {
|
|
| 64 |
+ return 1 |
|
| 65 |
+ } |
|
| 66 |
+ return 2 |
|
| 67 |
+ } |
|
| 68 |
+ if _, ok = ref.(Digested); ok {
|
|
| 69 |
+ return 3 |
|
| 70 |
+ } |
|
| 71 |
+ return 4 |
|
| 72 |
+ } |
|
| 73 |
+ return 5 |
|
| 74 |
+} |
| ... | ... |
@@ -386,6 +386,9 @@ github.com/deckarep/golang-set/v2 |
| 386 | 386 |
# github.com/dimchansky/utfbom v1.1.1 |
| 387 | 387 |
## explicit |
| 388 | 388 |
github.com/dimchansky/utfbom |
| 389 |
+# github.com/distribution/reference v0.5.0 |
|
| 390 |
+## explicit; go 1.20 |
|
| 391 |
+github.com/distribution/reference |
|
| 389 | 392 |
# github.com/docker/distribution v2.8.2+incompatible |
| 390 | 393 |
## explicit |
| 391 | 394 |
github.com/docker/distribution |