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
|
|
}
|