// findConfigurationConflicts iterates over the provided flags searching for // duplicated configurations. It returns an error with all the conflicts if // it finds any. func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagSet) error { var conflicts []string printConflict := func(name string, flagValue, fileValue interface{}) string { return fmt.Sprintf("%s: (from flag: %v, from file: %v)", name, flagValue, fileValue) } collectConflicts := func(f *flag.Flag) { // search option name in the json configuration payload if the value is a named option if namedOption, ok := f.Value.(opts.NamedOption); ok { if optsValue, ok := config[namedOption.Name()]; ok { conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue)) } } else { // search flag name in the json configuration payload without trailing dashes for _, name := range f.Names { name = strings.TrimLeft(name, "-") if value, ok := config[name]; ok { conflicts = append(conflicts, printConflict(name, f.Value.String(), value)) break } } } } flags.Visit(collectConflicts) if len(conflicts) > 0 { return fmt.Errorf("the following directives are specified both as a flag and in the configuration file: %s", strings.Join(conflicts, ", ")) } return nil }
// findConfigurationConflicts iterates over the provided flags searching for // duplicated configurations and unknown keys. It returns an error with all the conflicts if // it finds any. func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagSet) error { // 1. Search keys from the file that we don't recognize as flags. unknownKeys := make(map[string]interface{}) for key, value := range config { flagName := "-" + key if flag := flags.Lookup(flagName); flag == nil { unknownKeys[key] = value } } // 2. Discard values that implement NamedOption. // Their configuration name differs from their flag name, like `labels` and `label`. if len(unknownKeys) > 0 { unknownNamedConflicts := func(f *flag.Flag) { if namedOption, ok := f.Value.(opts.NamedOption); ok { if _, valid := unknownKeys[namedOption.Name()]; valid { delete(unknownKeys, namedOption.Name()) } } } flags.VisitAll(unknownNamedConflicts) } if len(unknownKeys) > 0 { var unknown []string for key := range unknownKeys { unknown = append(unknown, key) } return fmt.Errorf("the following directives don't match any configuration option: %s", strings.Join(unknown, ", ")) } var conflicts []string printConflict := func(name string, flagValue, fileValue interface{}) string { return fmt.Sprintf("%s: (from flag: %v, from file: %v)", name, flagValue, fileValue) } // 3. Search keys that are present as a flag and as a file option. duplicatedConflicts := func(f *flag.Flag) { // search option name in the json configuration payload if the value is a named option if namedOption, ok := f.Value.(opts.NamedOption); ok { if optsValue, ok := config[namedOption.Name()]; ok { conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue)) } } else { // search flag name in the json configuration payload without trailing dashes for _, name := range f.Names { name = strings.TrimLeft(name, "-") if value, ok := config[name]; ok { conflicts = append(conflicts, printConflict(name, f.Value.String(), value)) break } } } } flags.Visit(duplicatedConflicts) if len(conflicts) > 0 { return fmt.Errorf("the following directives are specified both as a flag and in the configuration file: %s", strings.Join(conflicts, ", ")) } return nil }