// FilterArgs filters the given arguments and returns a filtered argument list. // It only contains the arguments which are declared in the given configuration // struct. func FilterArgs(conf interface{}, args []string) []string { configArgs := []string{} // need to be declared so we can call it recursively var addFields func(fields []*structs.Field) addFields = func(fields []*structs.Field) { for _, field := range fields { // don't forget nested structs if field.Kind() == reflect.Struct { addFields(field.Fields()) continue } fName := strings.ToLower(strings.Join(camelcase.Split(field.Name()), "-")) val, err := flags.Value(fName, args) if err != nil { continue } configArgs = append(configArgs, "--"+fName, val) } } addFields(structs.Fields(conf)) return configArgs }
func applyConfigFile(options *Options, filePath string) error { filePath = expandHomeDir(filePath) if _, err := os.Stat(filePath); os.IsNotExist(err) { return err } fileString := []byte{} log.Printf("Loading config file at: %s", filePath) fileString, err := ioutil.ReadFile(filePath) if err != nil { return err } config := make(map[string]interface{}) hcl.Decode(&config, string(fileString)) o := structs.New(options) for _, name := range o.Names() { configName := strings.ToLower(strings.Join(camelcase.Split(name), "_")) if val, ok := config[configName]; ok { field, ok := o.FieldOk(name) if !ok { return errors.New("No such field: " + name) } err := field.Set(val) if err != nil { return err } } } return nil }
// generateFieldName generates the fiels name combined with the prefix and the // struct's field name func (e *EnvironmentLoader) generateFieldName(prefix string, field *structs.Field) string { fieldName := strings.ToUpper(field.Name()) if e.CamelCase { fieldName = strings.ToUpper(strings.Join(camelcase.Split(field.Name()), "_")) } return strings.ToUpper(prefix) + "_" + fieldName }
// convert keys of a map to underscore func ConvertKeysToUnderscore(m map[string]interface{}) map[string]interface{} { newMap := make(map[string]interface{}) for k, v := range m { splitted := camelcase.Split(k) newMap[strings.ToLower(strings.Join(splitted, "_"))] = v } return newMap }
// generateFieldName generates the field name combined with the prefix and the // struct's field name func (e *EnvironmentLoader) generateFieldName(prefix string, name string) string { fieldName := strings.ToUpper(name) if e.CamelCase { fieldName = strings.ToUpper(strings.Join(camelcase.Split(name), "_")) } return strings.ToUpper(prefix) + "_" + fieldName }
// init initializes the selector code before the start of the animators. func init() { Init(web.Loop) // Register all our easing providers. for name, vals := range EasingValues { cased := strings.ToLower(strings.Join(camelcase.Split(name), "-")) RegisterEasing(cased, NewSpline(vals[0], vals[1], vals[2], vals[3])) } }
// getEnvName returns all upper case and underscore separated string, from field. // field is a camel case string. // // example // AppName will change to APP_NAME func getEnvName(field string) string { camSplit := camelcase.Split(field) var rst string for k, v := range camSplit { if k == 0 { rst = strings.ToUpper(v) continue } rst = rst + "_" + strings.ToUpper(v) } return rst }
// processField generates a flag based on the given field and fieldName. If a // nested struct is detected, a flag for each field of that nested struct is // generated too. func (f *FlagLoader) processField(fieldName string, field *structs.Field) error { if f.CamelCase { fieldName = strings.Join(camelcase.Split(fieldName), "-") } switch field.Kind() { case reflect.Struct: for _, ff := range field.Fields() { flagName := field.Name() + "-" + ff.Name() if f.Flatten { // first check if it's set or not, because if we have duplicate // we don't want to break the flag. Panic by giving a readable // output f.flagSet.VisitAll(func(fl *flag.Flag) { if strings.ToLower(ff.Name()) == fl.Name { // already defined panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name)) } }) flagName = ff.Name() } if err := f.processField(flagName, ff); err != nil { return err } } default: // Add custom prefix to the flag if it's set if f.Prefix != "" { fieldName = f.Prefix + "-" + fieldName } // we only can get the value from expored fields, unexported fields panics if field.IsExported() { // use built-in or custom flag usage message flagUsageFunc := flagUsageDefault if f.FlagUsageFunc != nil { flagUsageFunc = f.FlagUsageFunc } f.flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsageFunc(fieldName)) } } return nil }
// processField generates a flag based on the given field and fieldName. If a // nested struct is detected, a flag for each field of that nested struct is // generated too. func (f *FlagLoader) processField(flagSet *flag.FlagSet, fieldName string, field *structs.Field) error { if !field.IsExported() { return nil } if f.CamelCase { fieldName = strings.Join(camelcase.Split(fieldName), "-") } switch { case field.Kind() == reflect.Struct && !implementsTextUnmarshaler(field): for _, ff := range field.Fields() { flagName := fieldName + "-" + ff.Name() if f.Flatten { // first check if it's set or not, because if we have duplicate // we don't want to break the flag. Panic by giving a readable // output flagSet.VisitAll(func(fl *flag.Flag) { if strings.ToLower(ff.Name()) == fl.Name { // already defined panic(fmt.Sprintf("flag '%s' is already defined in outer struct", fl.Name)) } }) flagName = ff.Name() } if err := f.processField(flagSet, flagName, ff); err != nil { return err } } case field.Kind() == reflect.Ptr: field.InitElem() return f.processField(flagSet, fieldName, field) default: // Add custom prefix to the flag if it's set if f.Prefix != "" { fieldName = f.Prefix + "-" + fieldName } flagSet.Var(newFieldValue(field), flagName(fieldName), flagUsage(fieldName)) } return nil }
func applyConfigFile(options *Options, filePath string) error { filePath = ExpandHomeDir(filePath) if _, err := os.Stat(filePath); os.IsNotExist(err) { return err } fileString := []byte{} log.Printf("Loading config file at: %s", filePath) fileString, err := ioutil.ReadFile(filePath) if err != nil { return err } config := make(map[string]interface{}) hcl.Decode(&config, string(fileString)) o := structs.New(options) for _, name := range o.Names() { configName := strings.ToLower(strings.Join(camelcase.Split(name), "_")) if val, ok := config[configName]; ok { field, ok := o.FieldOk(name) if !ok { return errors.New("No such option: " + name) } var err error if name == "Preferences" { prefs := val.([]map[string]interface{})[0] htermPrefs := make(map[string]interface{}) for key, value := range prefs { htermPrefs[strings.Replace(key, "_", "-", -1)] = value } err = field.Set(htermPrefs) } else { err = field.Set(val) } if err != nil { return err } } } return nil }
// GoIdentifierFrom provides a mechanism to mutate an arbitrary descriptive // string (name) into a Go identifier (variable name, function name, etc) that // e.g. can be used in generated code, taking into account a blacklist of names // that should not be used, plus the blacklist of the go language reserved key // words (https://golang.org/ref/spec#Keywords), in order to guarantee that a // new name is created which will not conflict with an existing type. // // Identifier syntax: https://golang.org/ref/spec#Identifiers // // Strategy to convert arbitrary unicode string to a valid identifier: // // 1) Ensure name is valid UTF-8; if not, replace it with empty string // // 2) Split name into arrays of allowed runes (words), by considering a run of // disallowed unicode characters to act as a separator, where allowed runes // include unicode letters, unicode numbers, and '_' character (disallowed // runes are discarded) // // 3) Split words further into sub words, by decomposing camel case words as // per https://github.com/fatih/camelcase#usage-and-examples // // 4) Designate the case of all subwords of all words to be uppercase, with the // exception of the first subword of the first word, which should be lowercase // if exported is false, otherwise uppercase // // 5) For each subword of each word, adjust as follows: if designated as // lowercase, lowercase all characters of the subword; if designated as // uppercase, then if recognised as a common "initialism", then uppercase all // the characters of the subword, otherwise uppercase only the first character // of the subword. Common "Initialisms" are defined as per: // https://github.com/golang/lint/blob/32a87160691b3c96046c0c678fe57c5bef761456/lint.go#L702 // // 6) Rejoin subwords to form a single word // // 7) Rejoin words into a single string // // 8) If the string starts with a number, add a leading `_` // // 9) If the string is the empty string or "_", set as "Identifier" // // 10) If the resulting identifier is in the given blacklist, or the list of // reserved key words (https://golang.org/ref/spec#Keywords), append the lowest // integer possible, >= 1, that results in no blacklist conflict // // 11) Add the new name to the given blacklist // // Note, the `map[string]bool` construction is simply a mechanism to implement // set semantics; a value of `true` signifies inclusion in the set. // Non-existence is equivalent to existence with a value of `false`; therefore // it is recommended to only store `true` values. func GoIdentifierFrom(name string, exported bool, blacklist map[string]bool) (identifier string) { if !utf8.ValidString(name) { name = "" } for i, word := range strings.FieldsFunc( name, func(c rune) bool { return !unicode.IsLetter(c) && !unicode.IsNumber(c) && c != '_' }, ) { caseAdaptedWord := "" for j, subWord := range camelcase.Split(word) { caseAdaptedWord += fixCase(subWord, i == 0 && j == 0 && !exported) } identifier += caseAdaptedWord } if strings.IndexFunc( identifier, func(c rune) bool { return unicode.IsNumber(c) }, ) == 0 { identifier = "_" + identifier } if identifier == "" || identifier == "_" { identifier = "Identifier" } // If name already exists, add an integer suffix to name. Start with "1" and increment // by 1 until an unused name is found. Example: if name FooBar was generated four times // , the first instance would be called FooBar, then the next would be FooBar1, the next // FooBar2 and the last would be assigned a name of FooBar3. We do this to guarantee we // don't use duplicate names for different logical entities. for k, baseName := 1, identifier; blacklist[identifier] || reservedKeyWords[identifier]; { identifier = fmt.Sprintf("%v%v", baseName, k) k++ } blacklist[identifier] = true return }
func makeTagName(s string) string { a := []rune(s) if len(a) <= 3 { return strings.ToLower(string(a)) } spl := camelcase.Split(string(a)) if len(spl) > 1 { fixed := []string{} for _, v := range spl { fixed = append(fixed, makeFirstUpperCase(strings.ToLower(v))) } x := makeFirstLowerCase(strings.Join(fixed, "")) return x } return makeFirstLowerCase(strings.Title(string(a))) }
// ExcludeArgs exludes the given arguments declared in the configuration and // returns the remaining arguments. It's the opposite of FilterArgs func ExcludeArgs(conf interface{}, args []string) []string { // need to be declared so we can call it recursively var addFields func(fields []*structs.Field) addFields = func(fields []*structs.Field) { for _, field := range fields { // don't forget nested structs if field.Kind() == reflect.Struct { addFields(field.Fields()) continue } fName := strings.ToLower(strings.Join(camelcase.Split(field.Name()), "-")) args = flags.Exclude(fName, args) } } addFields(structs.Fields(conf)) return args }
func convertInterfaceMap(p interface{}, except []string) map[string]string { nint := map[string]string{} var structItems map[string]interface{} structItems, _ = reflections.Items(p) for v, v2 := range structItems { if isZeroOfUnderlyingType(v2) || isInList(v, except) { continue } v = strings.ToLower(strings.Join(camelcase.Split(v), "_")) switch val := v2.(type) { case interface{}: sv, _ := json.Marshal(val) nint[v] = string(sv) default: nint[v] = fmt.Sprintf("%+v", v2) } } return nint }
func populateEnv(iface Interface) { options := reflect.ValueOf(iface.GetOptions()) if options.Kind() == reflect.Ptr { options = reflect.ValueOf(options.Elem().Interface()) } if options.Kind() == reflect.Struct { for i := 0; i < options.NumField(); i++ { name := strings.Join(camelcase.Split(options.Type().Field(i).Name), "_") envName := fmt.Sprintf("%s_%s", strings.ToUpper(iface.Name()), strings.ToUpper(name)) envName = strings.Map(func(r rune) rune { if unicode.IsDigit(r) || unicode.IsLetter(r) { return r } return '_' }, envName) var val string switch t := options.Field(i).Interface().(type) { case string: val = t case int, int8, int16, int32, int64: val = fmt.Sprintf("%d", t) case float32, float64: val = fmt.Sprintf("%f", t) case bool: val = fmt.Sprintf("%t", t) default: val, _ = util.JsonEncode(t) val = strings.TrimSpace(val) if val == "null" { val = "" } } os.Setenv(envName, val) } } }
func makeDashedFromCamelCase(in string) string { splitted := camelcase.Split(in) return strings.ToLower(strings.Join(splitted, "-")) }