code.cestus.io/tools/fabricator@v0.4.3/pkg/ff/ffyaml/ffyaml.go (about) 1 // Package ffyaml provides a YAML config file paser. 2 package ffyaml 3 4 import ( 5 "fmt" 6 "io" 7 "strconv" 8 9 "code.cestus.io/tools/fabricator/pkg/ff" 10 "gopkg.in/yaml.v3" 11 ) 12 13 // Parser is a parser for YAML file format. Flags and their values are read 14 // from the key/value pairs defined in the config file. 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 default: 72 return "", ff.StringConversionError{Value: val} 73 } 74 } 75 76 // ParseError wraps all errors originating from the YAML parser. 77 type ParseError struct { 78 Inner error 79 } 80 81 // Error implenents the error interface. 82 func (e ParseError) Error() string { 83 return fmt.Sprintf("error parsing YAML config: %v", e.Inner) 84 } 85 86 // Unwrap implements the errors.Wrapper interface, allowing errors.Is and 87 // errors.As to work with ParseErrors. 88 func (e ParseError) Unwrap() error { 89 return e.Inner 90 }