github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/registry/util.go (about)

     1  /*
     2  Copyright The Helm 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 registry // import "github.com/stefanmcshane/helm/pkg/registry"
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"io"
    24  	"strings"
    25  
    26  	"github.com/Masterminds/semver/v3"
    27  	"github.com/pkg/errors"
    28  	"github.com/sirupsen/logrus"
    29  	orascontext "oras.land/oras-go/pkg/context"
    30  	"oras.land/oras-go/pkg/registry"
    31  
    32  	"github.com/stefanmcshane/helm/pkg/chart"
    33  	"github.com/stefanmcshane/helm/pkg/chart/loader"
    34  )
    35  
    36  // IsOCI determines whether or not a URL is to be treated as an OCI URL
    37  func IsOCI(url string) bool {
    38  	return strings.HasPrefix(url, fmt.Sprintf("%s://", OCIScheme))
    39  }
    40  
    41  // ContainsTag determines whether a tag is found in a provided list of tags
    42  func ContainsTag(tags []string, tag string) bool {
    43  	for _, t := range tags {
    44  		if tag == t {
    45  			return true
    46  		}
    47  	}
    48  	return false
    49  }
    50  
    51  func GetTagMatchingVersionOrConstraint(tags []string, versionString string) (string, error) {
    52  	var constraint *semver.Constraints
    53  	if versionString == "" {
    54  		// If string is empty, set wildcard constraint
    55  		constraint, _ = semver.NewConstraint("*")
    56  	} else {
    57  		// when customer input exact version, check whether have exact match
    58  		// one first
    59  		for _, v := range tags {
    60  			if versionString == v {
    61  				return v, nil
    62  			}
    63  		}
    64  
    65  		// Otherwise set constraint to the string given
    66  		var err error
    67  		constraint, err = semver.NewConstraint(versionString)
    68  		if err != nil {
    69  			return "", err
    70  		}
    71  	}
    72  
    73  	// Otherwise try to find the first available version matching the string,
    74  	// in case it is a constraint
    75  	for _, v := range tags {
    76  		test, err := semver.NewVersion(v)
    77  		if err != nil {
    78  			continue
    79  		}
    80  		if constraint.Check(test) {
    81  			return v, nil
    82  		}
    83  	}
    84  
    85  	return "", errors.Errorf("Could not locate a version matching provided version string %s", versionString)
    86  }
    87  
    88  // extractChartMeta is used to extract a chart metadata from a byte array
    89  func extractChartMeta(chartData []byte) (*chart.Metadata, error) {
    90  	ch, err := loader.LoadArchive(bytes.NewReader(chartData))
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	return ch.Metadata, nil
    95  }
    96  
    97  // ctx retrieves a fresh context.
    98  // disable verbose logging coming from ORAS (unless debug is enabled)
    99  func ctx(out io.Writer, debug bool) context.Context {
   100  	if !debug {
   101  		return orascontext.Background()
   102  	}
   103  	ctx := orascontext.WithLoggerFromWriter(context.Background(), out)
   104  	orascontext.GetLogger(ctx).Logger.SetLevel(logrus.DebugLevel)
   105  	return ctx
   106  }
   107  
   108  // parseReference will parse and validate the reference, and clean tags when
   109  // applicable tags are only cleaned when plus (+) signs are present, and are
   110  // converted to underscores (_) before pushing
   111  // See https://github.com/helm/helm/issues/10166
   112  func parseReference(raw string) (registry.Reference, error) {
   113  	// The sole possible reference modification is replacing plus (+) signs
   114  	// present in tags with underscores (_). To do this properly, we first
   115  	// need to identify a tag, and then pass it on to the reference parser
   116  	// NOTE: Passing immediately to the reference parser will fail since (+)
   117  	// signs are an invalid tag character, and simply replacing all plus (+)
   118  	// occurrences could invalidate other portions of the URI
   119  	parts := strings.Split(raw, ":")
   120  	if len(parts) > 1 && !strings.Contains(parts[len(parts)-1], "/") {
   121  		tag := parts[len(parts)-1]
   122  
   123  		if tag != "" {
   124  			// Replace any plus (+) signs with known underscore (_) conversion
   125  			newTag := strings.ReplaceAll(tag, "+", "_")
   126  			raw = strings.ReplaceAll(raw, tag, newTag)
   127  		}
   128  	}
   129  
   130  	return registry.ParseReference(raw)
   131  }