github.com/Racer159/helm-experiment@v0.0.0-20230822001441-1eb31183f614/src/flags.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 cmd 18 19 import ( 20 "flag" 21 "fmt" 22 "log" 23 "path/filepath" 24 "sort" 25 "strings" 26 27 "github.com/spf13/cobra" 28 "github.com/spf13/pflag" 29 "k8s.io/klog/v2" 30 31 "helm.sh/helm/v3/pkg/action" 32 "helm.sh/helm/v3/pkg/cli/output" 33 "helm.sh/helm/v3/pkg/cli/values" 34 "helm.sh/helm/v3/pkg/helmpath" 35 "helm.sh/helm/v3/pkg/postrender" 36 "helm.sh/helm/v3/pkg/repo" 37 ) 38 39 const ( 40 outputFlag = "output" 41 postRenderFlag = "post-renderer" 42 postRenderArgsFlag = "post-renderer-args" 43 ) 44 45 func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) { 46 f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)") 47 f.StringArrayVar(&v.Values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") 48 f.StringArrayVar(&v.StringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") 49 f.StringArrayVar(&v.FileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") 50 f.StringArrayVar(&v.JSONValues, "set-json", []string{}, "set JSON values on the command line (can specify multiple or separate values with commas: key1=jsonval1,key2=jsonval2)") 51 } 52 53 func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) { 54 f.StringVar(&c.Version, "version", "", "specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used") 55 f.BoolVar(&c.Verify, "verify", false, "verify the package before using it") 56 f.StringVar(&c.Keyring, "keyring", defaultKeyring(), "location of public keys used for verification") 57 f.StringVar(&c.RepoURL, "repo", "", "chart repository url where to locate the requested chart") 58 f.StringVar(&c.Username, "username", "", "chart repository username where to locate the requested chart") 59 f.StringVar(&c.Password, "password", "", "chart repository password where to locate the requested chart") 60 f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") 61 f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file") 62 f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download") 63 f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") 64 f.BoolVar(&c.PassCredentialsAll, "pass-credentials", false, "pass credentials to all domains") 65 } 66 67 // bindOutputFlag will add the output flag to the given command and bind the 68 // value to the given format pointer 69 func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) { 70 cmd.Flags().VarP(newOutputValue(output.Table, varRef), outputFlag, "o", 71 fmt.Sprintf("prints the output in the specified format. Allowed values: %s", strings.Join(output.Formats(), ", "))) 72 73 err := cmd.RegisterFlagCompletionFunc(outputFlag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 74 var formatNames []string 75 for format, desc := range output.FormatsWithDesc() { 76 formatNames = append(formatNames, fmt.Sprintf("%s\t%s", format, desc)) 77 } 78 79 // Sort the results to get a deterministic order for the tests 80 sort.Strings(formatNames) 81 return formatNames, cobra.ShellCompDirectiveNoFileComp 82 }) 83 84 if err != nil { 85 log.Fatal(err) 86 } 87 } 88 89 type outputValue output.Format 90 91 func newOutputValue(defaultValue output.Format, p *output.Format) *outputValue { 92 *p = defaultValue 93 return (*outputValue)(p) 94 } 95 96 func (o *outputValue) String() string { 97 // It is much cleaner looking (and technically less allocations) to just 98 // convert to a string rather than type asserting to the underlying 99 // output.Format 100 return string(*o) 101 } 102 103 func (o *outputValue) Type() string { 104 return "format" 105 } 106 107 func (o *outputValue) Set(s string) error { 108 outfmt, err := output.ParseFormat(s) 109 if err != nil { 110 return err 111 } 112 *o = outputValue(outfmt) 113 return nil 114 } 115 116 func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) { 117 p := &postRendererOptions{varRef, "", []string{}} 118 cmd.Flags().Var(&postRendererString{p}, postRenderFlag, "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path") 119 cmd.Flags().Var(&postRendererArgsSlice{p}, postRenderArgsFlag, "an argument to the post-renderer (can specify multiple)") 120 } 121 122 type postRendererOptions struct { 123 renderer *postrender.PostRenderer 124 binaryPath string 125 args []string 126 } 127 128 type postRendererString struct { 129 options *postRendererOptions 130 } 131 132 func (p *postRendererString) String() string { 133 return p.options.binaryPath 134 } 135 136 func (p *postRendererString) Type() string { 137 return "postRendererString" 138 } 139 140 func (p *postRendererString) Set(val string) error { 141 if val == "" { 142 return nil 143 } 144 p.options.binaryPath = val 145 pr, err := postrender.NewExec(p.options.binaryPath, p.options.args...) 146 if err != nil { 147 return err 148 } 149 *p.options.renderer = pr 150 return nil 151 } 152 153 type postRendererArgsSlice struct { 154 options *postRendererOptions 155 } 156 157 func (p *postRendererArgsSlice) String() string { 158 return "[" + strings.Join(p.options.args, ",") + "]" 159 } 160 161 func (p *postRendererArgsSlice) Type() string { 162 return "postRendererArgsSlice" 163 } 164 165 func (p *postRendererArgsSlice) Set(val string) error { 166 167 // a post-renderer defined by a user may accept empty arguments 168 p.options.args = append(p.options.args, val) 169 170 if p.options.binaryPath == "" { 171 return nil 172 } 173 // overwrite if already create PostRenderer by `post-renderer` flags 174 pr, err := postrender.NewExec(p.options.binaryPath, p.options.args...) 175 if err != nil { 176 return err 177 } 178 *p.options.renderer = pr 179 return nil 180 } 181 182 func (p *postRendererArgsSlice) Append(val string) error { 183 p.options.args = append(p.options.args, val) 184 return nil 185 } 186 187 func (p *postRendererArgsSlice) Replace(val []string) error { 188 p.options.args = val 189 return nil 190 } 191 192 func (p *postRendererArgsSlice) GetSlice() []string { 193 return p.options.args 194 } 195 196 func compVersionFlag(chartRef string, toComplete string) ([]string, cobra.ShellCompDirective) { 197 chartInfo := strings.Split(chartRef, "/") 198 if len(chartInfo) != 2 { 199 return nil, cobra.ShellCompDirectiveNoFileComp 200 } 201 202 repoName := chartInfo[0] 203 chartName := chartInfo[1] 204 205 path := filepath.Join(settings.RepositoryCache, helmpath.CacheIndexFile(repoName)) 206 207 var versions []string 208 if indexFile, err := repo.LoadIndexFile(path); err == nil { 209 for _, details := range indexFile.Entries[chartName] { 210 appVersion := details.Metadata.AppVersion 211 appVersionDesc := "" 212 if appVersion != "" { 213 appVersionDesc = fmt.Sprintf("App: %s, ", appVersion) 214 } 215 created := details.Created.Format("January 2, 2006") 216 createdDesc := "" 217 if created != "" { 218 createdDesc = fmt.Sprintf("Created: %s ", created) 219 } 220 deprecated := "" 221 if details.Metadata.Deprecated { 222 deprecated = "(deprecated)" 223 } 224 versions = append(versions, fmt.Sprintf("%s\t%s%s%s", details.Metadata.Version, appVersionDesc, createdDesc, deprecated)) 225 } 226 } 227 228 return versions, cobra.ShellCompDirectiveNoFileComp 229 } 230 231 // addKlogFlags adds flags from k8s.io/klog 232 // marks the flags as hidden to avoid polluting the help text 233 func addKlogFlags(fs *pflag.FlagSet) { 234 local := flag.NewFlagSet("klog", flag.ExitOnError) 235 klog.InitFlags(local) 236 local.VisitAll(func(fl *flag.Flag) { 237 fl.Name = normalize(fl.Name) 238 if fs.Lookup(fl.Name) != nil { 239 return 240 } 241 newflag := pflag.PFlagFromGoFlag(fl) 242 newflag.Hidden = true 243 fs.AddFlag(newflag) 244 }) 245 } 246 247 // normalize replaces underscores with hyphens 248 func normalize(s string) string { 249 return strings.ReplaceAll(s, "_", "-") 250 }