github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/libpod/image/parts.go (about) 1 package image 2 3 import ( 4 "strings" 5 6 "github.com/containers/image/v5/docker/reference" 7 "github.com/pkg/errors" 8 ) 9 10 // imageParts describes the parts of an image's name 11 type imageParts struct { 12 unnormalizedRef reference.Named // WARNING: Did not go through docker.io[/library] normalization 13 hasRegistry bool 14 } 15 16 // Registries must contain a ":" or a "." or be localhost; this helper exists for users of reference.Parse. 17 // For inputs that should use the docker.io[/library] normalization, use reference.ParseNormalizedNamed instead. 18 func isRegistry(name string) bool { 19 return strings.ContainsAny(name, ".:") || name == "localhost" 20 } 21 22 // GetImageBaseName uses decompose and string splits to obtain the base 23 // name of an image. Doing this here because it beats changing the 24 // imageParts struct names to be exported as well. 25 func GetImageBaseName(input string) (string, error) { 26 decomposedImage, err := decompose(input) 27 if err != nil { 28 return "", err 29 } 30 splitImageName := strings.Split(decomposedImage.unnormalizedRef.Name(), "/") 31 return splitImageName[len(splitImageName)-1], nil 32 } 33 34 // decompose breaks an input name into an imageParts description 35 func decompose(input string) (imageParts, error) { 36 imgRef, err := reference.Parse(input) 37 if err != nil { 38 return imageParts{}, err 39 } 40 unnormalizedNamed := imgRef.(reference.Named) 41 // ip.unnormalizedRef, because it uses reference.Parse and not reference.ParseNormalizedNamed, 42 // does not use the standard heuristics for domains vs. namespaces/repos, so we need to check 43 // explicitly. 44 hasRegistry := isRegistry(reference.Domain(unnormalizedNamed)) 45 return imageParts{ 46 unnormalizedRef: unnormalizedNamed, 47 hasRegistry: hasRegistry, 48 }, nil 49 } 50 51 // suspiciousRefNameTagValuesForSearch returns a "tag" value used in a previous implementation. 52 // This exists only to preserve existing behavior in heuristic code; it’s dubious that that behavior is correct, 53 // gespecially for the tag value. 54 func (ip *imageParts) suspiciousRefNameTagValuesForSearch() (string, string, string) { 55 registry := reference.Domain(ip.unnormalizedRef) 56 imageName := reference.Path(ip.unnormalizedRef) 57 // ip.unnormalizedRef, because it uses reference.Parse and not reference.ParseNormalizedNamed, 58 // does not use the standard heuristics for domains vs. namespaces/repos. 59 if registry != "" && !isRegistry(registry) { 60 imageName = registry + "/" + imageName 61 registry = "" 62 } 63 64 var tag string 65 if tagged, isTagged := ip.unnormalizedRef.(reference.NamedTagged); isTagged { 66 tag = tagged.Tag() 67 } else if _, hasDigest := ip.unnormalizedRef.(reference.Digested); hasDigest { 68 tag = "none" 69 } else { 70 tag = LatestTag 71 } 72 return registry, imageName, tag 73 } 74 75 // referenceWithRegistry returns a (normalized) reference.Named composed of ip (with !ip.hasRegistry) 76 // qualified with registry. 77 func (ip *imageParts) referenceWithRegistry(registry string) (reference.Named, error) { 78 if ip.hasRegistry { 79 return nil, errors.Errorf("internal error: referenceWithRegistry called on imageParts with a registry (%#v)", *ip) 80 } 81 // We could build a reference.WithName+WithTag/WithDigest here, but we need to round-trip via a string 82 // and a ParseNormalizedNamed anyway to get the right normalization of docker.io/library, so 83 // just use a string directly. 84 qualified := registry + "/" + ip.unnormalizedRef.String() 85 ref, err := reference.ParseNormalizedNamed(qualified) 86 if err != nil { 87 return nil, errors.Wrapf(err, "error normalizing registry+unqualified reference %#v", qualified) 88 } 89 return ref, nil 90 } 91 92 // normalizedReference returns a (normalized) reference for ip (with ip.hasRegistry) 93 func (ip *imageParts) normalizedReference() (reference.Named, error) { 94 if !ip.hasRegistry { 95 return nil, errors.Errorf("internal error: normalizedReference called on imageParts without a registry (%#v)", *ip) 96 } 97 // We need to round-trip via a string to get the right normalization of docker.io/library 98 s := ip.unnormalizedRef.String() 99 ref, err := reference.ParseNormalizedNamed(s) 100 if err != nil { // Should never happen 101 return nil, errors.Wrapf(err, "error normalizing qualified reference %#v", s) 102 } 103 return ref, nil 104 }