func verboseName(name reference.Named) string { name = reference.WithDefaultTag(name) tag := "" if tagged, ok := name.(reference.NamedTagged); ok { tag = tagged.Tag() } return name.FullName() + ":" + tag }
// NewReference returns a Docker reference for a named reference. The reference must satisfy !reference.IsNameOnly(). func NewReference(ref reference.Named) (types.ImageReference, error) { if reference.IsNameOnly(ref) { return nil, errors.Errorf("Docker reference %s has neither a tag nor a digest", ref.String()) } // A github.com/distribution/reference value can have a tag and a digest at the same time! // docker/reference does not handle that, so fail. // (Even if it were supported, the semantics of policy namespaces are unclear - should we drop // the tag or the digest first?) _, isTagged := ref.(reference.NamedTagged) _, isDigested := ref.(reference.Canonical) if isTagged && isDigested { return nil, errors.Errorf("Docker references with both a tag and digest are currently not supported") } return dockerReference{ ref: ref, }, nil }
// manifestSchema1FromComponents builds a new manifestSchema1 from the supplied data. func manifestSchema1FromComponents(ref reference.Named, fsLayers []fsLayersSchema1, history []historySchema1, architecture string) genericManifest { var name, tag string if ref != nil { // Well, what to do if it _is_ nil? Most consumers actually don't use these fields nowadays, so we might as well try not supplying them. name = ref.RemoteName() if tagged, ok := ref.(reference.NamedTagged); ok { tag = tagged.Tag() } } return &manifestSchema1{ Name: name, Tag: tag, Architecture: architecture, FSLayers: fsLayers, History: history, SchemaVersion: 1, } }
// DockerReferenceIdentity returns a string representation of the reference, suitable for policy lookup, // as a backend for ImageReference.PolicyConfigurationIdentity. // The reference must satisfy !reference.IsNameOnly(). func DockerReferenceIdentity(ref reference.Named) (string, error) { res := ref.FullName() tagged, isTagged := ref.(reference.NamedTagged) digested, isDigested := ref.(reference.Canonical) switch { case isTagged && isDigested: // This should not happen, docker/reference.ParseNamed drops the tag. return "", errors.Errorf("Unexpected Docker reference %s with both a name and a digest", ref.String()) case !isTagged && !isDigested: // This should not happen, the caller is expected to ensure !reference.IsNameOnly() return "", errors.Errorf("Internal inconsistency: Docker reference %s with neither a tag nor a digest", ref.String()) case isTagged: res = res + ":" + tagged.Tag() case isDigested: res = res + "@" + digested.Digest().String() default: // Coverage: The above was supposed to be exhaustive. return "", errors.New("Internal inconsistency, unexpected default branch") } return res, nil }
// DockerReferenceNamespaces returns a list of other policy configuration namespaces to search, // as a backend for ImageReference.PolicyConfigurationIdentity. // The reference must satisfy !reference.IsNameOnly(). func DockerReferenceNamespaces(ref reference.Named) []string { // Look for a match of the repository, and then of the possible parent // namespaces. Note that this only happens on the expanded host names // and repository names, i.e. "busybox" is looked up as "docker.io/library/busybox", // then in its parent "docker.io/library"; in none of "busybox", // un-namespaced "library" nor in "" supposedly implicitly representing "library/". // // ref.FullName() == ref.Hostname() + "/" + ref.RemoteName(), so the last // iteration matches the host name (for any namespace). res := []string{} name := ref.FullName() for { res = append(res, name) lastSlash := strings.LastIndex(name, "/") if lastSlash == -1 { break } name = name[:lastSlash] } return res }