|
|
@ -22,6 +22,7 @@ import (
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"net/url"
|
|
|
|
"sort"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
|
@ -319,7 +320,7 @@ type (
|
|
|
|
|
|
|
|
|
|
|
|
// Pull downloads a chart from a registry
|
|
|
|
// Pull downloads a chart from a registry
|
|
|
|
func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) {
|
|
|
|
func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) {
|
|
|
|
parsedRef, err := NewReference(ref)
|
|
|
|
parsedRef, err := newReference(ref)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -351,7 +352,7 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var descriptors, layers []ocispec.Descriptor
|
|
|
|
var descriptors, layers []ocispec.Descriptor
|
|
|
|
remotesResolver, err := c.resolver(parsedRef.OrasReference)
|
|
|
|
remotesResolver, err := c.resolver(parsedRef.orasReference)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -535,7 +536,7 @@ type (
|
|
|
|
|
|
|
|
|
|
|
|
// Push uploads a chart to a registry.
|
|
|
|
// Push uploads a chart to a registry.
|
|
|
|
func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResult, error) {
|
|
|
|
func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResult, error) {
|
|
|
|
parsedRef, err := NewReference(ref)
|
|
|
|
parsedRef, err := newReference(ref)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -594,12 +595,12 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
remotesResolver, err := c.resolver(parsedRef.OrasReference)
|
|
|
|
remotesResolver, err := c.resolver(parsedRef.orasReference)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
registryStore := content.Registry{Resolver: remotesResolver}
|
|
|
|
registryStore := content.Registry{Resolver: remotesResolver}
|
|
|
|
_, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.OrasReference.String(), registryStore, "",
|
|
|
|
_, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.orasReference.String(), registryStore, "",
|
|
|
|
oras.WithNameValidation(nil))
|
|
|
|
oras.WithNameValidation(nil))
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
@ -630,7 +631,7 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Fprintf(c.out, "Pushed: %s\n", result.Ref)
|
|
|
|
fmt.Fprintf(c.out, "Pushed: %s\n", result.Ref)
|
|
|
|
fmt.Fprintf(c.out, "Digest: %s\n", result.Manifest.Digest)
|
|
|
|
fmt.Fprintf(c.out, "Digest: %s\n", result.Manifest.Digest)
|
|
|
|
if strings.Contains(parsedRef.OrasReference.Reference, "_") {
|
|
|
|
if strings.Contains(parsedRef.orasReference.Reference, "_") {
|
|
|
|
fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref)
|
|
|
|
fmt.Fprintf(c.out, "%s contains an underscore.\n", result.Ref)
|
|
|
|
fmt.Fprint(c.out, registryUnderscoreMessage+"\n")
|
|
|
|
fmt.Fprint(c.out, registryUnderscoreMessage+"\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -705,7 +706,7 @@ func (c *Client) Tags(ref string) ([]string, error) {
|
|
|
|
// Resolve a reference to a descriptor.
|
|
|
|
// Resolve a reference to a descriptor.
|
|
|
|
func (c *Client) Resolve(ref string) (*ocispec.Descriptor, error) {
|
|
|
|
func (c *Client) Resolve(ref string) (*ocispec.Descriptor, error) {
|
|
|
|
ctx := context.Background()
|
|
|
|
ctx := context.Background()
|
|
|
|
parsedRef, err := NewReference(ref)
|
|
|
|
parsedRef, err := newReference(ref)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -713,7 +714,7 @@ func (c *Client) Resolve(ref string) (*ocispec.Descriptor, error) {
|
|
|
|
return nil, nil
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
remotesResolver, err := c.resolver(parsedRef.OrasReference)
|
|
|
|
remotesResolver, err := c.resolver(parsedRef.orasReference)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -721,3 +722,69 @@ func (c *Client) Resolve(ref string) (*ocispec.Descriptor, error) {
|
|
|
|
_, desc, err := remotesResolver.Resolve(ctx, ref)
|
|
|
|
_, desc, err := remotesResolver.Resolve(ctx, ref)
|
|
|
|
return &desc, err
|
|
|
|
return &desc, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateReference for path and version
|
|
|
|
|
|
|
|
func (c *Client) ValidateReference(ref, version string, u *url.URL) (*url.URL, error) {
|
|
|
|
|
|
|
|
var tag string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
registryReference, err := newReference(u.Path)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if version == "" {
|
|
|
|
|
|
|
|
// Use OCI URI tag as default
|
|
|
|
|
|
|
|
version = registryReference.Tag
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if registryReference.Tag != "" && registryReference.Tag != version {
|
|
|
|
|
|
|
|
return nil, errors.Errorf("chart reference and version mismatch: %s is not %s", version, registryReference.Tag)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if registryReference.Digest != "" {
|
|
|
|
|
|
|
|
if registryReference.Tag == "" {
|
|
|
|
|
|
|
|
// Install by digest only
|
|
|
|
|
|
|
|
return u, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Validate the tag if it was specified
|
|
|
|
|
|
|
|
path := registryReference.Registry + "/" + registryReference.Repository + ":" + registryReference.Tag
|
|
|
|
|
|
|
|
desc, err := c.Resolve(path)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
// The resource does not have to be tagged when digest is specified
|
|
|
|
|
|
|
|
return u, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if desc != nil && desc.Digest.String() != registryReference.Digest {
|
|
|
|
|
|
|
|
return nil, errors.Errorf("chart reference digest mismatch: %s is not %s", desc.Digest.String(), registryReference.Digest)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return u, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Evaluate whether an explicit version has been provided. Otherwise, determine version to use
|
|
|
|
|
|
|
|
_, errSemVer := semver.NewVersion(version)
|
|
|
|
|
|
|
|
if errSemVer == nil {
|
|
|
|
|
|
|
|
tag = version
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Retrieve list of repository tags
|
|
|
|
|
|
|
|
tags, err := c.Tags(strings.TrimPrefix(ref, fmt.Sprintf("%s://", OCIScheme)))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(tags) == 0 {
|
|
|
|
|
|
|
|
return nil, errors.Errorf("Unable to locate any tags in provided repository: %s", ref)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Determine if version provided
|
|
|
|
|
|
|
|
// If empty, try to get the highest available tag
|
|
|
|
|
|
|
|
// If exact version, try to find it
|
|
|
|
|
|
|
|
// If semver constraint string, try to find a match
|
|
|
|
|
|
|
|
tag, err = GetTagMatchingVersionOrConstraint(tags, version)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u.Path = fmt.Sprintf("%s/%s:%s", registryReference.Registry, registryReference.Repository, tag)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return u, err
|
|
|
|
|
|
|
|
}
|
|
|
|