...
1
2 package ffyaml
3
4 import (
5 "fmt"
6 "io"
7 "strconv"
8
9 "github.com/peterbourgon/ff/v3"
10 "gopkg.in/yaml.v2"
11 )
12
13
14
15 func Parser(r io.Reader, set func(name, value string) error) error {
16 var m map[string]interface{}
17 d := yaml.NewDecoder(r)
18 if err := d.Decode(&m); err != nil && err != io.EOF {
19 return ParseError{err}
20 }
21 for key, val := range m {
22 values, err := valsToStrs(val)
23 if err != nil {
24 return ParseError{err}
25 }
26 for _, value := range values {
27 if err := set(key, value); err != nil {
28 return err
29 }
30 }
31 }
32 return nil
33 }
34
35 func valsToStrs(val interface{}) ([]string, error) {
36 if vals, ok := val.([]interface{}); ok {
37 ss := make([]string, len(vals))
38 for i := range vals {
39 s, err := valToStr(vals[i])
40 if err != nil {
41 return nil, err
42 }
43 ss[i] = s
44 }
45 return ss, nil
46 }
47 s, err := valToStr(val)
48 if err != nil {
49 return nil, err
50 }
51 return []string{s}, nil
52
53 }
54
55 func valToStr(val interface{}) (string, error) {
56 switch v := val.(type) {
57 case byte:
58 return string([]byte{v}), nil
59 case string:
60 return v, nil
61 case bool:
62 return strconv.FormatBool(v), nil
63 case uint64:
64 return strconv.FormatUint(v, 10), nil
65 case int:
66 return strconv.Itoa(v), nil
67 case int64:
68 return strconv.FormatInt(v, 10), nil
69 case float64:
70 return strconv.FormatFloat(v, 'g', -1, 64), nil
71 case nil:
72 return "", nil
73 default:
74 return "", ff.StringConversionError{Value: val}
75 }
76 }
77
78
79 type ParseError struct {
80 Inner error
81 }
82
83
84 func (e ParseError) Error() string {
85 return fmt.Sprintf("error parsing YAML config: %v", e.Inner)
86 }
87
88
89
90 func (e ParseError) Unwrap() error {
91 return e.Inner
92 }
93
View as plain text