mirror of
https://github.com/moby/moby.git
synced 2025-08-01 05:47:11 +03:00
Merge pull request #30043 from dmcgowan/distribution-reference-update-1
Distribution reference update
This commit is contained in:
@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
networktypes "github.com/docker/docker/api/types/network"
|
networktypes "github.com/docker/docker/api/types/network"
|
||||||
@ -13,8 +14,6 @@ import (
|
|||||||
"github.com/docker/docker/cli/command/image"
|
"github.com/docker/docker/cli/command/image"
|
||||||
apiclient "github.com/docker/docker/client"
|
apiclient "github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
// FIXME migrate to docker/distribution/reference
|
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
@ -72,7 +71,7 @@ func runCreate(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *createO
|
|||||||
}
|
}
|
||||||
|
|
||||||
func pullImage(ctx context.Context, dockerCli *command.DockerCli, image string, out io.Writer) error {
|
func pullImage(ctx context.Context, dockerCli *command.DockerCli, image string, out io.Writer) error {
|
||||||
ref, err := reference.ParseNamed(image)
|
ref, err := reference.ParseNormalizedNamed(image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -150,7 +149,12 @@ func newCIDFile(path string) (*cidFile, error) {
|
|||||||
func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *container.Config, hostConfig *container.HostConfig, networkingConfig *networktypes.NetworkingConfig, cidfile, name string) (*container.ContainerCreateCreatedBody, error) {
|
func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *container.Config, hostConfig *container.HostConfig, networkingConfig *networktypes.NetworkingConfig, cidfile, name string) (*container.ContainerCreateCreatedBody, error) {
|
||||||
stderr := dockerCli.Err()
|
stderr := dockerCli.Err()
|
||||||
|
|
||||||
var containerIDFile *cidFile
|
var (
|
||||||
|
containerIDFile *cidFile
|
||||||
|
trustedRef reference.Canonical
|
||||||
|
namedRef reference.Named
|
||||||
|
)
|
||||||
|
|
||||||
if cidfile != "" {
|
if cidfile != "" {
|
||||||
var err error
|
var err error
|
||||||
if containerIDFile, err = newCIDFile(cidfile); err != nil {
|
if containerIDFile, err = newCIDFile(cidfile); err != nil {
|
||||||
@ -159,21 +163,24 @@ func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *
|
|||||||
defer containerIDFile.Close()
|
defer containerIDFile.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
var trustedRef reference.Canonical
|
ref, err := reference.ParseAnyReference(config.Image)
|
||||||
_, ref, err := reference.ParseIDOrReference(config.Image)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if ref != nil {
|
if named, ok := ref.(reference.Named); ok {
|
||||||
ref = reference.WithDefaultTag(ref)
|
if reference.IsNameOnly(named) {
|
||||||
|
namedRef = reference.EnsureTagged(named)
|
||||||
|
} else {
|
||||||
|
namedRef = named
|
||||||
|
}
|
||||||
|
|
||||||
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
|
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && command.IsTrusted() {
|
||||||
var err error
|
var err error
|
||||||
trustedRef, err = image.TrustedReference(ctx, dockerCli, ref, nil)
|
trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.Image = trustedRef.String()
|
config.Image = reference.FamiliarString(trustedRef)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,15 +189,15 @@ func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *
|
|||||||
|
|
||||||
//if image not found try to pull it
|
//if image not found try to pull it
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apiclient.IsErrImageNotFound(err) && ref != nil {
|
if apiclient.IsErrImageNotFound(err) && namedRef != nil {
|
||||||
fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", ref.String())
|
fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
|
||||||
|
|
||||||
// we don't want to write to stdout anything apart from container.ID
|
// we don't want to write to stdout anything apart from container.ID
|
||||||
if err = pullImage(ctx, dockerCli, config.Image, stderr); err != nil {
|
if err = pullImage(ctx, dockerCli, config.Image, stderr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if ref, ok := ref.(reference.NamedTagged); ok && trustedRef != nil {
|
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {
|
||||||
if err := image.TagTrusted(ctx, dockerCli, trustedRef, ref); err != nil {
|
if err := image.TagTrusted(ctx, dockerCli, trustedRef, taggedRef); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -95,21 +95,23 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC
|
|||||||
repoDigests := map[string][]string{}
|
repoDigests := map[string][]string{}
|
||||||
|
|
||||||
for _, refString := range append(image.RepoTags) {
|
for _, refString := range append(image.RepoTags) {
|
||||||
ref, err := reference.ParseNamed(refString)
|
ref, err := reference.ParseNormalizedNamed(refString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if nt, ok := ref.(reference.NamedTagged); ok {
|
if nt, ok := ref.(reference.NamedTagged); ok {
|
||||||
repoTags[ref.Name()] = append(repoTags[ref.Name()], nt.Tag())
|
familiarRef := reference.FamiliarName(ref)
|
||||||
|
repoTags[familiarRef] = append(repoTags[familiarRef], nt.Tag())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, refString := range append(image.RepoDigests) {
|
for _, refString := range append(image.RepoDigests) {
|
||||||
ref, err := reference.ParseNamed(refString)
|
ref, err := reference.ParseNormalizedNamed(refString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c, ok := ref.(reference.Canonical); ok {
|
if c, ok := ref.(reference.Canonical); ok {
|
||||||
repoDigests[ref.Name()] = append(repoDigests[ref.Name()], c.Digest().String())
|
familiarRef := reference.FamiliarName(ref)
|
||||||
|
repoDigests[familiarRef] = append(repoDigests[familiarRef], c.Digest().String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
@ -25,7 +26,6 @@ import (
|
|||||||
"github.com/docker/docker/pkg/progress"
|
"github.com/docker/docker/pkg/progress"
|
||||||
"github.com/docker/docker/pkg/streamformatter"
|
"github.com/docker/docker/pkg/streamformatter"
|
||||||
"github.com/docker/docker/pkg/urlutil"
|
"github.com/docker/docker/pkg/urlutil"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
runconfigopts "github.com/docker/docker/runconfig/opts"
|
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -360,7 +360,7 @@ type translatorFunc func(context.Context, reference.NamedTagged) (reference.Cano
|
|||||||
|
|
||||||
// validateTag checks if the given image name can be resolved.
|
// validateTag checks if the given image name can be resolved.
|
||||||
func validateTag(rawRepo string) (string, error) {
|
func validateTag(rawRepo string) (string, error) {
|
||||||
_, err := reference.ParseNamed(rawRepo)
|
_, err := reference.ParseNormalizedNamed(rawRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -392,18 +392,21 @@ func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator
|
|||||||
matches := dockerfileFromLinePattern.FindStringSubmatch(line)
|
matches := dockerfileFromLinePattern.FindStringSubmatch(line)
|
||||||
if matches != nil && matches[1] != api.NoBaseImageSpecifier {
|
if matches != nil && matches[1] != api.NoBaseImageSpecifier {
|
||||||
// Replace the line with a resolved "FROM repo@digest"
|
// Replace the line with a resolved "FROM repo@digest"
|
||||||
ref, err := reference.ParseNamed(matches[1])
|
var ref reference.Named
|
||||||
|
ref, err = reference.ParseNormalizedNamed(matches[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
ref = reference.WithDefaultTag(ref)
|
if reference.IsNameOnly(ref) {
|
||||||
|
ref = reference.EnsureTagged(ref)
|
||||||
|
}
|
||||||
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
|
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
|
||||||
trustedRef, err := translator(ctx, ref)
|
trustedRef, err := translator(ctx, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", trustedRef.String()))
|
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", reference.FamiliarString(trustedRef)))
|
||||||
resolvedTags = append(resolvedTags, &resolvedTag{
|
resolvedTags = append(resolvedTags, &resolvedTag{
|
||||||
digestRef: trustedRef,
|
digestRef: trustedRef,
|
||||||
tagRef: ref,
|
tagRef: ref,
|
||||||
|
@ -7,9 +7,9 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -42,7 +42,8 @@ func NewPullCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
|
func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
|
||||||
distributionRef, err := reference.ParseNamed(opts.remote)
|
var distributionRef reference.Named
|
||||||
|
distributionRef, err := reference.ParseNormalizedNamed(opts.remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -51,8 +52,9 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !opts.all && reference.IsNameOnly(distributionRef) {
|
if !opts.all && reference.IsNameOnly(distributionRef) {
|
||||||
distributionRef = reference.WithDefaultTag(distributionRef)
|
taggedRef := reference.EnsureTagged(distributionRef)
|
||||||
fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", reference.DefaultTag)
|
fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", taggedRef.Tag())
|
||||||
|
distributionRef = taggedRef
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve the Repository name from fqn to RepositoryInfo
|
// Resolve the Repository name from fqn to RepositoryInfo
|
||||||
@ -71,7 +73,7 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
|
|||||||
if command.IsTrusted() && !isCanonical {
|
if command.IsTrusted() && !isCanonical {
|
||||||
err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege)
|
err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege)
|
||||||
} else {
|
} else {
|
||||||
err = imagePullPrivileged(ctx, dockerCli, authConfig, distributionRef.String(), requestPrivilege, opts.all)
|
err = imagePullPrivileged(ctx, dockerCli, authConfig, reference.FamiliarString(distributionRef), requestPrivilege, opts.all)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "target is plugin") {
|
if strings.Contains(err.Error(), "target is plugin") {
|
||||||
|
@ -3,10 +3,10 @@ package image
|
|||||||
import (
|
import (
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -30,7 +30,7 @@ func NewPushCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runPush(dockerCli *command.DockerCli, remote string) error {
|
func runPush(dockerCli *command.DockerCli, remote string) error {
|
||||||
ref, err := reference.ParseNamed(remote)
|
ref, err := reference.ParseNormalizedNamed(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ func runPush(dockerCli *command.DockerCli, remote string) error {
|
|||||||
return trustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)
|
return trustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)
|
||||||
}
|
}
|
||||||
|
|
||||||
responseBody, err := imagePushPrivileged(ctx, dockerCli, authConfig, ref.String(), requestPrivilege)
|
responseBody, err := imagePushPrivileged(ctx, dockerCli, authConfig, ref, requestPrivilege)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/cli/trust"
|
"github.com/docker/docker/cli/trust"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/docker/notary/client"
|
"github.com/docker/notary/client"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
@ -30,7 +30,7 @@ type target struct {
|
|||||||
|
|
||||||
// trustedPush handles content trust pushing of an image
|
// trustedPush handles content trust pushing of an image
|
||||||
func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
|
func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
|
||||||
responseBody, err := imagePushPrivileged(ctx, cli, authConfig, ref.String(), requestPrivilege)
|
responseBody, err := imagePushPrivileged(ctx, cli, authConfig, ref, requestPrivilege)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -202,7 +202,7 @@ func addTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.T
|
|||||||
}
|
}
|
||||||
|
|
||||||
// imagePushPrivileged push the image
|
// imagePushPrivileged push the image
|
||||||
func imagePushPrivileged(ctx context.Context, cli *command.DockerCli, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc) (io.ReadCloser, error) {
|
func imagePushPrivileged(ctx context.Context, cli *command.DockerCli, authConfig types.AuthConfig, ref reference.Named, requestPrivilege types.RequestPrivilegeFunc) (io.ReadCloser, error) {
|
||||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -212,7 +212,7 @@ func imagePushPrivileged(ctx context.Context, cli *command.DockerCli, authConfig
|
|||||||
PrivilegeFunc: requestPrivilege,
|
PrivilegeFunc: requestPrivilege,
|
||||||
}
|
}
|
||||||
|
|
||||||
return cli.Client().ImagePush(ctx, ref, options)
|
return cli.Client().ImagePush(ctx, reference.FamiliarString(ref), options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// trustedPull handles content trust pulling of an image
|
// trustedPull handles content trust pulling of an image
|
||||||
@ -229,12 +229,12 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry
|
|||||||
// List all targets
|
// List all targets
|
||||||
targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
|
targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return trust.NotaryError(repoInfo.FullName(), err)
|
return trust.NotaryError(ref.Name(), err)
|
||||||
}
|
}
|
||||||
for _, tgt := range targets {
|
for _, tgt := range targets {
|
||||||
t, err := convertTarget(tgt.Target)
|
t, err := convertTarget(tgt.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", repoInfo.Name())
|
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", reference.FamiliarName(ref))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Only list tags in the top level targets role or the releases delegation role - ignore
|
// Only list tags in the top level targets role or the releases delegation role - ignore
|
||||||
@ -245,17 +245,17 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry
|
|||||||
refs = append(refs, t)
|
refs = append(refs, t)
|
||||||
}
|
}
|
||||||
if len(refs) == 0 {
|
if len(refs) == 0 {
|
||||||
return trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trusted tags for %s", repoInfo.FullName()))
|
return trust.NotaryError(ref.Name(), fmt.Errorf("No trusted tags for %s", ref.Name()))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
|
t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return trust.NotaryError(repoInfo.FullName(), err)
|
return trust.NotaryError(ref.Name(), err)
|
||||||
}
|
}
|
||||||
// Only get the tag if it's in the top level targets role or the releases delegation role
|
// Only get the tag if it's in the top level targets role or the releases delegation role
|
||||||
// ignore it if it's in any other delegation roles
|
// ignore it if it's in any other delegation roles
|
||||||
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
||||||
return trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", tagged.Tag()))
|
return trust.NotaryError(ref.Name(), fmt.Errorf("No trust data for %s", tagged.Tag()))
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("retrieving target for %s role\n", t.Role)
|
logrus.Debugf("retrieving target for %s role\n", t.Role)
|
||||||
@ -272,24 +272,21 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry
|
|||||||
if displayTag != "" {
|
if displayTag != "" {
|
||||||
displayTag = ":" + displayTag
|
displayTag = ":" + displayTag
|
||||||
}
|
}
|
||||||
fmt.Fprintf(cli.Out(), "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), repoInfo.Name(), displayTag, r.digest)
|
fmt.Fprintf(cli.Out(), "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), reference.FamiliarName(ref), displayTag, r.digest)
|
||||||
|
|
||||||
ref, err := reference.WithDigest(reference.TrimNamed(repoInfo), r.digest)
|
trustedRef, err := reference.WithDigest(reference.TrimNamed(ref), r.digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := imagePullPrivileged(ctx, cli, authConfig, ref.String(), requestPrivilege, false); err != nil {
|
if err := imagePullPrivileged(ctx, cli, authConfig, reference.FamiliarString(trustedRef), requestPrivilege, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tagged, err := reference.WithTag(repoInfo, r.name)
|
tagged, err := reference.WithTag(reference.TrimNamed(ref), r.name)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
trustedRef, err := reference.WithDigest(reference.TrimNamed(repoInfo), r.digest)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := TagTrusted(ctx, cli, trustedRef, tagged); err != nil {
|
if err := TagTrusted(ctx, cli, trustedRef, tagged); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -375,7 +372,11 @@ func convertTarget(t client.Target) (target, error) {
|
|||||||
|
|
||||||
// TagTrusted tags a trusted ref
|
// TagTrusted tags a trusted ref
|
||||||
func TagTrusted(ctx context.Context, cli *command.DockerCli, trustedRef reference.Canonical, ref reference.NamedTagged) error {
|
func TagTrusted(ctx context.Context, cli *command.DockerCli, trustedRef reference.Canonical, ref reference.NamedTagged) error {
|
||||||
fmt.Fprintf(cli.Out(), "Tagging %s as %s\n", trustedRef.String(), ref.String())
|
// Use familiar references when interacting with client and output
|
||||||
|
familiarRef := reference.FamiliarString(ref)
|
||||||
|
trustedFamiliarRef := reference.FamiliarString(trustedRef)
|
||||||
|
|
||||||
return cli.Client().ImageTag(ctx, trustedRef.String(), ref.String())
|
fmt.Fprintf(cli.Out(), "Tagging %s as %s\n", trustedFamiliarRef, familiarRef)
|
||||||
|
|
||||||
|
return cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef)
|
||||||
}
|
}
|
||||||
|
@ -8,18 +8,18 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// validateTag checks if the given repoName can be resolved.
|
// validateTag checks if the given repoName can be resolved.
|
||||||
func validateTag(rawRepo string) error {
|
func validateTag(rawRepo string) error {
|
||||||
_, err := reference.ParseNamed(rawRepo)
|
_, err := reference.ParseNormalizedNamed(rawRepo)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -6,14 +6,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
distreference "github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/cli/command/image"
|
"github.com/docker/docker/cli/command/image"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
@ -52,8 +51,8 @@ func newInstallCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRepoIndexFromUnnormalizedRef(ref distreference.Named) (*registrytypes.IndexInfo, error) {
|
func getRepoIndexFromUnnormalizedRef(ref reference.Named) (*registrytypes.IndexInfo, error) {
|
||||||
named, err := reference.ParseNamed(ref.Name())
|
named, err := reference.ParseNormalizedNamed(ref.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -85,71 +84,60 @@ func newRegistryService() registry.Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
|
func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
|
||||||
// Parse name using distribution reference package to support name
|
// Names with both tag and digest will be treated by the daemon
|
||||||
// containing both tag and digest. Names with both tag and digest
|
// as a pull by digest with an alias for the tag
|
||||||
// will be treated by the daemon as a pull by digest with
|
// (if no alias is provided).
|
||||||
// an alias for the tag (if no alias is provided).
|
ref, err := reference.ParseNormalizedNamed(opts.name)
|
||||||
ref, err := distreference.ParseNamed(opts.name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
alias := ""
|
alias := ""
|
||||||
if opts.alias != "" {
|
if opts.alias != "" {
|
||||||
aref, err := reference.ParseNamed(opts.alias)
|
aref, err := reference.ParseNormalizedNamed(opts.alias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
aref = reference.WithDefaultTag(aref)
|
if _, ok := aref.(reference.Canonical); ok {
|
||||||
if _, ok := aref.(reference.NamedTagged); !ok {
|
|
||||||
return fmt.Errorf("invalid name: %s", opts.alias)
|
return fmt.Errorf("invalid name: %s", opts.alias)
|
||||||
}
|
}
|
||||||
alias = aref.String()
|
alias = reference.FamiliarString(reference.EnsureTagged(aref))
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
index, err := getRepoIndexFromUnnormalizedRef(ref)
|
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
remote := ref.String()
|
remote := ref.String()
|
||||||
|
|
||||||
_, isCanonical := ref.(distreference.Canonical)
|
_, isCanonical := ref.(reference.Canonical)
|
||||||
if command.IsTrusted() && !isCanonical {
|
if command.IsTrusted() && !isCanonical {
|
||||||
if alias == "" {
|
if alias == "" {
|
||||||
alias = ref.String()
|
alias = reference.FamiliarString(ref)
|
||||||
}
|
}
|
||||||
var nt reference.NamedTagged
|
|
||||||
named, err := reference.ParseNamed(ref.Name())
|
nt, ok := ref.(reference.NamedTagged)
|
||||||
if err != nil {
|
if !ok {
|
||||||
return err
|
nt = reference.EnsureTagged(ref)
|
||||||
}
|
|
||||||
if tagged, ok := ref.(distreference.Tagged); ok {
|
|
||||||
nt, err = reference.WithTag(named, tagged.Tag())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
named = reference.WithDefaultTag(named)
|
|
||||||
nt = named.(reference.NamedTagged)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trusted, err := image.TrustedReference(ctx, dockerCli, nt, newRegistryService())
|
trusted, err := image.TrustedReference(ctx, dockerCli, nt, newRegistryService())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
remote = trusted.String()
|
remote = reference.FamiliarString(trusted)
|
||||||
}
|
}
|
||||||
|
|
||||||
authConfig := command.ResolveAuthConfig(ctx, dockerCli, index)
|
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
|
||||||
|
|
||||||
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
registryAuthFunc := command.RegistryAuthenticationPrivilegedFunc(dockerCli, index, "plugin install")
|
registryAuthFunc := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "plugin install")
|
||||||
|
|
||||||
options := types.PluginInstallOptions{
|
options := types.PluginInstallOptions{
|
||||||
RegistryAuth: encodedAuth,
|
RegistryAuth: encodedAuth,
|
||||||
|
@ -5,11 +5,11 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/cli"
|
"github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/cli/command/image"
|
"github.com/docker/docker/cli/command/image"
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -32,16 +32,17 @@ func newPushCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runPush(dockerCli *command.DockerCli, name string) error {
|
func runPush(dockerCli *command.DockerCli, name string) error {
|
||||||
named, err := reference.ParseNamed(name) // FIXME: validate
|
named, err := reference.ParseNormalizedNamed(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if reference.IsNameOnly(named) {
|
if _, ok := named.(reference.Canonical); ok {
|
||||||
named = reference.WithDefaultTag(named)
|
return fmt.Errorf("invalid name: %s", name)
|
||||||
}
|
}
|
||||||
ref, ok := named.(reference.NamedTagged)
|
|
||||||
|
taggedRef, ok := named.(reference.NamedTagged)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid name: %s", named.String())
|
taggedRef = reference.EnsureTagged(named)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@ -56,7 +57,8 @@ func runPush(dockerCli *command.DockerCli, name string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
responseBody, err := dockerCli.Client().PluginPush(ctx, ref.String(), encodedAuth)
|
|
||||||
|
responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(taggedRef), encodedAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ func RetrieveAuthTokenFromImage(ctx context.Context, cli *DockerCli, image strin
|
|||||||
|
|
||||||
// resolveAuthConfigFromImage retrieves that AuthConfig using the image string
|
// resolveAuthConfigFromImage retrieves that AuthConfig using the image string
|
||||||
func resolveAuthConfigFromImage(ctx context.Context, cli *DockerCli, image string) (types.AuthConfig, error) {
|
func resolveAuthConfigFromImage(ctx context.Context, cli *DockerCli, image string) (types.AuthConfig, error) {
|
||||||
registryRef, err := reference.ParseNamed(image)
|
registryRef, err := reference.ParseNormalizedNamed(image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.AuthConfig{}, err
|
return types.AuthConfig{}, err
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
distreference "github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types/swarm"
|
"github.com/docker/docker/api/types/swarm"
|
||||||
"github.com/docker/docker/cli/command"
|
"github.com/docker/docker/cli/command"
|
||||||
"github.com/docker/docker/cli/trust"
|
"github.com/docker/docker/cli/trust"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
@ -24,41 +23,34 @@ func resolveServiceImageDigest(dockerCli *command.DockerCli, service *swarm.Serv
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
image := service.TaskTemplate.ContainerSpec.Image
|
ref, err := reference.ParseAnyReference(service.TaskTemplate.ContainerSpec.Image)
|
||||||
|
|
||||||
// We only attempt to resolve the digest if the reference
|
|
||||||
// could be parsed as a digest reference. Specifying an image ID
|
|
||||||
// is valid but not resolvable. There is no warning message for
|
|
||||||
// an image ID because it's valid to use one.
|
|
||||||
if _, err := digest.Parse(image); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ref, err := reference.ParseNamed(image)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not parse image reference %s", service.TaskTemplate.ContainerSpec.Image)
|
return errors.Wrapf(err, "invalid reference %s", service.TaskTemplate.ContainerSpec.Image)
|
||||||
}
|
}
|
||||||
if _, ok := ref.(reference.Canonical); !ok {
|
|
||||||
ref = reference.WithDefaultTag(ref)
|
|
||||||
|
|
||||||
taggedRef, ok := ref.(reference.NamedTagged)
|
// If reference does not have digest (is not canonical nor image id)
|
||||||
|
if _, ok := ref.(reference.Digested); !ok {
|
||||||
|
namedRef, ok := ref.(reference.Named)
|
||||||
if !ok {
|
if !ok {
|
||||||
// This should never happen because a reference either
|
return errors.New("failed to resolve image digest using content trust: reference is not named")
|
||||||
// has a digest, or WithDefaultTag would give it a tag.
|
|
||||||
return errors.New("Failed to resolve image digest using content trust: reference is missing a tag")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
taggedRef := reference.EnsureTagged(namedRef)
|
||||||
|
|
||||||
resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef)
|
resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to resolve image digest using content trust: %v", err)
|
return errors.Wrap(err, "failed to resolve image digest using content trust")
|
||||||
}
|
}
|
||||||
logrus.Debugf("resolved image tag to %s using content trust", resolvedImage.String())
|
resolvedFamiliar := reference.FamiliarString(resolvedImage)
|
||||||
service.TaskTemplate.ContainerSpec.Image = resolvedImage.String()
|
logrus.Debugf("resolved image tag to %s using content trust", resolvedFamiliar)
|
||||||
|
service.TaskTemplate.ContainerSpec.Image = resolvedFamiliar
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref reference.NamedTagged) (distreference.Canonical, error) {
|
func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref reference.NamedTagged) (reference.Canonical, error) {
|
||||||
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -78,7 +70,7 @@ func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref refer
|
|||||||
// Only get the tag if it's in the top level targets role or the releases delegation role
|
// Only get the tag if it's in the top level targets role or the releases delegation role
|
||||||
// ignore it if it's in any other delegation roles
|
// ignore it if it's in any other delegation roles
|
||||||
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
||||||
return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.String()))
|
return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", reference.FamiliarString(ref)))
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("retrieving target for %s role\n", t.Role)
|
logrus.Debugf("retrieving target for %s role\n", t.Role)
|
||||||
@ -89,8 +81,6 @@ func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref refer
|
|||||||
|
|
||||||
dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h))
|
dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h))
|
||||||
|
|
||||||
// Using distribution reference package to make sure that adding a
|
// Allow returning canonical reference with tag
|
||||||
// digest does not erase the tag. When the two reference packages
|
return reference.WithDigest(ref, dgst)
|
||||||
// are unified, this will no longer be an issue.
|
|
||||||
return distreference.WithDigest(ref, dgst)
|
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ func TestLayerAlreadyExists(t *testing.T) {
|
|||||||
checkOtherRepositories: true,
|
checkOtherRepositories: true,
|
||||||
metadata: []metadata.V2Metadata{
|
metadata: []metadata.V2Metadata{
|
||||||
{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/hello-world"},
|
{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/hello-world"},
|
||||||
{Digest: digest.Digest("orange"), SourceRepository: "docker.io/library/busybox/subapp"},
|
{Digest: digest.Digest("orange"), SourceRepository: "docker.io/busybox/subapp"},
|
||||||
{Digest: digest.Digest("pear"), SourceRepository: "docker.io/busybox"},
|
{Digest: digest.Digest("pear"), SourceRepository: "docker.io/busybox"},
|
||||||
{Digest: digest.Digest("plum"), SourceRepository: "busybox"},
|
{Digest: digest.Digest("plum"), SourceRepository: "busybox"},
|
||||||
{Digest: digest.Digest("banana"), SourceRepository: "127.0.0.1/busybox"},
|
{Digest: digest.Digest("banana"), SourceRepository: "127.0.0.1/busybox"},
|
||||||
|
@ -3082,7 +3082,7 @@ func (s *DockerSuite) TestBuildInvalidTag(c *check.C) {
|
|||||||
name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200)
|
name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200)
|
||||||
buildImage(name, withDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
|
buildImage(name, withDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
|
||||||
ExitCode: 125,
|
ExitCode: 125,
|
||||||
Err: "Error parsing reference",
|
Err: "invalid reference format",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ func (s *DockerSuite) TestCreateByImageID(c *check.C) {
|
|||||||
c.Fatalf("expected non-zero exit code; received %d", exit)
|
c.Fatalf("expected non-zero exit code; received %d", exit)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected := "Error parsing reference"; !strings.Contains(out, expected) {
|
if expected := "invalid reference format"; !strings.Contains(out, expected) {
|
||||||
c.Fatalf(`Expected %q in output; got: %s`, expected, out)
|
c.Fatalf(`Expected %q in output; got: %s`, expected, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3862,8 +3862,8 @@ func (s *DockerSuite) TestRunInvalidReference(c *check.C) {
|
|||||||
c.Fatalf("expected non-zero exist code; received %d", exit)
|
c.Fatalf("expected non-zero exist code; received %d", exit)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(out, "Error parsing reference") {
|
if !strings.Contains(out, "invalid reference format") {
|
||||||
c.Fatalf(`Expected "Error parsing reference" in output; got: %s`, out)
|
c.Fatalf(`Expected "invalid reference format" in output; got: %s`, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
@ -19,7 +20,6 @@ import (
|
|||||||
"github.com/docker/docker/pkg/ioutils"
|
"github.com/docker/docker/pkg/ioutils"
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
"github.com/docker/docker/plugin/v2"
|
"github.com/docker/docker/plugin/v2"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package reference
|
package reference
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
distreference "github.com/docker/distribution/reference"
|
distreference "github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"github.com/docker/docker/pkg/stringid"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -53,21 +52,31 @@ type Canonical interface {
|
|||||||
// returned.
|
// returned.
|
||||||
// If an error was encountered it is returned, along with a nil Reference.
|
// If an error was encountered it is returned, along with a nil Reference.
|
||||||
func ParseNamed(s string) (Named, error) {
|
func ParseNamed(s string) (Named, error) {
|
||||||
named, err := distreference.ParseNamed(s)
|
named, err := distreference.ParseNormalizedNamed(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Error parsing reference: %q is not a valid repository/tag: %s", s, err)
|
return nil, errors.Wrapf(err, "failed to parse reference %q", s)
|
||||||
}
|
}
|
||||||
r, err := WithName(named.Name())
|
if err := validateName(distreference.FamiliarName(named)); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure returned reference cannot have tag and digest
|
||||||
if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
|
if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
|
||||||
return WithDigest(r, canonical.Digest())
|
r, err := distreference.WithDigest(distreference.TrimNamed(named), canonical.Digest())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &canonicalRef{namedRef{r}}, nil
|
||||||
}
|
}
|
||||||
if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
|
if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
|
||||||
return WithTag(r, tagged.Tag())
|
r, err := distreference.WithTag(distreference.TrimNamed(named), tagged.Tag())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &taggedRef{namedRef{r}}, nil
|
||||||
}
|
}
|
||||||
return r, nil
|
|
||||||
|
return &namedRef{named}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrimNamed removes any tag or digest from the named reference
|
// TrimNamed removes any tag or digest from the named reference
|
||||||
@ -78,16 +87,15 @@ func TrimNamed(ref Named) Named {
|
|||||||
// WithName returns a named object representing the given string. If the input
|
// WithName returns a named object representing the given string. If the input
|
||||||
// is invalid ErrReferenceInvalidFormat will be returned.
|
// is invalid ErrReferenceInvalidFormat will be returned.
|
||||||
func WithName(name string) (Named, error) {
|
func WithName(name string) (Named, error) {
|
||||||
name, err := normalize(name)
|
r, err := distreference.ParseNormalizedNamed(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := validateName(name); err != nil {
|
if err := validateName(distreference.FamiliarName(r)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r, err := distreference.WithName(name)
|
if !distreference.IsNameOnly(r) {
|
||||||
if err != nil {
|
return nil, distreference.ErrReferenceInvalidFormat
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return &namedRef{r}, nil
|
return &namedRef{r}, nil
|
||||||
}
|
}
|
||||||
@ -122,17 +130,22 @@ type canonicalRef struct {
|
|||||||
namedRef
|
namedRef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *namedRef) Name() string {
|
||||||
|
return distreference.FamiliarName(r.Named)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *namedRef) String() string {
|
||||||
|
return distreference.FamiliarString(r.Named)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *namedRef) FullName() string {
|
func (r *namedRef) FullName() string {
|
||||||
hostname, remoteName := splitHostname(r.Name())
|
return r.Named.Name()
|
||||||
return hostname + "/" + remoteName
|
|
||||||
}
|
}
|
||||||
func (r *namedRef) Hostname() string {
|
func (r *namedRef) Hostname() string {
|
||||||
hostname, _ := splitHostname(r.Name())
|
return distreference.Domain(r.Named)
|
||||||
return hostname
|
|
||||||
}
|
}
|
||||||
func (r *namedRef) RemoteName() string {
|
func (r *namedRef) RemoteName() string {
|
||||||
_, remoteName := splitHostname(r.Name())
|
return distreference.Path(r.Named)
|
||||||
return remoteName
|
|
||||||
}
|
}
|
||||||
func (r *taggedRef) Tag() string {
|
func (r *taggedRef) Tag() string {
|
||||||
return r.namedRef.Named.(distreference.NamedTagged).Tag()
|
return r.namedRef.Named.(distreference.NamedTagged).Tag()
|
||||||
@ -173,41 +186,6 @@ func ParseIDOrReference(idOrRef string) (digest.Digest, Named, error) {
|
|||||||
return "", ref, err
|
return "", ref, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitHostname splits a repository name to hostname and remotename string.
|
|
||||||
// If no valid hostname is found, the default hostname is used. Repository name
|
|
||||||
// needs to be already validated before.
|
|
||||||
func splitHostname(name string) (hostname, remoteName string) {
|
|
||||||
i := strings.IndexRune(name, '/')
|
|
||||||
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
|
||||||
hostname, remoteName = DefaultHostname, name
|
|
||||||
} else {
|
|
||||||
hostname, remoteName = name[:i], name[i+1:]
|
|
||||||
}
|
|
||||||
if hostname == LegacyDefaultHostname {
|
|
||||||
hostname = DefaultHostname
|
|
||||||
}
|
|
||||||
if hostname == DefaultHostname && !strings.ContainsRune(remoteName, '/') {
|
|
||||||
remoteName = DefaultRepoPrefix + remoteName
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// normalize returns a repository name in its normalized form, meaning it
|
|
||||||
// will not contain default hostname nor library/ prefix for official images.
|
|
||||||
func normalize(name string) (string, error) {
|
|
||||||
host, remoteName := splitHostname(name)
|
|
||||||
if strings.ToLower(remoteName) != remoteName {
|
|
||||||
return "", errors.New("invalid reference format: repository name must be lowercase")
|
|
||||||
}
|
|
||||||
if host == DefaultHostname {
|
|
||||||
if strings.HasPrefix(remoteName, DefaultRepoPrefix) {
|
|
||||||
return strings.TrimPrefix(remoteName, DefaultRepoPrefix), nil
|
|
||||||
}
|
|
||||||
return remoteName, nil
|
|
||||||
}
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateName(name string) error {
|
func validateName(name string) error {
|
||||||
if err := stringid.ValidateID(name); err == nil {
|
if err := stringid.ValidateID(name); err == nil {
|
||||||
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
|
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
package registry
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/opts"
|
"github.com/docker/docker/opts"
|
||||||
"github.com/docker/docker/reference"
|
forkedref "github.com/docker/docker/reference"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -270,8 +271,8 @@ func ValidateMirror(val string) (string, error) {
|
|||||||
|
|
||||||
// ValidateIndexName validates an index name.
|
// ValidateIndexName validates an index name.
|
||||||
func ValidateIndexName(val string) (string, error) {
|
func ValidateIndexName(val string) (string, error) {
|
||||||
if val == reference.LegacyDefaultHostname {
|
if val == forkedref.LegacyDefaultHostname {
|
||||||
val = reference.DefaultHostname
|
val = forkedref.DefaultHostname
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
|
if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
|
||||||
return "", fmt.Errorf("Invalid index name (%s). Cannot begin or end with a hyphen.", val)
|
return "", fmt.Errorf("Invalid index name (%s). Cannot begin or end with a hyphen.", val)
|
||||||
@ -321,13 +322,19 @@ func GetAuthConfigKey(index *registrytypes.IndexInfo) string {
|
|||||||
|
|
||||||
// newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
|
// newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
|
||||||
func newRepositoryInfo(config *serviceConfig, name reference.Named) (*RepositoryInfo, error) {
|
func newRepositoryInfo(config *serviceConfig, name reference.Named) (*RepositoryInfo, error) {
|
||||||
index, err := newIndexInfo(config, name.Hostname())
|
index, err := newIndexInfo(config, reference.Domain(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
official := !strings.ContainsRune(reference.FamiliarName(name), '/')
|
||||||
|
|
||||||
|
// TODO: remove used of forked reference package
|
||||||
|
nameref, err := forkedref.ParseNamed(name.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
official := !strings.ContainsRune(name.Name(), '/')
|
|
||||||
return &RepositoryInfo{
|
return &RepositoryInfo{
|
||||||
Named: name,
|
Named: nameref,
|
||||||
Index: index,
|
Index: index,
|
||||||
Official: official,
|
Official: official,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -10,10 +10,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/client/transport"
|
"github.com/docker/distribution/registry/client/transport"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/reference"
|
forkedref "github.com/docker/docker/reference"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -201,7 +202,7 @@ func TestGetRemoteImageLayer(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetRemoteTag(t *testing.T) {
|
func TestGetRemoteTag(t *testing.T) {
|
||||||
r := spawnTestRegistrySession(t)
|
r := spawnTestRegistrySession(t)
|
||||||
repoRef, err := reference.ParseNamed(REPO)
|
repoRef, err := forkedref.ParseNamed(REPO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -211,7 +212,7 @@ func TestGetRemoteTag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assertEqual(t, tag, imageID, "Expected tag test to map to "+imageID)
|
assertEqual(t, tag, imageID, "Expected tag test to map to "+imageID)
|
||||||
|
|
||||||
bazRef, err := reference.ParseNamed("foo42/baz")
|
bazRef, err := forkedref.ParseNamed("foo42/baz")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -223,7 +224,7 @@ func TestGetRemoteTag(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetRemoteTags(t *testing.T) {
|
func TestGetRemoteTags(t *testing.T) {
|
||||||
r := spawnTestRegistrySession(t)
|
r := spawnTestRegistrySession(t)
|
||||||
repoRef, err := reference.ParseNamed(REPO)
|
repoRef, err := forkedref.ParseNamed(REPO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ func TestGetRemoteTags(t *testing.T) {
|
|||||||
assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID)
|
assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID)
|
||||||
assertEqual(t, tags["test"], imageID, "Expected tag test to map to "+imageID)
|
assertEqual(t, tags["test"], imageID, "Expected tag test to map to "+imageID)
|
||||||
|
|
||||||
bazRef, err := reference.ParseNamed("foo42/baz")
|
bazRef, err := forkedref.ParseNamed("foo42/baz")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -252,7 +253,7 @@ func TestGetRepositoryData(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
host := "http://" + parsedURL.Host + "/v1/"
|
host := "http://" + parsedURL.Host + "/v1/"
|
||||||
repoRef, err := reference.ParseNamed(REPO)
|
repoRef, err := forkedref.ParseNamed(REPO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -505,7 +506,7 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for reposName, expectedRepoInfo := range expectedRepoInfos {
|
for reposName, expectedRepoInfo := range expectedRepoInfos {
|
||||||
named, err := reference.WithName(reposName)
|
named, err := reference.ParseNormalizedNamed(reposName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -669,7 +670,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
pushAPIEndpoints, err := s.LookupPushEndpoints(imageName.Hostname())
|
pushAPIEndpoints, err := s.LookupPushEndpoints(reference.Domain(imageName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -677,7 +678,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
|
|||||||
t.Fatal("Push endpoint should not contain mirror")
|
t.Fatal("Push endpoint should not contain mirror")
|
||||||
}
|
}
|
||||||
|
|
||||||
pullAPIEndpoints, err := s.LookupPullEndpoints(imageName.Hostname())
|
pullAPIEndpoints, err := s.LookupPullEndpoints(reference.Domain(imageName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -688,7 +689,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
|
|||||||
|
|
||||||
func TestPushRegistryTag(t *testing.T) {
|
func TestPushRegistryTag(t *testing.T) {
|
||||||
r := spawnTestRegistrySession(t)
|
r := spawnTestRegistrySession(t)
|
||||||
repoRef, err := reference.ParseNamed(REPO)
|
repoRef, err := forkedref.ParseNamed(REPO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -710,7 +711,7 @@ func TestPushImageJSONIndex(t *testing.T) {
|
|||||||
Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
|
Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
repoRef, err := reference.ParseNamed(REPO)
|
repoRef, err := forkedref.ParseNamed(REPO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/distribution/registry/client/auth"
|
"github.com/docker/distribution/registry/client/auth"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/reference"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -43,7 +43,7 @@ github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
|
|||||||
github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
||||||
|
|
||||||
# get graph and distribution packages
|
# get graph and distribution packages
|
||||||
github.com/docker/distribution 7dba427612198a11b161a27f9d40bb2dca1ccd20
|
github.com/docker/distribution 129ad8ea0c3760d878b34cffdb9c3be874a7b2f7
|
||||||
github.com/vbatts/tar-split v0.10.1
|
github.com/vbatts/tar-split v0.10.1
|
||||||
github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
||||||
|
|
||||||
|
18
vendor/github.com/docker/distribution/reference/helpers.go
generated
vendored
18
vendor/github.com/docker/distribution/reference/helpers.go
generated
vendored
@ -10,3 +10,21 @@ func IsNameOnly(ref Named) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FamiliarName returns the familiar name string
|
||||||
|
// for the given named, familiarizing if needed.
|
||||||
|
func FamiliarName(ref Named) string {
|
||||||
|
if nn, ok := ref.(NormalizedNamed); ok {
|
||||||
|
return nn.Familiar().Name()
|
||||||
|
}
|
||||||
|
return ref.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FamiliarString returns the familiar string representation
|
||||||
|
// for the given reference, familiarizing if needed.
|
||||||
|
func FamiliarString(ref Reference) string {
|
||||||
|
if nn, ok := ref.(NormalizedNamed); ok {
|
||||||
|
return nn.Familiar().String()
|
||||||
|
}
|
||||||
|
return ref.String()
|
||||||
|
}
|
||||||
|
150
vendor/github.com/docker/distribution/reference/normalize.go
generated
vendored
150
vendor/github.com/docker/distribution/reference/normalize.go
generated
vendored
@ -1,9 +1,125 @@
|
|||||||
package reference
|
package reference
|
||||||
|
|
||||||
var (
|
import (
|
||||||
defaultTag = "latest"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/digestset"
|
||||||
|
"github.com/opencontainers/go-digest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
legacyDefaultDomain = "index.docker.io"
|
||||||
|
defaultDomain = "docker.io"
|
||||||
|
defaultRepoPrefix = "library/"
|
||||||
|
defaultTag = "latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NormalizedNamed represents a name which has been
|
||||||
|
// normalized and has a familiar form. A familiar name
|
||||||
|
// is what is used in Docker UI. An example normalized
|
||||||
|
// name is "docker.io/library/ubuntu" and corresponding
|
||||||
|
// familiar name of "ubuntu".
|
||||||
|
type NormalizedNamed interface {
|
||||||
|
Named
|
||||||
|
Familiar() Named
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseNormalizedNamed parses a string into a named reference
|
||||||
|
// transforming a familiar name from Docker UI to a fully
|
||||||
|
// qualified reference. If the value may be an identifier
|
||||||
|
// use ParseAnyReference.
|
||||||
|
func ParseNormalizedNamed(s string) (NormalizedNamed, error) {
|
||||||
|
if ok := anchoredIdentifierRegexp.MatchString(s); ok {
|
||||||
|
return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
|
||||||
|
}
|
||||||
|
domain, remainder := splitDockerDomain(s)
|
||||||
|
var remoteName string
|
||||||
|
if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 {
|
||||||
|
remoteName = remainder[:tagSep]
|
||||||
|
} else {
|
||||||
|
remoteName = remainder
|
||||||
|
}
|
||||||
|
if strings.ToLower(remoteName) != remoteName {
|
||||||
|
return nil, errors.New("invalid reference format: repository name must be lowercase")
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, err := Parse(domain + "/" + remainder)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
named, isNamed := ref.(NormalizedNamed)
|
||||||
|
if !isNamed {
|
||||||
|
return nil, fmt.Errorf("reference %s has no name", ref.String())
|
||||||
|
}
|
||||||
|
return named, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitDockerDomain splits a repository name to domain and remotename string.
|
||||||
|
// If no valid domain is found, the default domain is used. Repository name
|
||||||
|
// needs to be already validated before.
|
||||||
|
func splitDockerDomain(name string) (domain, remainder string) {
|
||||||
|
i := strings.IndexRune(name, '/')
|
||||||
|
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||||
|
domain, remainder = defaultDomain, name
|
||||||
|
} else {
|
||||||
|
domain, remainder = name[:i], name[i+1:]
|
||||||
|
}
|
||||||
|
if domain == legacyDefaultDomain {
|
||||||
|
domain = defaultDomain
|
||||||
|
}
|
||||||
|
if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
|
||||||
|
remainder = defaultRepoPrefix + remainder
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// familiarizeName returns a shortened version of the name familiar
|
||||||
|
// to to the Docker UI. Familiar names have the default domain
|
||||||
|
// "docker.io" and "library/" repository prefix removed.
|
||||||
|
// For example, "docker.io/library/redis" will have the familiar
|
||||||
|
// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp".
|
||||||
|
// Returns a familiarized named only reference.
|
||||||
|
func familiarizeName(named namedRepository) repository {
|
||||||
|
repo := repository{
|
||||||
|
domain: named.Domain(),
|
||||||
|
path: named.Path(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if repo.domain == defaultDomain {
|
||||||
|
repo.domain = ""
|
||||||
|
repo.path = strings.TrimPrefix(repo.path, defaultRepoPrefix)
|
||||||
|
}
|
||||||
|
return repo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r reference) Familiar() Named {
|
||||||
|
return reference{
|
||||||
|
namedRepository: familiarizeName(r.namedRepository),
|
||||||
|
tag: r.tag,
|
||||||
|
digest: r.digest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r repository) Familiar() Named {
|
||||||
|
return familiarizeName(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t taggedReference) Familiar() Named {
|
||||||
|
return taggedReference{
|
||||||
|
namedRepository: familiarizeName(t.namedRepository),
|
||||||
|
tag: t.tag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c canonicalReference) Familiar() Named {
|
||||||
|
return canonicalReference{
|
||||||
|
namedRepository: familiarizeName(c.namedRepository),
|
||||||
|
digest: c.digest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EnsureTagged adds the default tag "latest" to a reference if it only has
|
// EnsureTagged adds the default tag "latest" to a reference if it only has
|
||||||
// a repo name.
|
// a repo name.
|
||||||
func EnsureTagged(ref Named) NamedTagged {
|
func EnsureTagged(ref Named) NamedTagged {
|
||||||
@ -20,3 +136,33 @@ func EnsureTagged(ref Named) NamedTagged {
|
|||||||
}
|
}
|
||||||
return namedTagged
|
return namedTagged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseAnyReference parses a reference string as a possible identifier,
|
||||||
|
// full digest, or familiar name.
|
||||||
|
func ParseAnyReference(ref string) (Reference, error) {
|
||||||
|
if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
|
||||||
|
return digestReference("sha256:" + ref), nil
|
||||||
|
}
|
||||||
|
if dgst, err := digest.Parse(ref); err == nil {
|
||||||
|
return digestReference(dgst), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseNormalizedNamed(ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAnyReferenceWithSet parses a reference string as a possible short
|
||||||
|
// identifier to be matched in a digest set, a full digest, or familiar name.
|
||||||
|
func ParseAnyReferenceWithSet(ref string, ds *digestset.Set) (Reference, error) {
|
||||||
|
if ok := anchoredShortIdentifierRegexp.MatchString(ref); ok {
|
||||||
|
dgst, err := ds.Lookup(ref)
|
||||||
|
if err == nil {
|
||||||
|
return digestReference(dgst), nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if dgst, err := digest.Parse(ref); err == nil {
|
||||||
|
return digestReference(dgst), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseNormalizedNamed(ref)
|
||||||
|
}
|
||||||
|
178
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
178
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
@ -4,11 +4,11 @@
|
|||||||
// Grammar
|
// Grammar
|
||||||
//
|
//
|
||||||
// reference := name [ ":" tag ] [ "@" digest ]
|
// reference := name [ ":" tag ] [ "@" digest ]
|
||||||
// name := [hostname '/'] component ['/' component]*
|
// name := [domain '/'] path-component ['/' path-component]*
|
||||||
// hostname := hostcomponent ['.' hostcomponent]* [':' port-number]
|
// domain := domain-component ['.' domain-component]* [':' port-number]
|
||||||
// hostcomponent := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
||||||
// port-number := /[0-9]+/
|
// port-number := /[0-9]+/
|
||||||
// component := alpha-numeric [separator alpha-numeric]*
|
// path-component := alpha-numeric [separator alpha-numeric]*
|
||||||
// alpha-numeric := /[a-z0-9]+/
|
// alpha-numeric := /[a-z0-9]+/
|
||||||
// separator := /[_.]|__|[-]*/
|
// separator := /[_.]|__|[-]*/
|
||||||
//
|
//
|
||||||
@ -19,6 +19,9 @@
|
|||||||
// digest-algorithm-separator := /[+.-_]/
|
// digest-algorithm-separator := /[+.-_]/
|
||||||
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
||||||
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
||||||
|
//
|
||||||
|
// identifier := /[a-f0-9]{64}/
|
||||||
|
// short-identifier := /[a-f0-9]{6,64}/
|
||||||
package reference
|
package reference
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -126,23 +129,56 @@ type Digested interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Canonical reference is an object with a fully unique
|
// Canonical reference is an object with a fully unique
|
||||||
// name including a name with hostname and digest
|
// name including a name with domain and digest
|
||||||
type Canonical interface {
|
type Canonical interface {
|
||||||
Named
|
Named
|
||||||
Digest() digest.Digest
|
Digest() digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// namedRepository is a reference to a repository with a name.
|
||||||
|
// A namedRepository has both domain and path components.
|
||||||
|
type namedRepository interface {
|
||||||
|
Named
|
||||||
|
Domain() string
|
||||||
|
Path() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain returns the domain part of the Named reference
|
||||||
|
func Domain(named Named) string {
|
||||||
|
if r, ok := named.(namedRepository); ok {
|
||||||
|
return r.Domain()
|
||||||
|
}
|
||||||
|
domain, _ := splitDomain(named.Name())
|
||||||
|
return domain
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path returns the name without the domain part of the Named reference
|
||||||
|
func Path(named Named) (name string) {
|
||||||
|
if r, ok := named.(namedRepository); ok {
|
||||||
|
return r.Path()
|
||||||
|
}
|
||||||
|
_, path := splitDomain(named.Name())
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitDomain(name string) (string, string) {
|
||||||
|
match := anchoredNameRegexp.FindStringSubmatch(name)
|
||||||
|
if len(match) != 3 {
|
||||||
|
return "", name
|
||||||
|
}
|
||||||
|
return match[1], match[2]
|
||||||
|
}
|
||||||
|
|
||||||
// SplitHostname splits a named reference into a
|
// SplitHostname splits a named reference into a
|
||||||
// hostname and name string. If no valid hostname is
|
// hostname and name string. If no valid hostname is
|
||||||
// found, the hostname is empty and the full value
|
// found, the hostname is empty and the full value
|
||||||
// is returned as name
|
// is returned as name
|
||||||
|
// DEPRECATED: Use Domain or Path
|
||||||
func SplitHostname(named Named) (string, string) {
|
func SplitHostname(named Named) (string, string) {
|
||||||
name := named.Name()
|
if r, ok := named.(namedRepository); ok {
|
||||||
match := anchoredNameRegexp.FindStringSubmatch(name)
|
return r.Domain(), r.Path()
|
||||||
if len(match) != 3 {
|
|
||||||
return "", name
|
|
||||||
}
|
}
|
||||||
return match[1], match[2]
|
return splitDomain(named.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses s and returns a syntactically valid Reference.
|
// Parse parses s and returns a syntactically valid Reference.
|
||||||
@ -164,9 +200,20 @@ func Parse(s string) (Reference, error) {
|
|||||||
return nil, ErrNameTooLong
|
return nil, ErrNameTooLong
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var repo repository
|
||||||
|
|
||||||
|
nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])
|
||||||
|
if nameMatch != nil && len(nameMatch) == 3 {
|
||||||
|
repo.domain = nameMatch[1]
|
||||||
|
repo.path = nameMatch[2]
|
||||||
|
} else {
|
||||||
|
repo.domain = ""
|
||||||
|
repo.path = matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
ref := reference{
|
ref := reference{
|
||||||
name: matches[1],
|
namedRepository: repo,
|
||||||
tag: matches[2],
|
tag: matches[2],
|
||||||
}
|
}
|
||||||
if matches[3] != "" {
|
if matches[3] != "" {
|
||||||
var err error
|
var err error
|
||||||
@ -207,10 +254,15 @@ func WithName(name string) (Named, error) {
|
|||||||
if len(name) > NameTotalLengthMax {
|
if len(name) > NameTotalLengthMax {
|
||||||
return nil, ErrNameTooLong
|
return nil, ErrNameTooLong
|
||||||
}
|
}
|
||||||
if !anchoredNameRegexp.MatchString(name) {
|
|
||||||
|
match := anchoredNameRegexp.FindStringSubmatch(name)
|
||||||
|
if match == nil || len(match) != 3 {
|
||||||
return nil, ErrReferenceInvalidFormat
|
return nil, ErrReferenceInvalidFormat
|
||||||
}
|
}
|
||||||
return repository(name), nil
|
return repository{
|
||||||
|
domain: match[1],
|
||||||
|
path: match[2],
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTag combines the name from "name" and the tag from "tag" to form a
|
// WithTag combines the name from "name" and the tag from "tag" to form a
|
||||||
@ -219,16 +271,23 @@ func WithTag(name Named, tag string) (NamedTagged, error) {
|
|||||||
if !anchoredTagRegexp.MatchString(tag) {
|
if !anchoredTagRegexp.MatchString(tag) {
|
||||||
return nil, ErrTagInvalidFormat
|
return nil, ErrTagInvalidFormat
|
||||||
}
|
}
|
||||||
|
var repo repository
|
||||||
|
if r, ok := name.(namedRepository); ok {
|
||||||
|
repo.domain = r.Domain()
|
||||||
|
repo.path = r.Path()
|
||||||
|
} else {
|
||||||
|
repo.path = name.Name()
|
||||||
|
}
|
||||||
if canonical, ok := name.(Canonical); ok {
|
if canonical, ok := name.(Canonical); ok {
|
||||||
return reference{
|
return reference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
digest: canonical.Digest(),
|
digest: canonical.Digest(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return taggedReference{
|
return taggedReference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
tag: tag,
|
tag: tag,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,16 +297,23 @@ func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
|
|||||||
if !anchoredDigestRegexp.MatchString(digest.String()) {
|
if !anchoredDigestRegexp.MatchString(digest.String()) {
|
||||||
return nil, ErrDigestInvalidFormat
|
return nil, ErrDigestInvalidFormat
|
||||||
}
|
}
|
||||||
|
var repo repository
|
||||||
|
if r, ok := name.(namedRepository); ok {
|
||||||
|
repo.domain = r.Domain()
|
||||||
|
repo.path = r.Path()
|
||||||
|
} else {
|
||||||
|
repo.path = name.Name()
|
||||||
|
}
|
||||||
if tagged, ok := name.(Tagged); ok {
|
if tagged, ok := name.(Tagged); ok {
|
||||||
return reference{
|
return reference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
tag: tagged.Tag(),
|
tag: tagged.Tag(),
|
||||||
digest: digest,
|
digest: digest,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return canonicalReference{
|
return canonicalReference{
|
||||||
name: name.Name(),
|
namedRepository: repo,
|
||||||
digest: digest,
|
digest: digest,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,11 +329,15 @@ func Match(pattern string, ref Reference) (bool, error) {
|
|||||||
|
|
||||||
// TrimNamed removes any tag or digest from the named reference.
|
// TrimNamed removes any tag or digest from the named reference.
|
||||||
func TrimNamed(ref Named) Named {
|
func TrimNamed(ref Named) Named {
|
||||||
return repository(ref.Name())
|
domain, path := SplitHostname(ref)
|
||||||
|
return repository{
|
||||||
|
domain: domain,
|
||||||
|
path: path,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBestReferenceType(ref reference) Reference {
|
func getBestReferenceType(ref reference) Reference {
|
||||||
if ref.name == "" {
|
if ref.Name() == "" {
|
||||||
// Allow digest only references
|
// Allow digest only references
|
||||||
if ref.digest != "" {
|
if ref.digest != "" {
|
||||||
return digestReference(ref.digest)
|
return digestReference(ref.digest)
|
||||||
@ -277,16 +347,16 @@ func getBestReferenceType(ref reference) Reference {
|
|||||||
if ref.tag == "" {
|
if ref.tag == "" {
|
||||||
if ref.digest != "" {
|
if ref.digest != "" {
|
||||||
return canonicalReference{
|
return canonicalReference{
|
||||||
name: ref.name,
|
namedRepository: ref.namedRepository,
|
||||||
digest: ref.digest,
|
digest: ref.digest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return repository(ref.name)
|
return ref.namedRepository
|
||||||
}
|
}
|
||||||
if ref.digest == "" {
|
if ref.digest == "" {
|
||||||
return taggedReference{
|
return taggedReference{
|
||||||
name: ref.name,
|
namedRepository: ref.namedRepository,
|
||||||
tag: ref.tag,
|
tag: ref.tag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,17 +364,13 @@ func getBestReferenceType(ref reference) Reference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type reference struct {
|
type reference struct {
|
||||||
name string
|
namedRepository
|
||||||
tag string
|
tag string
|
||||||
digest digest.Digest
|
digest digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r reference) String() string {
|
func (r reference) String() string {
|
||||||
return r.name + ":" + r.tag + "@" + r.digest.String()
|
return r.Name() + ":" + r.tag + "@" + r.digest.String()
|
||||||
}
|
|
||||||
|
|
||||||
func (r reference) Name() string {
|
|
||||||
return r.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r reference) Tag() string {
|
func (r reference) Tag() string {
|
||||||
@ -315,14 +381,28 @@ func (r reference) Digest() digest.Digest {
|
|||||||
return r.digest
|
return r.digest
|
||||||
}
|
}
|
||||||
|
|
||||||
type repository string
|
type repository struct {
|
||||||
|
domain string
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
func (r repository) String() string {
|
func (r repository) String() string {
|
||||||
return string(r)
|
return r.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r repository) Name() string {
|
func (r repository) Name() string {
|
||||||
return string(r)
|
if r.domain == "" {
|
||||||
|
return r.path
|
||||||
|
}
|
||||||
|
return r.domain + "/" + r.path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r repository) Domain() string {
|
||||||
|
return r.domain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r repository) Path() string {
|
||||||
|
return r.path
|
||||||
}
|
}
|
||||||
|
|
||||||
type digestReference digest.Digest
|
type digestReference digest.Digest
|
||||||
@ -336,16 +416,12 @@ func (d digestReference) Digest() digest.Digest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type taggedReference struct {
|
type taggedReference struct {
|
||||||
name string
|
namedRepository
|
||||||
tag string
|
tag string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taggedReference) String() string {
|
func (t taggedReference) String() string {
|
||||||
return t.name + ":" + t.tag
|
return t.Name() + ":" + t.tag
|
||||||
}
|
|
||||||
|
|
||||||
func (t taggedReference) Name() string {
|
|
||||||
return t.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taggedReference) Tag() string {
|
func (t taggedReference) Tag() string {
|
||||||
@ -353,16 +429,12 @@ func (t taggedReference) Tag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type canonicalReference struct {
|
type canonicalReference struct {
|
||||||
name string
|
namedRepository
|
||||||
digest digest.Digest
|
digest digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c canonicalReference) String() string {
|
func (c canonicalReference) String() string {
|
||||||
return c.name + "@" + c.digest.String()
|
return c.Name() + "@" + c.digest.String()
|
||||||
}
|
|
||||||
|
|
||||||
func (c canonicalReference) Name() string {
|
|
||||||
return c.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c canonicalReference) Digest() digest.Digest {
|
func (c canonicalReference) Digest() digest.Digest {
|
||||||
|
41
vendor/github.com/docker/distribution/reference/regexp.go
generated
vendored
41
vendor/github.com/docker/distribution/reference/regexp.go
generated
vendored
@ -19,18 +19,18 @@ var (
|
|||||||
alphaNumericRegexp,
|
alphaNumericRegexp,
|
||||||
optional(repeated(separatorRegexp, alphaNumericRegexp)))
|
optional(repeated(separatorRegexp, alphaNumericRegexp)))
|
||||||
|
|
||||||
// hostnameComponentRegexp restricts the registry hostname component of a
|
// domainComponentRegexp restricts the registry domain component of a
|
||||||
// repository name to start with a component as defined by hostnameRegexp
|
// repository name to start with a component as defined by domainRegexp
|
||||||
// and followed by an optional port.
|
// and followed by an optional port.
|
||||||
hostnameComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
|
domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
|
||||||
|
|
||||||
// hostnameRegexp defines the structure of potential hostname components
|
// domainRegexp defines the structure of potential domain components
|
||||||
// that may be part of image names. This is purposely a subset of what is
|
// that may be part of image names. This is purposely a subset of what is
|
||||||
// allowed by DNS to ensure backwards compatibility with Docker image
|
// allowed by DNS to ensure backwards compatibility with Docker image
|
||||||
// names.
|
// names.
|
||||||
hostnameRegexp = expression(
|
domainRegexp = expression(
|
||||||
hostnameComponentRegexp,
|
domainComponentRegexp,
|
||||||
optional(repeated(literal(`.`), hostnameComponentRegexp)),
|
optional(repeated(literal(`.`), domainComponentRegexp)),
|
||||||
optional(literal(`:`), match(`[0-9]+`)))
|
optional(literal(`:`), match(`[0-9]+`)))
|
||||||
|
|
||||||
// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
||||||
@ -48,17 +48,17 @@ var (
|
|||||||
anchoredDigestRegexp = anchored(DigestRegexp)
|
anchoredDigestRegexp = anchored(DigestRegexp)
|
||||||
|
|
||||||
// NameRegexp is the format for the name component of references. The
|
// NameRegexp is the format for the name component of references. The
|
||||||
// regexp has capturing groups for the hostname and name part omitting
|
// regexp has capturing groups for the domain and name part omitting
|
||||||
// the separating forward slash from either.
|
// the separating forward slash from either.
|
||||||
NameRegexp = expression(
|
NameRegexp = expression(
|
||||||
optional(hostnameRegexp, literal(`/`)),
|
optional(domainRegexp, literal(`/`)),
|
||||||
nameComponentRegexp,
|
nameComponentRegexp,
|
||||||
optional(repeated(literal(`/`), nameComponentRegexp)))
|
optional(repeated(literal(`/`), nameComponentRegexp)))
|
||||||
|
|
||||||
// anchoredNameRegexp is used to parse a name value, capturing the
|
// anchoredNameRegexp is used to parse a name value, capturing the
|
||||||
// hostname and trailing components.
|
// domain and trailing components.
|
||||||
anchoredNameRegexp = anchored(
|
anchoredNameRegexp = anchored(
|
||||||
optional(capture(hostnameRegexp), literal(`/`)),
|
optional(capture(domainRegexp), literal(`/`)),
|
||||||
capture(nameComponentRegexp,
|
capture(nameComponentRegexp,
|
||||||
optional(repeated(literal(`/`), nameComponentRegexp))))
|
optional(repeated(literal(`/`), nameComponentRegexp))))
|
||||||
|
|
||||||
@ -68,6 +68,25 @@ var (
|
|||||||
ReferenceRegexp = anchored(capture(NameRegexp),
|
ReferenceRegexp = anchored(capture(NameRegexp),
|
||||||
optional(literal(":"), capture(TagRegexp)),
|
optional(literal(":"), capture(TagRegexp)),
|
||||||
optional(literal("@"), capture(DigestRegexp)))
|
optional(literal("@"), capture(DigestRegexp)))
|
||||||
|
|
||||||
|
// IdentifierRegexp is the format for string identifier used as a
|
||||||
|
// content addressable identifier using sha256. These identifiers
|
||||||
|
// are like digests without the algorithm, since sha256 is used.
|
||||||
|
IdentifierRegexp = match(`([a-f0-9]{64})`)
|
||||||
|
|
||||||
|
// ShortIdentifierRegexp is the format used to represent a prefix
|
||||||
|
// of an identifier. A prefix may be used to match a sha256 identifier
|
||||||
|
// within a list of trusted identifiers.
|
||||||
|
ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`)
|
||||||
|
|
||||||
|
// anchoredIdentifierRegexp is used to check or match an
|
||||||
|
// identifier value, anchored at start and end of string.
|
||||||
|
anchoredIdentifierRegexp = anchored(IdentifierRegexp)
|
||||||
|
|
||||||
|
// anchoredShortIdentifierRegexp is used to check if a value
|
||||||
|
// is a possible identifier prefix, anchored at start and end
|
||||||
|
// of string.
|
||||||
|
anchoredShortIdentifierRegexp = anchored(ShortIdentifierRegexp)
|
||||||
)
|
)
|
||||||
|
|
||||||
// match compiles the string to a regular expression.
|
// match compiles the string to a regular expression.
|
||||||
|
Reference in New Issue
Block a user