|
|
|
|
@ -29,6 +29,8 @@ import (
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/Masterminds/semver/v3"
|
|
|
|
|
|
|
|
|
|
"helm.sh/helm/v4/internal/fileutil"
|
|
|
|
|
ifs "helm.sh/helm/v4/internal/third_party/dep/fs"
|
|
|
|
|
"helm.sh/helm/v4/internal/urlutil"
|
|
|
|
|
@ -149,12 +151,7 @@ func (c *ChartDownloader) DownloadTo(ref, version, dest string) (string, *proven
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name := filepath.Base(u.Path)
|
|
|
|
|
if u.Scheme == registry.OCIScheme {
|
|
|
|
|
idx := strings.LastIndexByte(name, ':')
|
|
|
|
|
name = fmt.Sprintf("%s-%s.tgz", name[:idx], name[idx+1:])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name := c.getChartName(u.String())
|
|
|
|
|
destfile := filepath.Join(dest, name)
|
|
|
|
|
if err := fileutil.AtomicWriteFile(destfile, data, 0644); err != nil {
|
|
|
|
|
return destfile, nil, err
|
|
|
|
|
@ -302,11 +299,7 @@ func (c *ChartDownloader) DownloadToCache(ref, version string) (string, *provena
|
|
|
|
|
// Note, this does make an assumption that the name/version is unique to a
|
|
|
|
|
// hash when a provenance file is used. If this isn't true, this section of code
|
|
|
|
|
// will need to be reworked.
|
|
|
|
|
name := filepath.Base(u.Path)
|
|
|
|
|
if u.Scheme == registry.OCIScheme {
|
|
|
|
|
idx := strings.LastIndexByte(name, ':')
|
|
|
|
|
name = fmt.Sprintf("%s-%s.tgz", name[:idx], name[idx+1:])
|
|
|
|
|
}
|
|
|
|
|
name := c.getChartName(u.String())
|
|
|
|
|
|
|
|
|
|
// Copy chart to a known location with the right name for verification and then
|
|
|
|
|
// clean it up.
|
|
|
|
|
@ -353,9 +346,9 @@ func (c *ChartDownloader) DownloadToCache(ref, version string) (string, *provena
|
|
|
|
|
//
|
|
|
|
|
// TODO: support OCI hash
|
|
|
|
|
func (c *ChartDownloader) ResolveChartVersion(ref, version string) (string, *url.URL, error) {
|
|
|
|
|
u, err := url.Parse(ref)
|
|
|
|
|
u, err := c.parseChartURL(ref, version)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", nil, fmt.Errorf("invalid chart URL format: %s", ref)
|
|
|
|
|
return "", u, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if registry.IsOCI(u.String()) {
|
|
|
|
|
@ -574,6 +567,69 @@ func (c *ChartDownloader) scanReposForURL(u string, rf *repo.File) (*repo.Entry,
|
|
|
|
|
return nil, ErrNoOwnerRepo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *ChartDownloader) getChartName(url string) string {
|
|
|
|
|
name := filepath.Base(url)
|
|
|
|
|
if registry.IsOCI(url) {
|
|
|
|
|
idx := strings.LastIndexByte(name, ':')
|
|
|
|
|
name = fmt.Sprintf("%s-%s.tgz", name[:idx], name[idx+1:])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *ChartDownloader) parseChartURL(ref string, version string) (*url.URL, error) {
|
|
|
|
|
u, err := url.Parse(ref)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("invalid chart URL format: %s", ref)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if registry.IsOCI(u.String()) {
|
|
|
|
|
refAlreadyHasTagOrDigest := strings.Contains(u.Path, ":") || strings.Contains(u.Path, "@")
|
|
|
|
|
if refAlreadyHasTagOrDigest {
|
|
|
|
|
return u, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tag, err := c.getOciTag(ref, version)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u.Path = fmt.Sprintf("%s:%s", u.Path, tag)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return u, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *ChartDownloader) getOciTag(ref, version string) (string, error) {
|
|
|
|
|
var tag string
|
|
|
|
|
|
|
|
|
|
// 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.RegistryClient.Tags(strings.TrimPrefix(ref, fmt.Sprintf("%s://", registry.OCIScheme)))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
if len(tags) == 0 {
|
|
|
|
|
return "", fmt.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 = registry.GetTagMatchingVersionOrConstraint(tags, version)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tag, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func loadRepoConfig(file string) (*repo.File, error) {
|
|
|
|
|
r, err := repo.LoadFile(file)
|
|
|
|
|
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
|
|
|
|
|