mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 15:46:43 +00:00
cmd/geth: make TOML keys look exactly like Go struct fields
This commit is contained in:
parent
ee69b41d54
commit
075642f105
9 changed files with 192 additions and 89 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:"-"`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
86
vendor/github.com/naoina/toml/config.go
generated
vendored
Normal file
86
vendor/github.com/naoina/toml/config.go
generated
vendored
Normal file
|
|
@ -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)
|
||||
}
|
||||
65
vendor/github.com/naoina/toml/decode.go
generated
vendored
65
vendor/github.com/naoina/toml/decode.go
generated
vendored
|
|
@ -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)
|
||||
|
|
|
|||
47
vendor/github.com/naoina/toml/encode.go
generated
vendored
47
vendor/github.com/naoina/toml/encode.go
generated
vendored
|
|
@ -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()
|
||||
|
|
|
|||
18
vendor/github.com/naoina/toml/util.go
generated
vendored
18
vendor/github.com/naoina/toml/util.go
generated
vendored
|
|
@ -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 {
|
||||
|
|
|
|||
12
vendor/vendor.json
vendored
12
vendor/vendor.json
vendored
|
|
@ -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=",
|
||||
|
|
|
|||
Loading…
Reference in a new issue