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  }