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 }