github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/images/archive/reference.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package archive 18 19 import ( 20 "strings" 21 22 "github.com/containerd/containerd/reference" 23 distref "github.com/containerd/containerd/reference/docker" 24 "github.com/opencontainers/go-digest" 25 "github.com/pkg/errors" 26 ) 27 28 // FilterRefPrefix restricts references to having the given image 29 // prefix. Tag-only references will have the prefix prepended. 30 func FilterRefPrefix(image string) func(string) string { 31 return refTranslator(image, true) 32 } 33 34 // AddRefPrefix prepends the given image prefix to tag-only references, 35 // while leaving returning full references unmodified. 36 func AddRefPrefix(image string) func(string) string { 37 return refTranslator(image, false) 38 } 39 40 // refTranslator creates a reference which only has a tag or verifies 41 // a full reference. 42 func refTranslator(image string, checkPrefix bool) func(string) string { 43 return func(ref string) string { 44 // Check if ref is full reference 45 if strings.ContainsAny(ref, "/:@") { 46 // If not prefixed, don't include image 47 if checkPrefix && !isImagePrefix(ref, image) { 48 return "" 49 } 50 return ref 51 } 52 return image + ":" + ref 53 } 54 } 55 56 func isImagePrefix(s, prefix string) bool { 57 if !strings.HasPrefix(s, prefix) { 58 return false 59 } 60 if len(s) > len(prefix) { 61 switch s[len(prefix)] { 62 case '/', ':', '@': 63 // Prevent matching partial namespaces 64 default: 65 return false 66 } 67 } 68 return true 69 } 70 71 func normalizeReference(ref string) (string, error) { 72 // TODO: Replace this function to not depend on reference package 73 normalized, err := distref.ParseDockerRef(ref) 74 if err != nil { 75 return "", errors.Wrapf(err, "normalize image ref %q", ref) 76 } 77 78 return normalized.String(), nil 79 } 80 81 func familiarizeReference(ref string) (string, error) { 82 named, err := distref.ParseNormalizedNamed(ref) 83 if err != nil { 84 return "", errors.Wrapf(err, "failed to parse %q", ref) 85 } 86 named = distref.TagNameOnly(named) 87 88 return distref.FamiliarString(named), nil 89 } 90 91 func ociReferenceName(name string) string { 92 // OCI defines the reference name as only a tag excluding the 93 // repository. The containerd annotation contains the full image name 94 // since the tag is insufficient for correctly naming and referring to an 95 // image 96 var ociRef string 97 if spec, err := reference.Parse(name); err == nil { 98 ociRef = spec.Object 99 } else { 100 ociRef = name 101 } 102 103 return ociRef 104 } 105 106 // DigestTranslator creates a digest reference by adding the 107 // digest to an image name 108 func DigestTranslator(prefix string) func(digest.Digest) string { 109 return func(dgst digest.Digest) string { 110 return prefix + "@" + dgst.String() 111 } 112 }