github.com/containerd/nerdctl@v1.7.7/pkg/referenceutil/referenceutil.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 referenceutil 18 19 import ( 20 "fmt" 21 "path" 22 "strings" 23 24 refdocker "github.com/distribution/reference" 25 "github.com/ipfs/go-cid" 26 ) 27 28 // Reference is a reference to an image. 29 type Reference interface { 30 31 // String returns the full reference which can be understood by containerd. 32 String() string 33 } 34 35 // ParseAny parses the passed reference with allowing it to be non-docker reference. 36 // If the ref has IPFS scheme or can be parsed as CID, it's parsed as an IPFS reference. 37 // Otherwise it's parsed as a docker reference. 38 func ParseAny(rawRef string) (Reference, error) { 39 if scheme, ref, err := ParseIPFSRefWithScheme(rawRef); err == nil { 40 return stringRef{scheme: scheme, s: ref}, nil 41 } 42 if c, err := cid.Decode(rawRef); err == nil { 43 return c, nil 44 } 45 return ParseDockerRef(rawRef) 46 } 47 48 // ParseDockerRef parses the passed reference with assuming it's a docker reference. 49 func ParseDockerRef(rawRef string) (refdocker.Named, error) { 50 return refdocker.ParseDockerRef(rawRef) 51 } 52 53 // ParseIPFSRefWithScheme parses the passed reference with assuming it's an IPFS reference with scheme prefix. 54 func ParseIPFSRefWithScheme(name string) (scheme, ref string, err error) { 55 if strings.HasPrefix(name, "ipfs://") || strings.HasPrefix(name, "ipns://") { 56 return name[:4], name[7:], nil 57 } 58 return "", "", fmt.Errorf("reference is not an IPFS reference") 59 } 60 61 type stringRef struct { 62 scheme string 63 s string 64 } 65 66 func (s stringRef) String() string { 67 return s.s 68 } 69 70 // SuggestContainerName generates a container name from name. 71 // The result MUST NOT be parsed. 72 func SuggestContainerName(rawRef, containerID string) string { 73 const shortIDLength = 5 74 if len(containerID) < shortIDLength { 75 panic(fmt.Errorf("got too short (< %d) container ID: %q", shortIDLength, containerID)) 76 } 77 name := "untitled-" + containerID[:shortIDLength] 78 if rawRef != "" { 79 r, err := ParseAny(rawRef) 80 if err == nil { 81 switch rr := r.(type) { 82 case refdocker.Named: 83 if rrName := rr.Name(); rrName != "" { 84 imageNameBased := path.Base(rrName) 85 if imageNameBased != "" { 86 name = imageNameBased + "-" + containerID[:shortIDLength] 87 } 88 } 89 case cid.Cid: 90 name = "ipfs" + "-" + rr.String()[:shortIDLength] + "-" + containerID[:shortIDLength] 91 case stringRef: 92 name = rr.scheme + "-" + rr.s[:shortIDLength] + "-" + containerID[:shortIDLength] 93 } 94 } 95 } 96 return name 97 }