github.com/kristofferahl/go-centry@v1.5.0/cmd/centry/options.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/kristofferahl/go-centry/internal/pkg/cmd"
     8  	"github.com/kristofferahl/go-centry/internal/pkg/config"
     9  	"github.com/kristofferahl/go-centry/internal/pkg/shell"
    10  	"github.com/sirupsen/logrus"
    11  	"github.com/urfave/cli/v2"
    12  )
    13  
    14  func configureDefaultOptions() {
    15  	cli.HelpFlag = &cli.BoolFlag{
    16  		Name:    "help",
    17  		Aliases: []string{"h"},
    18  		Usage:   "Show help",
    19  	}
    20  	cli.VersionFlag = &cli.BoolFlag{
    21  		Name:    "version",
    22  		Aliases: []string{"v"},
    23  		Usage:   "Print the version",
    24  	}
    25  }
    26  
    27  func createGlobalOptions(runtime *Runtime) *cmd.OptionsSet {
    28  	context := runtime.context
    29  	manifest := context.manifest
    30  
    31  	// Add global options
    32  	options := cmd.NewOptionsSet("Global")
    33  
    34  	options.Add(&cmd.Option{
    35  		Type:        cmd.StringOption,
    36  		Name:        "centry-config-log-level",
    37  		Description: "Overrides the log level",
    38  		Default:     manifest.Config.Log.Level,
    39  		Hidden:      manifest.Config.HideInternalOptions,
    40  		Internal:    true,
    41  	})
    42  	options.Add(&cmd.Option{
    43  		Type:        cmd.BoolOption,
    44  		Name:        "centry-quiet",
    45  		Description: "Disables logging",
    46  		Default:     false,
    47  		Hidden:      manifest.Config.HideInternalOptions,
    48  		Internal:    true,
    49  	})
    50  
    51  	// Adding global options specified by the manifest
    52  	for _, o := range manifest.Options {
    53  		o := o
    54  
    55  		if context.optionEnabledFunc != nil && context.optionEnabledFunc(o) == false {
    56  			continue
    57  		}
    58  
    59  		err := options.Add(&cmd.Option{
    60  			Type:        o.Type,
    61  			Name:        o.Name,
    62  			Short:       o.Short,
    63  			Description: o.Description,
    64  			EnvName:     o.EnvName,
    65  			Values:      mapOptionValuesToCmdOptionValues(o),
    66  			Default:     o.Default,
    67  			Required:    o.Required,
    68  			Hidden:      o.Hidden,
    69  		})
    70  
    71  		if err != nil {
    72  			runtime.events = append(runtime.events, fmt.Sprintf("failed to register global option \"%s\", error: %v", o.Name, err))
    73  			continue
    74  		}
    75  
    76  		runtime.events = append(runtime.events, fmt.Sprintf("registered global option \"%s\"", o.Name))
    77  	}
    78  
    79  	return options
    80  }
    81  
    82  func optionsSetToFlags(options *cmd.OptionsSet) []cli.Flag {
    83  	flags := make([]cli.Flag, 0)
    84  
    85  	for _, o := range options.Sorted() {
    86  		short := []string{o.Short}
    87  		if o.Short == "" {
    88  			short = nil
    89  		}
    90  
    91  		switch o.Type {
    92  		case cmd.SelectOption:
    93  			def := false
    94  			if o.Default != nil {
    95  				def = o.Default.(bool)
    96  			}
    97  			flags = append(flags, &cli.BoolFlag{
    98  				Name:     o.Name,
    99  				Aliases:  short,
   100  				Usage:    o.Description,
   101  				Value:    def,
   102  				Required: false,
   103  				Hidden:   o.Hidden,
   104  			})
   105  		case cmd.SelectOptionV2:
   106  			def := false
   107  			if o.Default != nil {
   108  				def = o.Default.(bool)
   109  			}
   110  			for _, v := range o.Values {
   111  				short := []string{v.Short}
   112  				if v.Short == "" {
   113  					short = nil
   114  				}
   115  				flags = append(flags, &SelectOptionFlag{
   116  					BoolFlag: cli.BoolFlag{
   117  						Name:     v.Name,
   118  						Aliases:  short,
   119  						Usage:    o.Description,
   120  						Value:    def,
   121  						Required: false,
   122  						Hidden:   o.Hidden,
   123  					},
   124  					GroupName:     o.Name,
   125  					GroupRequired: o.Required,
   126  					Values:        o.Values,
   127  				})
   128  			}
   129  		case cmd.IntegerOption:
   130  			def := 0
   131  			if o.Default != nil {
   132  				def = o.Default.(int)
   133  			}
   134  			flags = append(flags, &cli.IntFlag{
   135  				Name:     o.Name,
   136  				Aliases:  short,
   137  				Usage:    o.Description,
   138  				Value:    def,
   139  				Required: o.Required,
   140  				Hidden:   o.Hidden,
   141  			})
   142  		case cmd.BoolOption:
   143  			def := false
   144  			if o.Default != nil {
   145  				def = o.Default.(bool)
   146  			}
   147  			flags = append(flags, &cli.BoolFlag{
   148  				Name:     o.Name,
   149  				Aliases:  short,
   150  				Usage:    o.Description,
   151  				Value:    def,
   152  				Required: o.Required,
   153  				Hidden:   o.Hidden,
   154  			})
   155  		case cmd.StringOption:
   156  			def := ""
   157  			if o.Default != nil {
   158  				def = o.Default.(string)
   159  			}
   160  			flags = append(flags, &cli.StringFlag{
   161  				Name:     o.Name,
   162  				Aliases:  short,
   163  				Usage:    o.Description,
   164  				Value:    def,
   165  				Required: o.Required,
   166  				Hidden:   o.Hidden,
   167  			})
   168  		default:
   169  			panic(fmt.Sprintf("option type \"%s\" not implemented", o.Type))
   170  		}
   171  	}
   172  
   173  	return flags
   174  }
   175  
   176  func optionsSetToEnvVars(c *cli.Context, set *cmd.OptionsSet, prefix string) []shell.EnvironmentVariable {
   177  	envVars := make([]shell.EnvironmentVariable, 0)
   178  	for _, o := range set.Sorted() {
   179  		o := o
   180  
   181  		envName := o.EnvName
   182  		if envName == "" {
   183  			envName = o.Name
   184  		}
   185  		envName = strings.Replace(strings.ToUpper(envName), ".", "_", -1)
   186  		envName = strings.Replace(strings.ToUpper(envName), "-", "_", -1)
   187  
   188  		if prefix != "" && o.Internal == false {
   189  			envName = prefix + envName
   190  		}
   191  
   192  		value := c.String(o.Name)
   193  
   194  		switch o.Type {
   195  		case cmd.StringOption:
   196  			envVars = append(envVars, shell.EnvironmentVariable{
   197  				Name:  envName,
   198  				Value: value,
   199  				Type:  shell.EnvironmentVariableTypeString,
   200  			})
   201  		case cmd.BoolOption:
   202  			envVars = append(envVars, shell.EnvironmentVariable{
   203  				Name:  envName,
   204  				Value: value,
   205  				Type:  shell.EnvironmentVariableTypeBool,
   206  			})
   207  		case cmd.IntegerOption:
   208  			envVars = append(envVars, shell.EnvironmentVariable{
   209  				Name:  envName,
   210  				Value: value,
   211  				Type:  shell.EnvironmentVariableTypeInteger,
   212  			})
   213  		case cmd.SelectOption:
   214  			if value == "true" {
   215  				envVars = append(envVars, shell.EnvironmentVariable{
   216  					Name:  envName,
   217  					Value: o.Name,
   218  					Type:  shell.EnvironmentVariableTypeString,
   219  				})
   220  			}
   221  		case cmd.SelectOptionV2:
   222  			value := ""
   223  			for _, v := range o.Values {
   224  				ov := c.String(v.Name)
   225  				if ov == "true" {
   226  					value = v.ResolveValue()
   227  					break
   228  				}
   229  			}
   230  
   231  			if value != "" {
   232  				envVars = append(envVars, shell.EnvironmentVariable{
   233  					Name:  envName,
   234  					Value: value,
   235  					Type:  shell.EnvironmentVariableTypeString,
   236  				})
   237  			}
   238  		default:
   239  			panic(fmt.Sprintf("option type \"%s\" not implemented", o.Type))
   240  		}
   241  	}
   242  
   243  	return shell.SortEnvironmentVariables(envVars)
   244  }
   245  
   246  func mapOptionValuesToCmdOptionValues(o config.Option) []cmd.OptionValue {
   247  	values := []cmd.OptionValue{}
   248  	for _, v := range o.Values {
   249  		values = append(values, cmd.OptionValue{
   250  			Name:  v.Name,
   251  			Short: v.Short,
   252  			Value: v.Value,
   253  		})
   254  	}
   255  	return values
   256  }
   257  
   258  func validateOptionsSet(c *cli.Context, set *cmd.OptionsSet, cmdName string, level string, log *logrus.Entry) error {
   259  	selectOptions := make(map[string][]string)
   260  	selectOptionRequired := make(map[string]bool)
   261  	selectOptionSelectedValues := make(map[string][]string)
   262  
   263  	for _, o := range set.Sorted() {
   264  		o := o
   265  
   266  		switch o.Type {
   267  		case cmd.SelectOption:
   268  			group := o.EnvName
   269  			selectOptions[group] = append(selectOptions[group], o.Name)
   270  			if o.Required {
   271  				selectOptionRequired[group] = true
   272  			}
   273  			v := c.String(o.Name)
   274  			log.Debugf("found select option %s (group=%s value=%v required=%v)\n", o.Name, group, v, o.Required)
   275  			if v == "true" {
   276  				selectOptionSelectedValues[group] = append(selectOptionSelectedValues[group], o.Name)
   277  			}
   278  		case cmd.SelectOptionV2:
   279  			group := o.Name
   280  			if o.Required {
   281  				selectOptionRequired[group] = true
   282  			}
   283  			for _, ov := range o.Values {
   284  				selectOptions[group] = append(selectOptions[group], ov.Name)
   285  				v := c.String(ov.Name)
   286  				log.Debugf("found select option %s (group=%s value=%v required=%v)\n", ov.Name, group, v, o.Required)
   287  				if v == "true" {
   288  					selectOptionSelectedValues[group] = append(selectOptionSelectedValues[group], ov.Name)
   289  				}
   290  			}
   291  		}
   292  	}
   293  
   294  	for group := range selectOptions {
   295  		if selectOptionRequired[group] {
   296  			optionValues, ok := selectOptionSelectedValues[group]
   297  			if ok && optionValues[0] != "" {
   298  				log.Debugf("select option group %s was set by option %s", group, optionValues[0])
   299  			} else {
   300  				cli.ShowCommandHelp(c, cmdName)
   301  				return fmt.Errorf("Required %s flag missing for select option group \"%s\" (one of \" %s \" must be provided)\n", level, group, strings.Join(selectOptions[group], " | "))
   302  			}
   303  		} else {
   304  			log.Debugf("select option group %s does not require a value", group)
   305  		}
   306  
   307  		if optionValues, ok := selectOptionSelectedValues[group]; ok && len(optionValues) > 1 {
   308  			return fmt.Errorf("%s flag specified multiple times for select option group \"%s\" (one of \" %s \" must be provided)\n", level, group, strings.Join(selectOptions[group], " | "))
   309  		}
   310  	}
   311  	return nil
   312  }