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  }