github.com/ssube/gitlab-ci-multi-runner@v1.2.1-0.20160607142738-b8d1285632e6/Godeps/_workspace/src/gitlab.com/ayufan/golang-cli-helpers/struct_field.go (about) 1 package clihelpers 2 3 import ( 4 "strings" 5 "reflect" 6 "github.com/codegangsta/cli" 7 ) 8 9 type StructFieldValue struct { 10 field reflect.StructField 11 value reflect.Value 12 } 13 14 func (f StructFieldValue) IsBoolFlag() bool { 15 if f.value.Kind() == reflect.Bool { 16 return true 17 } else if f.value.Kind() == reflect.Ptr && f.value.Elem().Kind() == reflect.Bool { 18 return true 19 } else { 20 return false 21 } 22 } 23 24 func (s StructFieldValue) Set(val string) error { 25 return convert(val, s.value, s.field.Tag) 26 } 27 28 func (s StructFieldValue) String() string { 29 if s.value.Kind() == reflect.Ptr && s.value.IsNil() { 30 return "" 31 } 32 retval, _ := convertToString(s.value, s.field.Tag) 33 return retval 34 } 35 36 type StructFieldFlag struct { 37 cli.GenericFlag 38 } 39 40 func (f StructFieldFlag) String() string { 41 if sf, ok := f.Value.(StructFieldValue); ok { 42 if sf.IsBoolFlag() { 43 flag := &cli.BoolFlag{ 44 Name: f.Name, 45 Usage: f.Usage, 46 EnvVar: f.EnvVar, 47 } 48 return flag.String() 49 } else { 50 flag := &cli.StringFlag{ 51 Name: f.Name, 52 Value: sf.String(), 53 Usage: f.Usage, 54 EnvVar: f.EnvVar, 55 } 56 return flag.String() 57 } 58 } else { 59 return f.GenericFlag.String() 60 } 61 } 62 63 func getStructFieldFlag(field reflect.StructField, fieldValue reflect.Value, ns []string) []cli.Flag { 64 var names []string 65 66 if name := field.Tag.Get("short"); name != "" { 67 names = append(names, strings.Join(append(ns, name), "-")) 68 } 69 if name := field.Tag.Get("long"); name != "" { 70 names = append(names, strings.Join(append(ns, name), "-")) 71 } 72 73 if len(names) == 0 { 74 return []cli.Flag{} 75 } 76 77 flag := cli.GenericFlag{ 78 Name: strings.Join(names, ", "), 79 Value: StructFieldValue{ 80 field: field, 81 value: fieldValue, 82 }, 83 Usage: field.Tag.Get("description"), 84 EnvVar: field.Tag.Get("env"), 85 } 86 return []cli.Flag{StructFieldFlag{GenericFlag: flag}} 87 } 88 89 func getFlagsForStructField(field reflect.StructField, fieldValue reflect.Value, ns []string) []cli.Flag { 90 if !fieldValue.IsValid() { 91 return []cli.Flag{} 92 } 93 94 switch field.Type.Kind() { 95 case reflect.Struct: 96 if newNs := field.Tag.Get("namespace"); newNs != "" { 97 return getFlagsForValue(fieldValue, append(ns, newNs)) 98 } else if field.Anonymous { 99 return getFlagsForValue(fieldValue, ns) 100 } 101 break 102 case reflect.Ptr: 103 if field.Type.Elem().Kind() == reflect.Struct { 104 if newNs := field.Tag.Get("namespace"); newNs != "" { 105 return getFlagsForValue(fieldValue, append(ns, newNs)) 106 } 107 } else { 108 return getStructFieldFlag(field, fieldValue, ns) 109 } 110 break 111 case reflect.Chan: 112 case reflect.Func: 113 case reflect.Interface: 114 case reflect.UnsafePointer: 115 break 116 default: 117 return getStructFieldFlag(field, fieldValue, ns) 118 } 119 120 return []cli.Flag{} 121 } 122 123 func getFlagsForValue(value reflect.Value, ns []string) []cli.Flag { 124 var flags []cli.Flag 125 126 if value.Type().Kind() == reflect.Ptr && value.Type().Elem().Kind() == reflect.Struct { 127 if value.IsNil() { 128 value.Set(reflect.New(value.Type().Elem())) 129 } 130 131 value = reflect.Indirect(value) 132 } else if value.Type().Kind() != reflect.Struct { 133 return []cli.Flag{} 134 } 135 136 valueType := value.Type() 137 for i := 0; i < valueType.NumField(); i++ { 138 newFlags := getFlagsForStructField(valueType.Field(i), value.Field(i), ns) 139 flags = append(flags, newFlags...) 140 } 141 142 return flags 143 } 144 145 func GetFlagsFromStruct(data interface{}, ns... string) []cli.Flag { 146 return getFlagsForValue(reflect.ValueOf(data), ns) 147 }