175 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
| package imageparser
 | |
| 
 | |
| import (
 | |
| 	_ "crypto/sha256" // initialize crypto/sha256 to enable sha256 algorithm
 | |
| 	_ "crypto/sha512" // initialize crypto/sha512 to enable sha512 algorithm
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/distribution/distribution/v3/reference"
 | |
| )
 | |
| 
 | |
| // Components make up a whole image.
 | |
| // Basically we presume an image can be made of `[domain][:port][path]<name>[:tag][@sha256:digest]`, ie:
 | |
| // fictional.registry.example:10443/karmada/karmada-controller-manager:v1.0.0 or
 | |
| // fictional.registry.example:10443/karmada/karmada-controller-manager@sha256:50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c
 | |
| type Components struct {
 | |
| 	// hostname is the prefix of referencing image, like "registry.k8s.io".
 | |
| 	// It may optionally be followed by a port number, like "fictional.registry.example:10443".
 | |
| 	hostname string
 | |
| 	// repository is the short name of referencing image, like "karmada-controller-manager".
 | |
| 	// It may be made up of slash-separated components, like "karmada/karmada-controller-manager".
 | |
| 	repository string
 | |
| 	// tag is the tag of referencing image. ie:
 | |
| 	// - latest
 | |
| 	// - v1.19.1
 | |
| 	tag string
 | |
| 	// digest is the digest of referencing image. ie:
 | |
| 	// - sha256:50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c
 | |
| 	digest string
 | |
| }
 | |
| 
 | |
| // Hostname returns the hostname, as well known as image registry.
 | |
| func (c *Components) Hostname() string {
 | |
| 	return c.hostname
 | |
| }
 | |
| 
 | |
| // SetHostname sets the hostname.
 | |
| func (c *Components) SetHostname(hostname string) {
 | |
| 	c.hostname = hostname
 | |
| }
 | |
| 
 | |
| // RemoveHostname removes the hostname.
 | |
| func (c *Components) RemoveHostname() {
 | |
| 	c.hostname = ""
 | |
| }
 | |
| 
 | |
| // Repository returns the repository without hostname.
 | |
| func (c *Components) Repository() string {
 | |
| 	return c.repository
 | |
| }
 | |
| 
 | |
| // SetRepository sets the repository.
 | |
| func (c *Components) SetRepository(repository string) {
 | |
| 	c.repository = repository
 | |
| }
 | |
| 
 | |
| // RemoveRepository removes the repository.
 | |
| func (c *Components) RemoveRepository() {
 | |
| 	c.repository = ""
 | |
| }
 | |
| 
 | |
| // FullRepository returns the whole repository, including hostname if not empty.
 | |
| func (c *Components) FullRepository() string {
 | |
| 	if c.hostname == "" {
 | |
| 		return c.repository
 | |
| 	}
 | |
| 
 | |
| 	return c.hostname + "/" + c.repository
 | |
| }
 | |
| 
 | |
| // String returns the full name of the image, including repository and tag(or digest).
 | |
| func (c Components) String() string {
 | |
| 	if c.tag != "" {
 | |
| 		return c.FullRepository() + ":" + c.tag
 | |
| 	} else if c.digest != "" {
 | |
| 		return c.FullRepository() + "@" + c.digest
 | |
| 	}
 | |
| 
 | |
| 	return c.FullRepository()
 | |
| }
 | |
| 
 | |
| // Tag returns the tag.
 | |
| func (c *Components) Tag() string {
 | |
| 	return c.tag
 | |
| }
 | |
| 
 | |
| // SetTag sets the tag.
 | |
| func (c *Components) SetTag(tag string) {
 | |
| 	c.tag = tag
 | |
| }
 | |
| 
 | |
| // RemoveTag removes the tag.
 | |
| func (c *Components) RemoveTag() {
 | |
| 	c.tag = ""
 | |
| }
 | |
| 
 | |
| // Digest returns the digest.
 | |
| func (c *Components) Digest() string {
 | |
| 	return c.digest
 | |
| }
 | |
| 
 | |
| // SetDigest sets the digest.
 | |
| func (c *Components) SetDigest(digest string) {
 | |
| 	c.digest = digest
 | |
| }
 | |
| 
 | |
| // RemoveDigest removes the digest.
 | |
| func (c *Components) RemoveDigest() {
 | |
| 	c.digest = ""
 | |
| }
 | |
| 
 | |
| // TagOrDigest returns image tag if not empty otherwise returns image digest.
 | |
| func (c *Components) TagOrDigest() string {
 | |
| 	if c.tag != "" {
 | |
| 		return c.tag
 | |
| 	}
 | |
| 
 | |
| 	return c.digest
 | |
| }
 | |
| 
 | |
| // SetTagOrDigest sets image tag or digest by matching the input.
 | |
| func (c *Components) SetTagOrDigest(input string) {
 | |
| 	if anchoredTagRegexp.MatchString(input) {
 | |
| 		c.SetTag(input)
 | |
| 		c.RemoveDigest()
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	if anchoredDigestRegexp.MatchString(input) {
 | |
| 		c.SetDigest(input)
 | |
| 		c.RemoveTag()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // RemoveTagOrDigest removes tag or digest.
 | |
| // Since tag and digest don't co-exist, so remove tag if tag not empty, otherwise remove digest.
 | |
| func (c *Components) RemoveTagOrDigest() {
 | |
| 	if c.tag != "" {
 | |
| 		c.tag = ""
 | |
| 	} else if c.digest != "" {
 | |
| 		c.digest = ""
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Parse returns a Components of the given image.
 | |
| func Parse(image string) (*Components, error) {
 | |
| 	ref, err := reference.Parse(image)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	comp := &Components{}
 | |
| 	if named, ok := ref.(reference.Named); ok {
 | |
| 		comp.hostname, comp.repository = SplitHostname(named.Name())
 | |
| 	}
 | |
| 
 | |
| 	if tagged, ok := ref.(reference.Tagged); ok {
 | |
| 		comp.tag = tagged.Tag()
 | |
| 	} else if digested, ok := ref.(reference.Digested); ok {
 | |
| 		comp.digest = digested.Digest().String()
 | |
| 	}
 | |
| 
 | |
| 	return comp, nil
 | |
| }
 | |
| 
 | |
| // SplitHostname splits a repository name(ie: registry.k8s.io/kube-apiserver) to hostname(registry.k8s.io) and remotename(kube-apiserver) string.
 | |
| func SplitHostname(name string) (hostname, remoteName string) {
 | |
| 	i := strings.IndexRune(name, '/')
 | |
| 	if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
 | |
| 		hostname, remoteName = "", name
 | |
| 	} else {
 | |
| 		hostname, remoteName = name[:i], name[i+1:]
 | |
| 	}
 | |
| 	return
 | |
| }
 |