func execTags(in interface{}, fs *pflag.FlagSet) error { if reflect.TypeOf(in).Kind() != reflect.Ptr { return errors.New("Calling parser with non-pointer") } if reflect.ValueOf(in).Elem().Kind() != reflect.Struct { return errors.New("Calling parser with pointer to non-struct") } st := reflect.ValueOf(in).Elem() for i := 0; i < st.NumField(); i++ { valField := st.Field(i) typeField := st.Type().Field(i) if typeField.Tag.Get("default") == "" && typeField.Tag.Get("env") == "" && typeField.Tag.Get("flag") == "" && typeField.Type.Kind() != reflect.Struct { // None of our supported tags is present and it's not a sub-struct continue } value := varDefault(typeField.Tag.Get("vardefault"), typeField.Tag.Get("default")) value = envDefault(typeField.Tag.Get("env"), value) parts := strings.Split(typeField.Tag.Get("flag"), ",") switch typeField.Type.Kind() { case reflect.String: if typeField.Tag.Get("flag") != "" { if len(parts) == 1 { fs.StringVar(valField.Addr().Interface().(*string), parts[0], value, typeField.Tag.Get("description")) } else { fs.StringVarP(valField.Addr().Interface().(*string), parts[0], parts[1], value, typeField.Tag.Get("description")) } } else { valField.SetString(value) } case reflect.Bool: v := value == "true" if typeField.Tag.Get("flag") != "" { if len(parts) == 1 { fs.BoolVar(valField.Addr().Interface().(*bool), parts[0], v, typeField.Tag.Get("description")) } else { fs.BoolVarP(valField.Addr().Interface().(*bool), parts[0], parts[1], v, typeField.Tag.Get("description")) } } else { valField.SetBool(v) } case reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64: vt, err := strconv.ParseInt(value, 10, 64) if err != nil { if value == "" { vt = 0 } else { return err } } if typeField.Tag.Get("flag") != "" { registerFlagInt(typeField.Type.Kind(), fs, valField.Addr().Interface(), parts, vt, typeField.Tag.Get("description")) } else { valField.SetInt(vt) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: vt, err := strconv.ParseUint(value, 10, 64) if err != nil { if value == "" { vt = 0 } else { return err } } if typeField.Tag.Get("flag") != "" { registerFlagUint(typeField.Type.Kind(), fs, valField.Addr().Interface(), parts, vt, typeField.Tag.Get("description")) } else { valField.SetUint(vt) } case reflect.Float32, reflect.Float64: vt, err := strconv.ParseFloat(value, 64) if err != nil { if value == "" { vt = 0.0 } else { return err } } if typeField.Tag.Get("flag") != "" { registerFlagFloat(typeField.Type.Kind(), fs, valField.Addr().Interface(), parts, vt, typeField.Tag.Get("description")) } else { valField.SetFloat(vt) } case reflect.Struct: if err := execTags(valField.Addr().Interface(), fs); err != nil { return err } case reflect.Slice: switch typeField.Type.Elem().Kind() { case reflect.Int: def := []int{} for _, v := range strings.Split(value, ",") { it, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64) if err != nil { return err } def = append(def, int(it)) } if len(parts) == 1 { fs.IntSliceVar(valField.Addr().Interface().(*[]int), parts[0], def, typeField.Tag.Get("description")) } else { fs.IntSliceVarP(valField.Addr().Interface().(*[]int), parts[0], parts[1], def, typeField.Tag.Get("description")) } case reflect.String: del := typeField.Tag.Get("delimiter") if len(del) == 0 { del = "," } def := strings.Split(value, del) if len(parts) == 1 { fs.StringSliceVar(valField.Addr().Interface().(*[]string), parts[0], def, typeField.Tag.Get("description")) } else { fs.StringSliceVarP(valField.Addr().Interface().(*[]string), parts[0], parts[1], def, typeField.Tag.Get("description")) } } } } return nil }