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  }