...

Source file src/github.com/urfave/cli/v2/altsrc/json_source_context.go

Documentation: github.com/urfave/cli/v2/altsrc

     1  package altsrc
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/urfave/cli/v2"
    11  )
    12  
    13  // NewJSONSourceFromFlagFunc returns a func that takes a cli.Context
    14  // and returns an InputSourceContext suitable for retrieving config
    15  // variables from a file containing JSON data with the file name defined
    16  // by the given flag.
    17  func NewJSONSourceFromFlagFunc(flag string) func(c *cli.Context) (InputSourceContext, error) {
    18  	return func(cCtx *cli.Context) (InputSourceContext, error) {
    19  		if cCtx.IsSet(flag) {
    20  			return NewJSONSourceFromFile(cCtx.String(flag))
    21  		}
    22  
    23  		return defaultInputSource()
    24  	}
    25  }
    26  
    27  // NewJSONSourceFromFile returns an InputSourceContext suitable for
    28  // retrieving config variables from a file (or url) containing JSON
    29  // data.
    30  func NewJSONSourceFromFile(f string) (InputSourceContext, error) {
    31  	data, err := loadDataFrom(f)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	return NewJSONSource(data)
    37  }
    38  
    39  // NewJSONSourceFromReader returns an InputSourceContext suitable for
    40  // retrieving config variables from an io.Reader that returns JSON data.
    41  func NewJSONSourceFromReader(r io.Reader) (InputSourceContext, error) {
    42  	data, err := io.ReadAll(r)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return NewJSONSource(data)
    47  }
    48  
    49  // NewJSONSource returns an InputSourceContext suitable for retrieving
    50  // config variables from raw JSON data.
    51  func NewJSONSource(data []byte) (InputSourceContext, error) {
    52  	var deserialized map[string]interface{}
    53  	if err := json.Unmarshal(data, &deserialized); err != nil {
    54  		return nil, err
    55  	}
    56  	return &jsonSource{deserialized: deserialized}, nil
    57  }
    58  
    59  func (x *jsonSource) Source() string {
    60  	return x.file
    61  }
    62  
    63  func (x *jsonSource) Int(name string) (int, error) {
    64  	i, err := x.getValue(name)
    65  	if err != nil {
    66  		return 0, err
    67  	}
    68  	switch v := i.(type) {
    69  	default:
    70  		return 0, fmt.Errorf("unexpected type %T for %q", i, name)
    71  	case int:
    72  		return v, nil
    73  	case float32:
    74  		return int(v), nil
    75  	case float64:
    76  		return int(v), nil
    77  	}
    78  }
    79  
    80  func (x *jsonSource) Int64(name string) (int64, error) {
    81  	i, err := x.getValue(name)
    82  	if err != nil {
    83  		return 0, err
    84  	}
    85  	switch v := i.(type) {
    86  	default:
    87  		return 0, fmt.Errorf("unexpected type %T for %q", i, name)
    88  	case int64:
    89  		return v, nil
    90  	case int:
    91  		return int64(v), nil
    92  	case float32:
    93  		return int64(v), nil
    94  	case float64:
    95  		return int64(v), nil
    96  	}
    97  }
    98  
    99  func (x *jsonSource) Uint(name string) (uint, error) {
   100  	i, err := x.getValue(name)
   101  	if err != nil {
   102  		return 0, err
   103  	}
   104  	switch v := i.(type) {
   105  	default:
   106  		return 0, fmt.Errorf("unexpected type %T for %q", i, name)
   107  	case uint:
   108  		return v, nil
   109  	case uint64:
   110  		return uint(v), nil
   111  	case float32:
   112  		return uint(v), nil
   113  	case float64:
   114  		return uint(v), nil
   115  	}
   116  }
   117  
   118  func (x *jsonSource) Uint64(name string) (uint64, error) {
   119  	i, err := x.getValue(name)
   120  	if err != nil {
   121  		return 0, err
   122  	}
   123  	switch v := i.(type) {
   124  	default:
   125  		return 0, fmt.Errorf("unexpected type %T for %q", i, name)
   126  	case uint64:
   127  		return v, nil
   128  	case uint:
   129  		return uint64(v), nil
   130  	case float32:
   131  		return uint64(v), nil
   132  	case float64:
   133  		return uint64(v), nil
   134  	}
   135  }
   136  
   137  func (x *jsonSource) Duration(name string) (time.Duration, error) {
   138  	i, err := x.getValue(name)
   139  	if err != nil {
   140  		return 0, err
   141  	}
   142  	v, ok := i.(time.Duration)
   143  	if !ok {
   144  		return 0, fmt.Errorf("unexpected type %T for %q", i, name)
   145  	}
   146  	return v, nil
   147  }
   148  
   149  func (x *jsonSource) Float64(name string) (float64, error) {
   150  	i, err := x.getValue(name)
   151  	if err != nil {
   152  		return 0, err
   153  	}
   154  	v, ok := i.(float64)
   155  	if !ok {
   156  		return 0, fmt.Errorf("unexpected type %T for %q", i, name)
   157  	}
   158  	return v, nil
   159  }
   160  
   161  func (x *jsonSource) String(name string) (string, error) {
   162  	i, err := x.getValue(name)
   163  	if err != nil {
   164  		return "", err
   165  	}
   166  	v, ok := i.(string)
   167  	if !ok {
   168  		return "", fmt.Errorf("unexpected type %T for %q", i, name)
   169  	}
   170  	return v, nil
   171  }
   172  
   173  func (x *jsonSource) StringSlice(name string) ([]string, error) {
   174  	i, err := x.getValue(name)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	switch v := i.(type) {
   179  	default:
   180  		return nil, fmt.Errorf("unexpected type %T for %q", i, name)
   181  	case []string:
   182  		return v, nil
   183  	case []interface{}:
   184  		c := []string{}
   185  		for _, s := range v {
   186  			if str, ok := s.(string); ok {
   187  				c = append(c, str)
   188  			} else {
   189  				return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
   190  			}
   191  		}
   192  		return c, nil
   193  	}
   194  }
   195  
   196  func (x *jsonSource) IntSlice(name string) ([]int, error) {
   197  	i, err := x.getValue(name)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	switch v := i.(type) {
   202  	default:
   203  		return nil, fmt.Errorf("unexpected type %T for %q", i, name)
   204  	case []int:
   205  		return v, nil
   206  	case []interface{}:
   207  		c := []int{}
   208  		for _, s := range v {
   209  			if i2, ok := s.(int); ok {
   210  				c = append(c, i2)
   211  			} else {
   212  				return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
   213  			}
   214  		}
   215  		return c, nil
   216  	}
   217  }
   218  
   219  func (x *jsonSource) Int64Slice(name string) ([]int64, error) {
   220  	i, err := x.getValue(name)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  	switch v := i.(type) {
   225  	default:
   226  		return nil, fmt.Errorf("unexpected type %T for %q", i, name)
   227  	case []int64:
   228  		return v, nil
   229  	case []interface{}:
   230  		c := []int64{}
   231  		for _, s := range v {
   232  			if i2, ok := s.(int64); ok {
   233  				c = append(c, i2)
   234  			} else {
   235  				return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
   236  			}
   237  		}
   238  		return c, nil
   239  	}
   240  }
   241  
   242  func (x *jsonSource) Float64Slice(name string) ([]float64, error) {
   243  	i, err := x.getValue(name)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  	switch v := i.(type) {
   248  	default:
   249  		return nil, fmt.Errorf("unexpected type %T for %q", i, name)
   250  	case []float64:
   251  		return v, nil
   252  	case []interface{}:
   253  		c := []float64{}
   254  		for _, s := range v {
   255  			if i2, ok := s.(float64); ok {
   256  				c = append(c, i2)
   257  			} else {
   258  				return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
   259  			}
   260  		}
   261  		return c, nil
   262  	}
   263  }
   264  
   265  func (x *jsonSource) Generic(name string) (cli.Generic, error) {
   266  	i, err := x.getValue(name)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  	v, ok := i.(cli.Generic)
   271  	if !ok {
   272  		return nil, fmt.Errorf("unexpected type %T for %q", i, name)
   273  	}
   274  	return v, nil
   275  }
   276  
   277  func (x *jsonSource) Bool(name string) (bool, error) {
   278  	i, err := x.getValue(name)
   279  	if err != nil {
   280  		return false, err
   281  	}
   282  	v, ok := i.(bool)
   283  	if !ok {
   284  		return false, fmt.Errorf("unexpected type %T for %q", i, name)
   285  	}
   286  	return v, nil
   287  }
   288  
   289  func (x *jsonSource) isSet(name string) bool {
   290  	_, err := x.getValue(name)
   291  	return err == nil
   292  }
   293  
   294  func (x *jsonSource) getValue(key string) (interface{}, error) {
   295  	return jsonGetValue(key, x.deserialized)
   296  }
   297  
   298  func jsonGetValue(key string, m map[string]interface{}) (interface{}, error) {
   299  	var ret interface{}
   300  	var ok bool
   301  	working := m
   302  	keys := strings.Split(key, ".")
   303  	for ix, k := range keys {
   304  		if ret, ok = working[k]; !ok {
   305  			return ret, fmt.Errorf("missing key %q", key)
   306  		}
   307  		if working, ok = ret.(map[string]interface{}); !ok {
   308  			if ix < len(keys)-1 {
   309  				return ret, fmt.Errorf("unexpected intermediate value at %q segment of %q: %T", k, key, ret)
   310  			}
   311  		}
   312  	}
   313  	return ret, nil
   314  }
   315  
   316  type jsonSource struct {
   317  	file         string
   318  	deserialized map[string]interface{}
   319  }
   320  

View as plain text