github.com/ssube/gitlab-ci-multi-runner@v1.2.1-0.20160607142738-b8d1285632e6/Godeps/_workspace/src/gitlab.com/ayufan/golang-cli-helpers/convert.go (about)

     1  package clihelpers
     2  // Copyright 2012 Jesse van den Kieboom. All rights reserved.
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  // The source is taken from: https://raw.githubusercontent.com/jessevdk/go-flags/master/convert.go
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"strconv"
    11  	"strings"
    12  	"time"
    13  )
    14  
    15  // Marshaler is the interface implemented by types that can marshal themselves
    16  // to a string representation of the flag.
    17  type Marshaler interface {
    18  	// MarshalFlag marshals a flag value to its string representation.
    19  	MarshalFlag() (string, error)
    20  }
    21  
    22  // Unmarshaler is the interface implemented by types that can unmarshal a flag
    23  // argument to themselves. The provided value is directly passed from the
    24  // command line.
    25  type Unmarshaler interface {
    26  	// UnmarshalFlag unmarshals a string value representation to the flag
    27  	// value (which therefore needs to be a pointer receiver).
    28  	UnmarshalFlag(value string) error
    29  }
    30  
    31  func getBase(options reflect.StructTag, base int) (int, error) {
    32  	sbase := options.Get("base")
    33  
    34  	var err error
    35  	var ivbase int64
    36  
    37  	if sbase != "" {
    38  		ivbase, err = strconv.ParseInt(sbase, 10, 32)
    39  		base = int(ivbase)
    40  	}
    41  
    42  	return base, err
    43  }
    44  
    45  func convertMarshal(val reflect.Value) (bool, string, error) {
    46  	// Check first for the Marshaler interface
    47  	if val.Type().NumMethod() > 0 && val.CanInterface() {
    48  		if marshaler, ok := val.Interface().(Marshaler); ok {
    49  			ret, err := marshaler.MarshalFlag()
    50  			return true, ret, err
    51  		}
    52  	}
    53  
    54  	return false, "", nil
    55  }
    56  
    57  func convertToString(val reflect.Value, options reflect.StructTag) (string, error) {
    58  	if ok, ret, err := convertMarshal(val); ok {
    59  		return ret, err
    60  	}
    61  
    62  	tp := val.Type()
    63  
    64  	// Support for time.Duration
    65  	if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
    66  		stringer := val.Interface().(fmt.Stringer)
    67  		return stringer.String(), nil
    68  	}
    69  
    70  	switch tp.Kind() {
    71  	case reflect.String:
    72  		return val.String(), nil
    73  	case reflect.Bool:
    74  		if val.Bool() {
    75  			return "true", nil
    76  		}
    77  
    78  		return "false", nil
    79  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    80  		base, err := getBase(options, 10)
    81  
    82  		if err != nil {
    83  			return "", err
    84  		}
    85  
    86  		return strconv.FormatInt(val.Int(), base), nil
    87  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    88  		base, err := getBase(options, 10)
    89  
    90  		if err != nil {
    91  			return "", err
    92  		}
    93  
    94  		return strconv.FormatUint(val.Uint(), base), nil
    95  	case reflect.Float32, reflect.Float64:
    96  		return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits()), nil
    97  	case reflect.Slice:
    98  		if val.Len() == 0 {
    99  			return "", nil
   100  		}
   101  
   102  		ret := "["
   103  
   104  		for i := 0; i < val.Len(); i++ {
   105  			if i != 0 {
   106  				ret += ", "
   107  			}
   108  
   109  			item, err := convertToString(val.Index(i), options)
   110  
   111  			if err != nil {
   112  				return "", err
   113  			}
   114  
   115  			ret += item
   116  		}
   117  
   118  		return ret + "]", nil
   119  	case reflect.Map:
   120  		ret := "{"
   121  
   122  		for i, key := range val.MapKeys() {
   123  			if i != 0 {
   124  				ret += ", "
   125  			}
   126  
   127  			keyitem, err := convertToString(key, options)
   128  
   129  			if err != nil {
   130  				return "", err
   131  			}
   132  
   133  			item, err := convertToString(val.MapIndex(key), options)
   134  
   135  			if err != nil {
   136  				return "", err
   137  			}
   138  
   139  			ret += keyitem + ":" + item
   140  		}
   141  
   142  		return ret + "}", nil
   143  	case reflect.Ptr:
   144  		return convertToString(reflect.Indirect(val), options)
   145  	case reflect.Interface:
   146  		if !val.IsNil() {
   147  			return convertToString(val.Elem(), options)
   148  		}
   149  	}
   150  
   151  	return "", nil
   152  }
   153  
   154  func convertUnmarshal(val string, retval reflect.Value) (bool, error) {
   155  	if retval.Type().NumMethod() > 0 && retval.CanInterface() {
   156  		if unmarshaler, ok := retval.Interface().(Unmarshaler); ok {
   157  			return true, unmarshaler.UnmarshalFlag(val)
   158  		}
   159  	}
   160  
   161  	if retval.Type().Kind() != reflect.Ptr && retval.CanAddr() {
   162  		return convertUnmarshal(val, retval.Addr())
   163  	}
   164  
   165  	if retval.Type().Kind() == reflect.Interface && !retval.IsNil() {
   166  		return convertUnmarshal(val, retval.Elem())
   167  	}
   168  
   169  	return false, nil
   170  }
   171  
   172  func convert(val string, retval reflect.Value, options reflect.StructTag) error {
   173  	if ok, err := convertUnmarshal(val, retval); ok {
   174  		return err
   175  	}
   176  
   177  	tp := retval.Type()
   178  
   179  	// Support for time.Duration
   180  	if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
   181  		parsed, err := time.ParseDuration(val)
   182  
   183  		if err != nil {
   184  			return err
   185  		}
   186  
   187  		retval.SetInt(int64(parsed))
   188  		return nil
   189  	}
   190  
   191  	switch tp.Kind() {
   192  	case reflect.String:
   193  		retval.SetString(val)
   194  	case reflect.Bool:
   195  		if val == "" {
   196  			retval.SetBool(true)
   197  		} else {
   198  			b, err := strconv.ParseBool(val)
   199  
   200  			if err != nil {
   201  				return err
   202  			}
   203  
   204  			retval.SetBool(b)
   205  		}
   206  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   207  		base, err := getBase(options, 10)
   208  
   209  		if err != nil {
   210  			return err
   211  		}
   212  
   213  		parsed, err := strconv.ParseInt(val, base, tp.Bits())
   214  
   215  		if err != nil {
   216  			return err
   217  		}
   218  
   219  		retval.SetInt(parsed)
   220  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   221  		base, err := getBase(options, 10)
   222  
   223  		if err != nil {
   224  			return err
   225  		}
   226  
   227  		parsed, err := strconv.ParseUint(val, base, tp.Bits())
   228  
   229  		if err != nil {
   230  			return err
   231  		}
   232  
   233  		retval.SetUint(parsed)
   234  	case reflect.Float32, reflect.Float64:
   235  		parsed, err := strconv.ParseFloat(val, tp.Bits())
   236  
   237  		if err != nil {
   238  			return err
   239  		}
   240  
   241  		retval.SetFloat(parsed)
   242  	case reflect.Slice:
   243  		elemtp := tp.Elem()
   244  
   245  		elemvalptr := reflect.New(elemtp)
   246  		elemval := reflect.Indirect(elemvalptr)
   247  
   248  		if err := convert(val, elemval, options); err != nil {
   249  			return err
   250  		}
   251  
   252  		retval.Set(reflect.Append(retval, elemval))
   253  	case reflect.Map:
   254  		parts := strings.SplitN(val, ":", 2)
   255  
   256  		key := parts[0]
   257  		var value string
   258  
   259  		if len(parts) == 2 {
   260  			value = parts[1]
   261  		}
   262  
   263  		keytp := tp.Key()
   264  		keyval := reflect.New(keytp)
   265  
   266  		if err := convert(key, keyval, options); err != nil {
   267  			return err
   268  		}
   269  
   270  		valuetp := tp.Elem()
   271  		valueval := reflect.New(valuetp)
   272  
   273  		if err := convert(value, valueval, options); err != nil {
   274  			return err
   275  		}
   276  
   277  		if retval.IsNil() {
   278  			retval.Set(reflect.MakeMap(tp))
   279  		}
   280  
   281  		retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval))
   282  	case reflect.Ptr:
   283  		if retval.IsNil() {
   284  			retval.Set(reflect.New(retval.Type().Elem()))
   285  		}
   286  
   287  		return convert(val, reflect.Indirect(retval), options)
   288  	case reflect.Interface:
   289  		if !retval.IsNil() {
   290  			return convert(val, retval.Elem(), options)
   291  		}
   292  	}
   293  
   294  	return nil
   295  }
   296  
   297  func isPrint(s string) bool {
   298  	for _, c := range s {
   299  		if !strconv.IsPrint(c) {
   300  			return false
   301  		}
   302  	}
   303  
   304  	return true
   305  }
   306  
   307  func quoteIfNeeded(s string) string {
   308  	if !isPrint(s) {
   309  		return strconv.Quote(s)
   310  	}
   311  
   312  	return s
   313  }
   314  
   315  func quoteIfNeededV(s []string) []string {
   316  	ret := make([]string, len(s))
   317  
   318  	for i, v := range s {
   319  		ret[i] = quoteIfNeeded(v)
   320  	}
   321  
   322  	return ret
   323  }
   324  
   325  func quoteV(s []string) []string {
   326  	ret := make([]string, len(s))
   327  
   328  	for i, v := range s {
   329  		ret[i] = strconv.Quote(v)
   330  	}
   331  
   332  	return ret
   333  }
   334  
   335  func unquoteIfPossible(s string) (string, error) {
   336  	if len(s) == 0 || s[0] != '"' {
   337  		return s, nil
   338  	}
   339  
   340  	return strconv.Unquote(s)
   341  }
   342  
   343  func wrapText(s string, l int, prefix string) string {
   344  	// Basic text wrapping of s at spaces to fit in l
   345  	var ret string
   346  
   347  	s = strings.TrimSpace(s)
   348  
   349  	for len(s) > l {
   350  		// Try to split on space
   351  		suffix := ""
   352  
   353  		pos := strings.LastIndex(s[:l], " ")
   354  
   355  		if pos < 0 {
   356  			pos = l - 1
   357  			suffix = "-\n"
   358  		}
   359  
   360  		if len(ret) != 0 {
   361  			ret += "\n" + prefix
   362  		}
   363  
   364  		ret += strings.TrimSpace(s[:pos]) + suffix
   365  		s = strings.TrimSpace(s[pos:])
   366  	}
   367  
   368  	if len(s) > 0 {
   369  		if len(ret) != 0 {
   370  			ret += "\n" + prefix
   371  		}
   372  
   373  		return ret + s
   374  	}
   375  
   376  	return ret
   377  }