From 075642f105aa13e7baded79d25e4fd766880cbcd Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 11 Apr 2017 00:56:56 +0200 Subject: [PATCH] cmd/geth: make TOML keys look exactly like Go struct fields --- cmd/geth/config.go | 25 ++++++- eth/config.go | 2 +- eth/gen_config.go | 4 +- node/config.go | 22 +++---- vendor/github.com/naoina/toml/config.go | 86 +++++++++++++++++++++++++ vendor/github.com/naoina/toml/decode.go | 65 ++++++++++--------- vendor/github.com/naoina/toml/encode.go | 47 +++++++------- vendor/github.com/naoina/toml/util.go | 18 +++--- vendor/vendor.json | 12 +--- 9 files changed, 192 insertions(+), 89 deletions(-) create mode 100644 vendor/github.com/naoina/toml/config.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index d0446b1ad7..b57f61edce 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -20,8 +20,11 @@ import ( "bufio" "encoding/hex" "errors" + "fmt" "io" "os" + "reflect" + "unicode" cli "gopkg.in/urfave/cli.v1" @@ -62,6 +65,23 @@ var defaultNodeConfig = node.Config{ WSModules: []string{"eth", "net", "web3"}, } +// These settings ensure that TOML keys use the same names as Go struct fields. +var tomlSettings = toml.Config{ + NormFieldName: func(rt reflect.Type, key string) string { + return key + }, + FieldToKey: func(rt reflect.Type, field string) string { + return field + }, + MissingField: func(rt reflect.Type, field string) error { + link := "" + if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { + link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name()) + } + return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) + }, +} + type gethConfig struct { Eth eth.Config Node node.Config @@ -73,7 +93,8 @@ func loadConfig(file string, cfg *gethConfig) error { return err } defer f.Close() - err = toml.NewDecoder(bufio.NewReader(f)).Decode(cfg) + + err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg) // Add file name to errors that have a line number. if _, ok := err.(*toml.LineError); ok { err = errors.New(file + ", " + err.Error()) @@ -145,7 +166,7 @@ func dumpConfig(ctx *cli.Context) error { comment += "# Note: this config doesn't contain the genesis block.\n\n" } - out, err := toml.Marshal(&cfg) + out, err := tomlSettings.Marshal(&cfg) if err != nil { return err } diff --git a/eth/config.go b/eth/config.go index d2a0ad0c0a..de43df3183 100644 --- a/eth/config.go +++ b/eth/config.go @@ -97,7 +97,7 @@ type Config struct { EthashDatasetsOnDisk int // Gas Price Oracle options - GPO gasprice.Config `toml:"gpo"` + GPO gasprice.Config // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool diff --git a/eth/gen_config.go b/eth/gen_config.go index e9f1b06611..fc5391f1e0 100644 --- a/eth/gen_config.go +++ b/eth/gen_config.go @@ -33,7 +33,7 @@ func (c Config) MarshalTOML() (interface{}, error) { EthashDatasetDir string EthashDatasetsInMem int EthashDatasetsOnDisk int - GPO gasprice.Config `toml:"gpo"` + GPO gasprice.Config EnablePreimageRecording bool SolcPath string DocRoot string `toml:"-"` @@ -94,7 +94,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { EthashDatasetDir *string EthashDatasetsInMem *int EthashDatasetsOnDisk *int - GPO *gasprice.Config `toml:"gpo"` + GPO *gasprice.Config EnablePreimageRecording *bool SolcPath *string DocRoot *string `toml:"-"` diff --git a/node/config.go b/node/config.go index 903889cb09..7c17e707dd 100644 --- a/node/config.go +++ b/node/config.go @@ -67,7 +67,7 @@ type Config struct { DataDir string // Configuration of peer-to-peer networking. - P2P p2p.Config `toml:"p2p"` + P2P p2p.Config // KeyStoreDir is the file system folder that contains private keys. The directory can // be specified as a relative path, in which case it is resolved relative to the @@ -80,51 +80,51 @@ type Config struct { // UseLightweightKDF lowers the memory and CPU requirements of the key store // scrypt KDF at the expense of security. - UseLightweightKDF bool `toml:"use_lightweight_kdf,omitempty"` + UseLightweightKDF bool `toml:",omitempty"` // IPCPath is the requested location to place the IPC endpoint. If the path is // a simple file name, it is placed inside the data directory (or on the root // pipe path on Windows), whereas if it's a resolvable path name (absolute or // relative), then that specific path is enforced. An empty path disables IPC. - IPCPath string `toml:"ipc_path,omitempty"` + IPCPath string `toml:",omitempty"` // HTTPHost is the host interface on which to start the HTTP RPC server. If this // field is empty, no HTTP API endpoint will be started. - HTTPHost string `toml:"http_host,omitempty"` + HTTPHost string `toml:",omitempty"` // HTTPPort is the TCP port number on which to start the HTTP RPC server. The // default zero value is/ valid and will pick a port number randomly (useful // for ephemeral nodes). - HTTPPort int `toml:"http_port,omitempty"` + HTTPPort int `toml:",omitempty"` // HTTPCors is the Cross-Origin Resource Sharing header to send to requesting // clients. Please be aware that CORS is a browser enforced security, it's fully // useless for custom HTTP clients. - HTTPCors string `toml:"http_cors,omitempty"` + HTTPCors string `toml:",omitempty"` // HTTPModules is a list of API modules to expose via the HTTP RPC interface. // If the module list is empty, all RPC API endpoints designated public will be // exposed. - HTTPModules []string `toml:"http_modules,omitempty"` + HTTPModules []string `toml:",omitempty"` // WSHost is the host interface on which to start the websocket RPC server. If // this field is empty, no websocket API endpoint will be started. - WSHost string `toml:"ws_host,omitempty"` + WSHost string `toml:",omitempty"` // WSPort is the TCP port number on which to start the websocket RPC server. The // default zero value is/ valid and will pick a port number randomly (useful for // ephemeral nodes). - WSPort int `toml:"ws_port,omitempty"` + WSPort int `toml:",omitempty"` // WSOrigins is the list of domain to accept websocket requests from. Please be // aware that the server can only act upon the HTTP request the client sends and // cannot verify the validity of the request header. - WSOrigins string `toml:"ws_origins,omitempty"` + WSOrigins string `toml:",omitempty"` // WSModules is a list of API modules to expose via the websocket RPC interface. // If the module list is empty, all RPC API endpoints designated public will be // exposed. - WSModules []string `toml:"ws_modules,omitempty"` + WSModules []string `toml:",omitempty"` } // IPCEndpoint resolves an IPC endpoint based on a configured value, taking into diff --git a/vendor/github.com/naoina/toml/config.go b/vendor/github.com/naoina/toml/config.go new file mode 100644 index 0000000000..06bb9493b8 --- /dev/null +++ b/vendor/github.com/naoina/toml/config.go @@ -0,0 +1,86 @@ +package toml + +import ( + "fmt" + "io" + "reflect" + "strings" + + stringutil "github.com/naoina/go-stringutil" + "github.com/naoina/toml/ast" +) + +// Config contains options for encoding and decoding. +type Config struct { + // NormFieldName is used to match TOML keys to struct fields. The function runs for + // both input keys and struct field names and should return a string that makes the + // two match. You must set this field to use the decoder. + // + // Example: The function in the default config removes _ and lowercases all keys. This + // allows a key called 'api_key' to match the struct field 'APIKey' because both are + // normalized to 'apikey'. + // + // Note that NormFieldName is not used for fields which define a TOML + // key through the struct tag. + NormFieldName func(typ reflect.Type, keyOrField string) string + + // FieldToKey determines the TOML key of a struct field when encoding. + // You must set this field to use the encoder. + // + // Note that FieldToKey is not used for fields which define a TOML + // key through the struct tag. + FieldToKey func(typ reflect.Type, field string) string + + // MissingField, if non-nil, is called when the decoder encounters a key for which no + // matching struct field exists. The default behavior is to return an error. + MissingField func(typ reflect.Type, key string) error +} + +// DefaultConfig contains the default options for encoding and decoding. +// Snake case (i.e. 'foo_bar') is used for key names. +var DefaultConfig = Config{ + NormFieldName: defaultNormFieldName, + FieldToKey: snakeCase, +} + +func defaultNormFieldName(typ reflect.Type, s string) string { + return strings.Replace(strings.ToLower(s), "_", "", -1) +} + +func snakeCase(typ reflect.Type, s string) string { + return stringutil.ToSnakeCase(s) +} + +func defaultMissingField(typ reflect.Type, key string) error { + return fmt.Errorf("field corresponding to `%s' is not defined in %v", key, typ) +} + +// NewEncoder returns a new Encoder that writes to w. +// It is shorthand for DefaultConfig.NewEncoder(w). +func NewEncoder(w io.Writer) *Encoder { + return DefaultConfig.NewEncoder(w) +} + +// Marshal returns the TOML encoding of v. +// It is shorthand for DefaultConfig.Marshal(v). +func Marshal(v interface{}) ([]byte, error) { + return DefaultConfig.Marshal(v) +} + +// Unmarshal parses the TOML data and stores the result in the value pointed to by v. +// It is shorthand for DefaultConfig.Unmarshal(data, v). +func Unmarshal(data []byte, v interface{}) error { + return DefaultConfig.Unmarshal(data, v) +} + +// UnmarshalTable applies the contents of an ast.Table to the value pointed at by v. +// It is shorthand for DefaultConfig.UnmarshalTable(t, v). +func UnmarshalTable(t *ast.Table, v interface{}) error { + return DefaultConfig.UnmarshalTable(t, v) +} + +// NewDecoder returns a new Decoder that reads from r. +// It is shorthand for DefaultConfig.NewDecoder(r). +func NewDecoder(r io.Reader) *Decoder { + return DefaultConfig.NewDecoder(r) +} diff --git a/vendor/github.com/naoina/toml/decode.go b/vendor/github.com/naoina/toml/decode.go index c34bed1bc2..b3c169eb1c 100644 --- a/vendor/github.com/naoina/toml/decode.go +++ b/vendor/github.com/naoina/toml/decode.go @@ -47,12 +47,12 @@ var timeType = reflect.TypeOf(time.Time{}) // TOML arrays to any type of slice // TOML tables to struct or map // TOML array tables to slice of struct or map -func Unmarshal(data []byte, v interface{}) error { +func (cfg *Config) Unmarshal(data []byte, v interface{}) error { table, err := Parse(data) if err != nil { return err } - if err := UnmarshalTable(table, v); err != nil { + if err := cfg.UnmarshalTable(table, v); err != nil { return err } return nil @@ -60,15 +60,14 @@ func Unmarshal(data []byte, v interface{}) error { // A Decoder reads and decodes TOML from an input stream. type Decoder struct { - r io.Reader + r io.Reader + cfg *Config } // NewDecoder returns a new Decoder that reads from r. // Note that it reads all from r before parsing it. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{ - r: r, - } +func (cfg *Config) NewDecoder(r io.Reader) *Decoder { + return &Decoder{r, cfg} } // Decode parses the TOML data from its input and stores it in the value pointed to by v. @@ -78,7 +77,7 @@ func (d *Decoder) Decode(v interface{}) error { if err != nil { return err } - return Unmarshal(b, v) + return d.cfg.Unmarshal(b, v) } // UnmarshalerRec may be implemented by types to customize their behavior when being @@ -113,17 +112,17 @@ type Unmarshaler interface { // TOML arrays to any type of slice // TOML tables to struct or map // TOML array tables to slice of struct or map -func UnmarshalTable(t *ast.Table, v interface{}) error { +func (cfg *Config) UnmarshalTable(t *ast.Table, v interface{}) error { rv := reflect.ValueOf(v) toplevelMap := rv.Kind() == reflect.Map if (!toplevelMap && rv.Kind() != reflect.Ptr) || rv.IsNil() { return &invalidUnmarshalError{reflect.TypeOf(v)} } - return unmarshalTable(rv, t, toplevelMap) + return unmarshalTable(cfg, rv, t, toplevelMap) } // used for UnmarshalerRec. -func unmarshalTableOrValue(rv reflect.Value, av interface{}) error { +func unmarshalTableOrValue(cfg *Config, rv reflect.Value, av interface{}) error { if (rv.Kind() != reflect.Ptr && rv.Kind() != reflect.Map) || rv.IsNil() { return &invalidUnmarshalError{rv.Type()} } @@ -131,12 +130,12 @@ func unmarshalTableOrValue(rv reflect.Value, av interface{}) error { switch av.(type) { case *ast.KeyValue, *ast.Table, []*ast.Table: - if err := unmarshalField(rv, av); err != nil { + if err := unmarshalField(cfg, rv, av); err != nil { return lineError(fieldLineNumber(av), err) } return nil case ast.Value: - return setValue(rv, av.(ast.Value)) + return setValue(cfg, rv, av.(ast.Value)) default: panic(fmt.Sprintf("BUG: unhandled AST node type %T", av)) } @@ -146,21 +145,23 @@ func unmarshalTableOrValue(rv reflect.Value, av interface{}) error { // // toplevelMap is true when rv is an (unadressable) map given to UnmarshalTable. In this // (special) case, the map is used as-is instead of creating a new map. -func unmarshalTable(rv reflect.Value, t *ast.Table, toplevelMap bool) error { +func unmarshalTable(cfg *Config, rv reflect.Value, t *ast.Table, toplevelMap bool) error { rv = indirect(rv) - if err, ok := setUnmarshaler(rv, t); ok { + if err, ok := setUnmarshaler(cfg, rv, t); ok { return lineError(t.Line, err) } switch { case rv.Kind() == reflect.Struct: - fc := makeFieldCache(rv.Type()) + fc := makeFieldCache(cfg, rv.Type()) for key, fieldAst := range t.Fields { - fv, fieldName, err := fc.findField(rv, key) + fv, fieldName, err := fc.findField(cfg, rv, key) if err != nil { return lineError(fieldLineNumber(fieldAst), err) } - if err := unmarshalField(fv, fieldAst); err != nil { - return lineErrorField(fieldLineNumber(fieldAst), rv.Type().String()+"."+fieldName, err) + if fv.IsValid() { + if err := unmarshalField(cfg, fv, fieldAst); err != nil { + return lineErrorField(fieldLineNumber(fieldAst), rv.Type().String()+"."+fieldName, err) + } } } case rv.Kind() == reflect.Map || isEface(rv): @@ -179,7 +180,7 @@ func unmarshalTable(rv reflect.Value, t *ast.Table, toplevelMap bool) error { return lineError(fieldLineNumber(fieldAst), err) } fv := reflect.New(elemtyp).Elem() - if err := unmarshalField(fv, fieldAst); err != nil { + if err := unmarshalField(cfg, fv, fieldAst); err != nil { return lineError(fieldLineNumber(fieldAst), err) } m.SetMapIndex(kv, fv) @@ -206,15 +207,15 @@ func fieldLineNumber(fieldAst interface{}) int { } } -func unmarshalField(rv reflect.Value, fieldAst interface{}) error { +func unmarshalField(cfg *Config, rv reflect.Value, fieldAst interface{}) error { switch av := fieldAst.(type) { case *ast.KeyValue: - return setValue(rv, av.Value) + return setValue(cfg, rv, av.Value) case *ast.Table: - return unmarshalTable(rv, av, false) + return unmarshalTable(cfg, rv, av, false) case []*ast.Table: rv = indirect(rv) - if err, ok := setUnmarshaler(rv, fieldAst); ok { + if err, ok := setUnmarshaler(cfg, rv, fieldAst); ok { return err } var slice reflect.Value @@ -228,7 +229,7 @@ func unmarshalField(rv reflect.Value, fieldAst interface{}) error { } for i, tbl := range av { vv := reflect.New(slice.Type().Elem()).Elem() - if err := unmarshalTable(vv, tbl, false); err != nil { + if err := unmarshalTable(cfg, vv, tbl, false); err != nil { return err } slice.Index(i).Set(vv) @@ -266,9 +267,9 @@ func unmarshalMapKey(typ reflect.Type, key string) (reflect.Value, error) { return rv, nil } -func setValue(lhs reflect.Value, val ast.Value) error { +func setValue(cfg *Config, lhs reflect.Value, val ast.Value) error { lhs = indirect(lhs) - if err, ok := setUnmarshaler(lhs, val); ok { + if err, ok := setUnmarshaler(cfg, lhs, val); ok { return err } if err, ok := setTextUnmarshaler(lhs, val); ok { @@ -286,7 +287,7 @@ func setValue(lhs reflect.Value, val ast.Value) error { case *ast.Datetime: return setDatetime(lhs, v) case *ast.Array: - return setArray(lhs, v) + return setArray(cfg, lhs, v) default: panic(fmt.Sprintf("BUG: unhandled node type %T", v)) } @@ -302,11 +303,11 @@ func indirect(rv reflect.Value) reflect.Value { return rv } -func setUnmarshaler(lhs reflect.Value, av interface{}) (error, bool) { +func setUnmarshaler(cfg *Config, lhs reflect.Value, av interface{}) (error, bool) { if lhs.CanAddr() { if u, ok := lhs.Addr().Interface().(UnmarshalerRec); ok { err := u.UnmarshalTOML(func(v interface{}) error { - return unmarshalTableOrValue(reflect.ValueOf(v), av) + return unmarshalTableOrValue(cfg, reflect.ValueOf(v), av) }) return err, true } @@ -438,7 +439,7 @@ func setDatetime(rv reflect.Value, v *ast.Datetime) error { return nil } -func setArray(rv reflect.Value, v *ast.Array) error { +func setArray(cfg *Config, rv reflect.Value, v *ast.Array) error { var slicetyp reflect.Type switch { case rv.Kind() == reflect.Slice: @@ -463,7 +464,7 @@ func setArray(rv reflect.Value, v *ast.Array) error { return errArrayMultiType } tmp := reflect.New(typ).Elem() - if err := setValue(tmp, vv); err != nil { + if err := setValue(cfg, tmp, vv); err != nil { return err } slice.Index(i).Set(tmp) diff --git a/vendor/github.com/naoina/toml/encode.go b/vendor/github.com/naoina/toml/encode.go index 9d899c57da..ae6bfd575f 100644 --- a/vendor/github.com/naoina/toml/encode.go +++ b/vendor/github.com/naoina/toml/encode.go @@ -10,7 +10,6 @@ import ( "strconv" "time" - "github.com/naoina/go-stringutil" "github.com/naoina/toml/ast" ) @@ -25,6 +24,7 @@ const ( // the TOML structure unless // - the field's tag is "-", or // - the field is empty and its tag specifies the "omitempty" option. +// // The "toml" key in the struct field's tag value is the key name, followed by // an optional comma and options. Examples: // @@ -41,20 +41,21 @@ const ( // // Field appears in TOML as key "field", but the field is skipped if // // empty. Note the leading comma. // Field int `toml:",omitempty"` -func Marshal(v interface{}) ([]byte, error) { +func (cfg *Config) Marshal(v interface{}) ([]byte, error) { buf := new(bytes.Buffer) - err := NewEncoder(buf).Encode(v) + err := cfg.NewEncoder(buf).Encode(v) return buf.Bytes(), err } // A Encoder writes TOML to an output stream. type Encoder struct { - w io.Writer + w io.Writer + cfg *Config } // NewEncoder returns a new Encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{w: w} +func (cfg *Config) NewEncoder(w io.Writer) *Encoder { + return &Encoder{w, cfg} } // Encode writes the TOML of v to the stream. @@ -71,9 +72,9 @@ func (e *Encoder) Encode(v interface{}) error { var err error switch rv.Kind() { case reflect.Struct: - err = buf.structFields(rv) + err = buf.structFields(e.cfg, rv) case reflect.Map: - err = buf.mapFields(rv) + err = buf.mapFields(e.cfg, rv) default: err = &marshalTableError{rv.Type()} } @@ -161,7 +162,7 @@ func (b *tableBuf) addChild(child *tableBuf) { b.children = append(b.children, child) } -func (b *tableBuf) structFields(rv reflect.Value) error { +func (b *tableBuf) structFields(cfg *Config, rv reflect.Value) error { rt := rv.Type() for i := 0; i < rv.NumField(); i++ { ft := rt.Field(i) @@ -177,9 +178,9 @@ func (b *tableBuf) structFields(rv reflect.Value) error { continue } if name == "" { - name = stringutil.ToSnakeCase(ft.Name) + name = cfg.FieldToKey(rt, ft.Name) } - if err := b.field(name, fv); err != nil { + if err := b.field(cfg, name, fv); err != nil { return err } } @@ -195,7 +196,7 @@ func (l mapKeyList) Len() int { return len(l) } func (l mapKeyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } func (l mapKeyList) Less(i, j int) bool { return l[i].key < l[j].key } -func (b *tableBuf) mapFields(rv reflect.Value) error { +func (b *tableBuf) mapFields(cfg *Config, rv reflect.Value) error { keys := rv.MapKeys() keylist := make(mapKeyList, len(keys)) for i, key := range keys { @@ -209,18 +210,18 @@ func (b *tableBuf) mapFields(rv reflect.Value) error { sort.Sort(keylist) for _, kv := range keylist { - if err := b.field(kv.key, kv.value); err != nil { + if err := b.field(cfg, kv.key, kv.value); err != nil { return err } } return nil } -func (b *tableBuf) field(name string, rv reflect.Value) error { +func (b *tableBuf) field(cfg *Config, name string, rv reflect.Value) error { off := len(b.body) b.body = append(b.body, quoteName(name)...) b.body = append(b.body, " = "...) - isTable, err := b.value(rv, name) + isTable, err := b.value(cfg, rv, name) if isTable { b.body = b.body[:off] // rub out "key =" } else { @@ -229,8 +230,8 @@ func (b *tableBuf) field(name string, rv reflect.Value) error { return err } -func (b *tableBuf) value(rv reflect.Value, name string) (bool, error) { - isMarshaler, isTable, err := b.marshaler(rv, name) +func (b *tableBuf) value(cfg *Config, rv reflect.Value, name string) (bool, error) { + isMarshaler, isTable, err := b.marshaler(cfg, rv, name) if isMarshaler { return isTable, err } @@ -249,7 +250,7 @@ func (b *tableBuf) value(rv reflect.Value, name string) (bool, error) { if rv.IsNil() { return false, &marshalNilError{rv.Type()} } - return b.value(rv.Elem(), name) + return b.value(cfg, rv.Elem(), name) case reflect.Slice, reflect.Array: rvlen := rv.Len() if rvlen == 0 { @@ -261,7 +262,7 @@ func (b *tableBuf) value(rv reflect.Value, name string) (bool, error) { wroteElem := false b.body = append(b.body, '[') for i := 0; i < rvlen; i++ { - isTable, err := b.value(rv.Index(i), name) + isTable, err := b.value(cfg, rv.Index(i), name) if err != nil { return isTable, err } @@ -281,12 +282,12 @@ func (b *tableBuf) value(rv reflect.Value, name string) (bool, error) { return !wroteElem, nil case reflect.Struct: child := b.newChild(name) - err := child.structFields(rv) + err := child.structFields(cfg, rv) b.addChild(child) return true, err case reflect.Map: child := b.newChild(name) - err := child.mapFields(rv) + err := child.mapFields(cfg, rv) b.addChild(child) return true, err default: @@ -295,7 +296,7 @@ func (b *tableBuf) value(rv reflect.Value, name string) (bool, error) { return false, nil } -func (b *tableBuf) marshaler(rv reflect.Value, name string) (handled, isTable bool, err error) { +func (b *tableBuf) marshaler(cfg *Config, rv reflect.Value, name string) (handled, isTable bool, err error) { switch t := rv.Interface().(type) { case encoding.TextMarshaler: enc, err := t.MarshalText() @@ -309,7 +310,7 @@ func (b *tableBuf) marshaler(rv reflect.Value, name string) (handled, isTable bo if err != nil { return true, false, err } - isTable, err = b.value(reflect.ValueOf(newval), name) + isTable, err = b.value(cfg, reflect.ValueOf(newval), name) return true, isTable, err case Marshaler: enc, err := t.MarshalTOML() diff --git a/vendor/github.com/naoina/toml/util.go b/vendor/github.com/naoina/toml/util.go index 51966e42da..f882f4e5f8 100644 --- a/vendor/github.com/naoina/toml/util.go +++ b/vendor/github.com/naoina/toml/util.go @@ -20,7 +20,7 @@ type fieldInfo struct { ignored bool } -func makeFieldCache(rt reflect.Type) fieldCache { +func makeFieldCache(cfg *Config, rt reflect.Type) fieldCache { named, auto := make(map[string]fieldInfo), make(map[string]fieldInfo) for i := 0; i < rt.NumField(); i++ { ft := rt.Field(i) @@ -31,7 +31,7 @@ func makeFieldCache(rt reflect.Type) fieldCache { col, _ := extractTag(ft.Tag.Get(fieldTagName)) info := fieldInfo{index: ft.Index, name: ft.Name, ignored: col == "-"} if col == "" || col == "-" { - auto[normFieldName(ft.Name)] = info + auto[cfg.NormFieldName(rt, ft.Name)] = info } else { named[col] = info } @@ -39,23 +39,23 @@ func makeFieldCache(rt reflect.Type) fieldCache { return fieldCache{named, auto} } -func (fc fieldCache) findField(rv reflect.Value, name string) (reflect.Value, string, error) { +func (fc fieldCache) findField(cfg *Config, rv reflect.Value, name string) (reflect.Value, string, error) { info, found := fc.named[name] if !found { - info, found = fc.auto[normFieldName(name)] + info, found = fc.auto[cfg.NormFieldName(rv.Type(), name)] } if !found { - return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' is not defined in %v", name, rv.Type()) + if cfg.MissingField == nil { + return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' is not defined in %v", name, rv.Type()) + } else { + return reflect.Value{}, "", cfg.MissingField(rv.Type(), name) + } } else if info.ignored { return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' in %v cannot be set through TOML", name, rv.Type()) } return rv.FieldByIndex(info.index), info.name, nil } -func normFieldName(s string) string { - return strings.Replace(strings.ToLower(s), "_", "", -1) -} - func extractTag(tag string) (col, rest string) { tags := strings.SplitN(tag, ",", 2) if len(tags) == 2 { diff --git a/vendor/vendor.json b/vendor/vendor.json index 9a08b45b3f..d79c80a67a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -202,16 +202,10 @@ "revisionTime": "2015-03-14T17:03:34Z" }, { - "checksumSHA1": "A6nZdZ1/lTOVINhIndyw2ZWN9JU=", - "path": "github.com/naoina/go-stringutil", - "revision": "6b638e95a32d0c1131db0e7fe83775cbea4a0d0b", - "revisionTime": "2015-11-18T23:44:43Z" - }, - { - "checksumSHA1": "qzMyvEe802B17Amr94Lq2KvFif4=", + "checksumSHA1": "2gmvVTDCks8cPhpmyDlvm0sbrXE=", "path": "github.com/naoina/toml", - "revision": "5fabdde119404993567f090673d9fb7b05b57833", - "revisionTime": "2017-04-05T10:49:32Z" + "revision": "ac014c6b6502388d89a85552b7208b8da7cfe104", + "revisionTime": "2017-04-10T21:57:17Z" }, { "checksumSHA1": "xZBlSMT5o/A+EDOro6KbfHZwSNc=",