Coder Social home page Coder Social logo

configor's Introduction

Configor

Golang Configuration tool that support YAML, JSON, TOML, Shell Environment (Supports Go 1.10+)

test status

Usage

package main

import (
	"fmt"
	"github.com/jinzhu/configor"
)

var Config = struct {
	APPName string `default:"app name"`

	DB struct {
		Name     string
		User     string `default:"root"`
		Password string `required:"true" env:"DBPassword"`
		Port     uint   `default:"3306"`
	}

	Contacts []struct {
		Name  string
		Email string `required:"true"`
	}
}{}

func main() {
	configor.Load(&Config, "config.yml")
	fmt.Printf("config: %#v", Config)
}

With configuration file config.yml:

appname: test

db:
    name:     test
    user:     test
    password: test
    port:     1234

contacts:
- name: i test
  email: [email protected]

Debug Mode & Verbose Mode

Debug/Verbose mode is helpful when debuging your application, debug mode will let you know how configor loaded your configurations, like from which file, shell env, verbose mode will tell you even more, like those shell environments configor tried to load.

// Enable debug mode or set env `CONFIGOR_DEBUG_MODE` to true when running your application
configor.New(&configor.Config{Debug: true}).Load(&Config, "config.json")

// Enable verbose mode or set env `CONFIGOR_VERBOSE_MODE` to true when running your application
configor.New(&configor.Config{Verbose: true}).Load(&Config, "config.json")

Auto Reload Mode

Configor can auto reload configuration based on time

// auto reload configuration every second
configor.New(&configor.Config{AutoReload: true}).Load(&Config, "config.json")

// auto reload configuration every minute
configor.New(&configor.Config{AutoReload: true, AutoReloadInterval: time.Minute}).Load(&Config, "config.json")

Auto Reload Callback

configor.New(&configor.Config{AutoReload: true, AutoReloadCallback: func(config interface{}) {
    fmt.Printf("%v changed", config)
}}).Load(&Config, "config.json")

Advanced Usage

  • Load mutiple configurations
// Earlier configurations have higher priority
configor.Load(&Config, "application.yml", "database.json")
  • Return error on unmatched keys

Return an error on finding keys in the config file that do not match any fields in the config struct. In the example below, an error will be returned if config.toml contains keys that do not match any fields in the ConfigStruct struct. If ErrorOnUnmatchedKeys is not set, it defaults to false.

Note that for json files, setting ErrorOnUnmatchedKeys to true will have an effect only if using go 1.10 or later.

err := configor.New(&configor.Config{ErrorOnUnmatchedKeys: true}).Load(&ConfigStruct, "config.toml")
  • Load configuration by environment

Use CONFIGOR_ENV to set environment, if CONFIGOR_ENV not set, environment will be development by default, and it will be test when running tests with go test

// config.go
configor.Load(&Config, "config.json")

$ go run config.go
// Will load `config.json`, `config.development.json` if it exists
// `config.development.json` will overwrite `config.json`'s configuration
// You could use this to share same configuration across different environments

$ CONFIGOR_ENV=production go run config.go
// Will load `config.json`, `config.production.json` if it exists
// `config.production.json` will overwrite `config.json`'s configuration

$ go test
// Will load `config.json`, `config.test.json` if it exists
// `config.test.json` will overwrite `config.json`'s configuration

$ CONFIGOR_ENV=production go test
// Will load `config.json`, `config.production.json` if it exists
// `config.production.json` will overwrite `config.json`'s configuration
// Set environment by config
configor.New(&configor.Config{Environment: "production"}).Load(&Config, "config.json")
  • Example Configuration
// config.go
configor.Load(&Config, "config.yml")

$ go run config.go
// Will load `config.example.yml` automatically if `config.yml` not found and print warning message
  • Load From Shell Environment
$ CONFIGOR_APPNAME="hello world" CONFIGOR_DB_NAME="hello world" go run config.go
// Load configuration from shell environment, it's name is {{prefix}}_FieldName
// You could overwrite the prefix with environment CONFIGOR_ENV_PREFIX, for example:
$ CONFIGOR_ENV_PREFIX="WEB" WEB_APPNAME="hello world" WEB_DB_NAME="hello world" go run config.go

// Set prefix by config
configor.New(&configor.Config{ENVPrefix: "WEB"}).Load(&Config, "config.json")
  • Anonymous Struct

Add the anonymous:"true" tag to an anonymous, embedded struct to NOT include the struct name in the environment variable of any contained fields. For example:

type Details struct {
	Description string
}

type Config struct {
	Details `anonymous:"true"`
}

With the anonymous:"true" tag specified, the environment variable for the Description field is CONFIGOR_DESCRIPTION. Without the anonymous:"true"tag specified, then environment variable would include the embedded struct name and be CONFIGOR_DETAILS_DESCRIPTION.

  • With flags
func main() {
	config := flag.String("file", "config.yml", "configuration file")
	flag.StringVar(&Config.APPName, "name", "", "app name")
	flag.StringVar(&Config.DB.Name, "db-name", "", "database name")
	flag.StringVar(&Config.DB.User, "db-user", "root", "database user")
	flag.Parse()

	os.Setenv("CONFIGOR_ENV_PREFIX", "-")
	configor.Load(&Config, *config)
	// configor.Load(&Config) // only load configurations from shell env & flag
}

Contributing

You can help to make the project better, check out http://gorm.io/contribute.html for things you can do.

Author

jinzhu

License

Released under the MIT License

configor's People

Contributors

c4s4 avatar darinkrauss avatar jinzhu avatar k3a avatar kovetskiy avatar moisespsena avatar slijkhuis avatar xzya avatar zenermerps avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

configor's Issues

Support embedded directories

Describe the feature

There is a new feature in Golang 1.16 which allows embedding multiple files in the executable.
More info: https://blog.jetbrains.com/go/2021/06/09/how-to-use-go-embed-in-go-1-16

Will be great if configor has a LoadFromMemory method that allows passing embed.FS to it instead of a file path.

Motivation

The embedding of config files is useful when the executable cannot use absolute paths to refer to its config files and relative paths depend on the working directory which causes issues.

[]bytes tries to convert to []uint8

yaml:
key: "MYRANDOMEKEY"

proto:
bytes key = 1 [(gogoproto.moretags) = "yaml:",omitempty""];

proto.go
Key []byte protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty" yaml:",omitempty"

{"level":"fatal","error":"yaml: unmarshal errors:\n line 86: cannot unmarshal !!str MYRANDOMEKEY... into []uint8","time":"2020-07-03T21:33:59-07:00"}

use fsnotify instead of polling for autoreload

Describe the feature

configor should reload config when the file changes and not poll it every once in a while.

Motivation

Currently, it does polling, if I do it too aggressively it calls my function too often, if not, then my credentials are rotated, but I won't know about it.

A much nicer API would be to use fsnotify instead. It has good support and it only calls if the file has changed.

Related Issues

Test conditions in code

I would not put test conditions in production code, such as:

if isTest, _ := regexp.MatchString("/_test/", os.Args[0]); isTest {
    return "test"
}

Obscure `invalid config, should be struct` error being thrown sometimes

I had some users report the following issue: failed to load configuration from '/myproject/pawn.json': invalid config, should be struct.

This comes from the following line of code: https://github.com/Southclaws/sampctl/blob/master/types/package.go#L140

As you can see, pkg is a struct, it's a types.Package struct and is initialised by the return value definition. I can't reproduce this myself on my macbook though which is odd, my users are all on Windows afaik.

Loading struct with unexported field causes crash

Hello,

Having a model like this one

type Model struct {
	Name        string
	CreatedAt time.Time
}

will cause the following error

panic: reflect.Value.Interface: cannot return value obtained from unexported field or method

on this line, because time.Time has unexported fields, and you are calling field.Interface(). You can get around it by defining another struct without that field, e.g.:

type TestModel struct {
	Name        string
}

but this is not very maintainable, especially when having a lot of complex objects.

So maybe instead of crashing, just skip the unexported fields? E.g. you can check if you can access the field via field.CanInterface() before accessing field.Interface() in order to avoid the crash.

Thanks!

Loading configuration by env stops at struct bool if env is not a bool

If env name is not a bool (true or false), e.g. 1 or 0, as described in struct, then it stops loading more env.

export ENVIRONMENT_ID=id
export ENVIRONMENT_NAME=name
export ENVIRONMENT_REUSE=1
export ENVIRONMENT_GROUP=group

Environment struct {
ID string env:"ENVIRONMENT_ID"
Name string env:"ENVIRONMENT_NAME"
Reuse bool env:"ENVIRONMENT_REUSE"
Group string env:"ENVIRONMENT_GROUP"
}

Debug mode:
Loading configuration for struct 's field ID from env ENVIRONMENT_ID...
Loading configuration for struct 's field Name from env ENVIRONMENT_NAME...
Loading configuration for struct 's field Reuse from env ENVIRONMENT_REUSE...
Configuration:
...

Does not populate maps from environment variables

Given the following struct:

type Configuration struct {
  Item map[string]string
}

And environment variables:

CONFIGOR_CONFIGURATION_ITEM_KEY1=value1
CONFIGOR_CONFIGURATION_ITEM_KEY2=value2

The struct's Item is not populated.

Missing tags for versioning

Hey, first of all congrats for the nice package!

Without git tags there is no way for package managers to lock a version, and will always update to the latest commit.

This project may be in a very early phase but it's always good to have at least on tag to prevent breaking changes and kind of stuff.

It's possible to release 1.0.0 or 0.1.0 at the current master branch?

wrong example in the README.md

The example in README.md can not work.
I found it is because the "gopkg.in/yaml.v2" package only support lower case letters in the yaml file.
If you want to use Upper case letters in the yaml file you must declare yaml:"Name" in the struct.

Cannot read the targetfile when I placed the config file in a subpakage and then run program with Environment argument

code like:
configPath := flag.String("conf", "config/config.yml", "default config file name : config.yml")
env := flag.String("env", "", "run environment: default: test, opt: prod / dev")
flag.Parse()
configor.New(&configor.Config{Environment: *env}).Load(&Config, *configPath)

the run command is :
go build -o main.exe main.go
main.exe -conf ./config/config.yml -env prod

but the program load the file named config.yml not config.prod.yml

Recursive nested YAML structure

Hi,

I'm running in the issue that the YAML config is not loaded correctly or better the programm runs in an infinitive loop.

Given is the following YAML config:

smartdevices:
  - name: Tado_Esszimmer
    id: tado.0.466027.Rooms.1
    tags:
      product: tado
      room: esszimmer
    values:
    - id: tado.0.466027.Rooms.1.Actual_Humidity
      field: humidity
    - id: tado.0.466027.Rooms.1.Actual_Temperature
      field: temperature
    - id: tado.0.466027.Rooms.1.openWindow
      values:
      - id: tado.0.466027.Rooms.1.openWindow.detectedTime
        field: open_window_detected_time
      - id: tado.0.466027.Rooms.1.openWindow.durationInSeconds
        field: open_window_duration_in_seconds
      - id: tado.0.466027.Rooms.1.openWindow.expiry
        field: open_window_expiry
      - id: tado.0.466027.Rooms.1.openWindow.remainingTimeInSeconds
        field: open_window_remaining_time

The Go definition of that as structs:

// IoDevice defines an object/device
type IoDevice struct {
	Name string `yaml:"name"`
	ID   string `yaml:"id"`
	Tags struct {
		Product string `yaml:"product"`
		Haus    string `yaml:"haus"`
		Room    string `yaml:"room"`
	} `yaml:"tags"`
	Values []IoValue `yaml:"values"`
}

// IoValue defines the value
type IoValue struct {
	ID    string `yaml:"id"`
	Field string `yaml:"field,omitempty"`
	Values []IoValue `yaml:"values"`
}

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)

	// Load config.yaml file
	path, err := os.Getwd()
	if err != nil {
		log.Println(err)
	}
	fmt.Println(path) // for example /home/user
	err = configor.New(&configor.Config{Debug: true}).Load(&YAMLConfig, filepath.Join(path, "config.yaml"))
	if err != nil {
		log.Fatal(err)
	}

	for _, device := range YAMLConfig.IoBrokerDevices {
		if len(device.Name) > 0 {
			fmt.Println("Not null")
		}
		fmt.Printf("Lenn values: %d\n", len(device.Name))
	}
}

The ouput is as follows

C:\apps\gomqtt
Current environment: 'development'
Loading configurations from file 'C:\apps\iobroker\gomqtt\config.yaml'...

End then it runs in an infintive loop. The next lines are never executed.

Any hints?

Thanks for your help!

Can't load string with line break correct through env

The line break character will be change to a space character (see the example below).

package main

import (
	"fmt"
	"os"

	"github.com/jinzhu/configor"
)

type config struct {
	LineBreakString string `required:"true"`
}

func main() {
	cfg := &config{}

	if err := configor.Load(cfg); err != nil {
		panic(err)
	}

	if cfg.LineBreakString != os.Getenv("CONFIGOR_LineBreakString") {
		fmt.Printf("os.Getenv: \n%v\n", os.Getenv("CONFIGOR_LineBreakString"))
		fmt.Printf("configor.Load: \n%v\n", cfg.LineBreakString)
		panic("unexpected LineBreakString value loaded from env")
	}
}
$ export CONFIGOR_ENV_PREFIX="CONFIGOR"
$ export CONFIGOR_LineBreakString="Line one
Line two
Line three
And more lines"
$ go run main.go
os.Getenv:
Line one
Line two
Line three
And more lines
configor.Load:
Line one Line two Line three And more lines
panic: unexpected LineBreakString value loaded from env

Support command line flags

If configor could support command line flags as well, this package would beat others like viper. Most configuration packages require calling a ton of special functions and have separate handling of different config ways.

If configor could support CLI flags while sticking to the simple struct-approach, that would be awesome!

无法正常读取yaml文件

根据readme中的代码原样拷贝至代码文件,解析时仅得到了默认值,请问可能的原因是什么?

config: struct { APPName string "default:\"app name\""; DB struct { Name string; User string "default:\"root\""; Password string "required:\"true\" env:\"DBPassword\""; Port uint "default:\"3306\"" }; Contacts []struct { Name string; Email string "required:\"true\"" } }{APPName:"app name", DB:struct { Name string; User string "default:\"root\""; Password string "required:\"true\" env:\"DBPassword\""; Port uint "default:\"3306\"" }{Name:"", User:"root", Password:"", Port:0x0}, Contacts:[]struct { Name string; Email string "required:\"true\"" }(nil)}

config.yml未做改

APPName: test

DB:
    Name:     test
    User:     test
    Password: test
    Port:     1234

Contacts:
- Name: i test
  Email: [email protected]

是格式的原因吗?

Document how to use []string with ENV variables

When the config struct contains a slice, f.e. of strings, the config files allow for using lists and command line arguments allow for repeating arguments.

How does that work for environment variables?

Lists/slices from environment

Is it possible to populate a []string field from environment variables? Perhaps something like:

var cfg = struct{
  Names []string
}
CONFIGOR_NAMES_1=bob CONFIGOR_NAMES_2=fred go run main.go

Can't parse list/array in YAML

My env is "go version go1.5.3 darwin/amd64"
Failed to parse Contacts in example code (result is Contacts:[]struct { Name string; Email string "required:"true"" }(nil)), only primitive type from shell environment is ok.

Map type cause error "already set in map" with ErrorOnUnmatchedKeys, multiple YAML overlays

I am using following structs and enabled ErrorOnUnmatchedKeys

Got Error
yaml: unmarshal errors:\n line 21: key \"account\" already set in map\n line 24: key \"greeter\" already set in map\n line 27: key \"emailer\" already set in map\n line 30: key \"recorder\" already set in map

type Service struct {
	Endpoint             string   `yaml:"endpoint,omitempty"`
	Version              string   `yaml:"version,omitempty" default:"v0.1.0"`
	Deadline             uint32   `yaml:",omitempty" default:"1000000"`
}

type Configuration struct {
	Services             map[string]*Service   
}

config.yaml

services:
  account:
    endpoint: mkit.service.account
    version: v0.1.0
  greeter:
    endpoint: mkit.service.greeter
    version: v0.1.0
  emailer:
    endpoint: mkit.service.emailer
    version: v0.1.0
  recorder:
    endpoint: mkit.service.recorder
    version: v0.1.0

config.development.yaml

services:
  account:
    endpoint: mkit.service.account
    version: v0.2.0
  greeter:
    endpoint: mkit.service.greeter
    version: v0.2.0

使用yaml.v2的库不能build

报错:

github.com/jinzhu/configor

../../../jinzhu/configor/utils.go:102:11: undefined: yaml.UnmarshalStrict
../../../jinzhu/configor/utils.go:123:16: undefined: yaml.UnmarshalStrict

使用以下库代替解决:
"github.com/go-yaml/yaml"

No indication when there are unmatched keys in config file

Hello,

When loading a config file into a struct, like this: configor.Load(&Config, "config.yml"), there is no indication if there are any keys in config.yml that do not match any field in the Config struct. The Load function will silently load whatever it can and return.

It would be nice to have the ability to return an error when there are keys in the file that do not match any field in the struct. That will make it easier to catch errors in the config file.

Add support for loading into interface fields which have a *struct{} in them

Describe the feature

Add the ability to load a struct that has an interface element which has a struct assigned to it

Motivation

This would support go style polymorphism, where a portion of the configuration is set before Load() is called.

Consider the following:

type DatabaseProvider interface {
  GetDatabase() *gorm.DB
}
type SqliteDatabase struct {
  File string `env:"SQLITE_DATABASE_FILE"`
  // ...
}
func (s *SqliteDatabase) GetDB() *gorm.DB {
  // ...
}
type PostgresqlDatabase struct {
  Name string `env:"PSQL_DATABASE_NAME"`
  // ...
}
func (p *PostgresqlDatabase) GetDB() *gorm.DB {
  // ...
}
type AppConfig struct {
  DatabaseProvider `anonymous:"true"`
}
func NewAppConfig() (*AppConfig, error) {
  env := os.GetEnvironment("ENVIRONMENT")
  var appConfig *AppConfig
  switch env {
  case "dev":
    appConfig = &AppConfig{ &SqliteDatabase{} }
  default:
    appConfig = &AppConfig{ &PostgresqlDatabase{} }
  }
  return appConfig, configor.New(&configor.Config{}).Load(appConfig)
}

Currently configor will not load the underlying database configuration, but there is no reason that it cannot do so since the value of the interface is a struct.

Related Issues

attempting to load slice from env leads to errors

Hello,

With this commit 7dd23e5#diff-7d1c2a3334601b6c1958aae0a594cba8R240 , it looks lie behaviour for loading slices changed and now if a slice has 0 length in the config file then it is attempted to be loaded from the environment variables. What happens is that if the slice is made up of structs then a new struct is initialised and them attempted to be validate and this will lead to failure if the struct as any required elements which are not set in the environment.

For example, I have a configuration file made up of the below Cfg struct:

type Cfg struct {
	DataDir       string             `required:"true" yaml:"data_dir" json:"data_dir"`
	Email  []ConfigNotificationEmail  `yaml:"email,omitempty" json:"email,omitempty"`
}
type ConfigNotificationEmail struct {
	Server string   `required:"true" yaml:"server" json:"server"`
	User   string   `yaml:"user,omitempty" json:"user,omitempty"`
}

Loading a yaml file into the Cfg struct will now fail because the Email array which is defined as optional (omitempty) and which is made up of elements of type ConfigNotificationEmail fails because the Server element is not defined; the actual error is:

Server is required, but blank

I don't have in my configuration file any definition for a email entry but because now the env vars are looked up and during validation an empty struct of type ConfigNotificationEmail is created and then attempted to be validated, it then leads to failing to load the whole configuration.

Before the mentioned patch was applied, this was not an issue.

P.S. If I do add an email entry in my .yaml config file and this entry has the server key then things work as expected. The problem appears only when there is no email entry.

Nested YAML issue

Hi,

How to define a type for the following YAML?

part1:
- level1:
 - level2:
   -level3:
       key1: value1
       key2: value2

Is the scenario supported in general?

Ambiguous error message on required

Hi, thanks for this project.
We have only one painfull issue with this library.
We use this for web services configuration and the config struct is nested and contains a lot of URLs to other services.

Sometimes we forgot to add secret to Vault, but error message is not much helpfull.

Here is our common usage
https://play.golang.org/p/XdV_kGtkQn7

package main

import (
	"fmt"
	"log"

	"github.com/jinzhu/configor"
)

type Config struct {
	InputService struct {
		URL string `env:"IN_SERVICE_URL" required:"true"`
	}
	OutputService struct {
		URL string `env:"OUT_SERVICE_URL" required:"true"`
	}
}

func main() {
	var config Config
	if err := configor.Load(&config); err != nil {
		log.Fatal(err) // URL is required, but blank
	}

	fmt.Println("Your config:", config)
}

no functionality behind required: true

For me, using Password string required:"true" does not fail anything if Password is empty. I propose to either remove this from the documentation or actually do something with it.

I am using a YAML config file

Bool property with default value works not properly

I have a problem with a default value for a boolean property.

type Config struct {
	Silent bool `default:"true"`
}

Yaml:

silent: false

Result:

err := configor.Load(conf, *configPath)
if err != nil {
	log.Fatal(err)
}
log.Println(conf.Silent)

Actual:

true

Expected:

false

Obscure error caused by a `default` tag: line 1: cannot unmarshal !!seq into string

This stumped me for quite a while, not sure if it's a bug or just an undocumented quirk but I figured I should open an issue here anyway.

Some of my fields have a default tag, it seems that this particular piece of code was trying to unmarshal the data and failing causing the entire load to fail.

This is the struct that caused most of the issues:

https://github.com/Southclaws/sampctl/blob/master/types/runtime.go#L34

It contains mostly "-" as the default value, but maybe it was the fact that it used *string types instead of string?

I'm still not sure, for now my fix is to simply ignore errors of this type:

https://github.com/Southclaws/sampctl/blob/dev/types/package.go#L142-L144

Which is messy but temporary until I know more about this problem.

Thanks for such a useful library!

Specify env var name in .yml file instead of go struct

Is there a way to use env var specified as a value in .yml file? I would prefer configor to do it dynamically.

test:
  some_setting: "THIS_IS_MY_ENV_VAR"
  some_other_setting: "YET_ANOTHER_ENV_VAR"
var Config = struct {
	Test struct {
		SomeSetting      string
		SomeOtherSetting string
	}
}{}

I've got multiple .yml config files which fits exactly the same struct (pattern). I want to avoid duplicating struct definition in Go, so it would be much better to have the ability to load env variables by what was specified in .yml file directly (env var name as a value). Is it possible?

I can accept any format. Something like this would work great (it's just an example, it doesn't work... yet 😄)

test:
  some_setting: "env.THIS_IS_MY_ENV_VAR"
  some_other_setting: "env.YET_ANOTHER_ENV_VAR"

Expected answer

Well, it's a simple question. Please let me know how to achieve my goal 😄

Bug: when struct has pointer to other struct, processDefaults is not working

Hot to Reproduce

Change the test case

func TestDefaultValue(t *testing.T) {
	config := generateDefaultConfig()
	config.APPName = ""
	config.DB.Port = 0
	config.DB.SSL = false

	if bytes, err := json.Marshal(config); err == nil {
		if file, err := ioutil.TempFile("/tmp", "configor"); err == nil {
			defer file.Close()
			defer os.Remove(file.Name())
			file.Write(bytes)

			var result testConfig
			Load(&result, file.Name())

			if !reflect.DeepEqual(result, generateDefaultConfig()) {
				t.Errorf("result should be set default value correctly")
			}
		}
	} else {
		t.Errorf("failed to marshal config")
	}
}

** using a pointer to Database**

type Anonymous struct {
	Description string
}

type Database struct {
	Name     string
	User     string `yaml:",omitempty" default:"root"`
	Password string `required:"true" env:"DBPassword"`
	Port     uint   `default:"3306" yaml:",omitempty" json:",omitempty"`
	SSL      bool   `default:"true" yaml:",omitempty" json:",omitempty"`
}

type Contact struct {
	Name  string
	Email string `required:"true"`
}

type testConfig struct {
	APPName   string `default:"configor" yaml:",omitempty" json:",omitempty"`
	Hosts     []string
	DB        *Database
	Contacts  []Contact
	Anonymous `anonymous:"true"`
	private   string
}

func generateDefaultConfig() testConfig {
	return testConfig{
		APPName: "configor",
		Hosts:   []string{"http://example.org", "http://jinzhu.me"},
		DB: &Database{
			Name:     "configor",
			User:     "configor",
			Password: "configor",
			Port:     3306,
			SSL:      true,
		},
		Contacts: []Contact{
			{
				Name:  "Jinzhu",
				Email: "[email protected]",
			},
		},
		Anonymous: Anonymous{
			Description: "This is an anonymous embedded struct whose environment variables should NOT include 'ANONYMOUS'",
		},
	}
}

Root cause

Problem is at https://github.com/jinzhu/configor/blob/master/utils.go#L217

		for field.Kind() == reflect.Ptr {
			field = field.Elem()
		}

after this statement, field.Kind() becomes invalid.

configor.Load(&config, "./config.yml") will not return an error if the config file is not found

Hi there,

Thank you for this nice library. We did just notice some unexpected behavior:

The load method will print an error message "Failed to find configuration ./config.yml" but will not return an error. This will cause the program to assume that a configuration was correctly loaded on continue on if no specific additional checks are implemented.

I think it would be better if the load method would return an error if no config file was found.

Example code doesn't compile

I would rather replace with an example that compiles and works:

package main

import (
    "fmt"
    "github.com/jinzhu/configor"
)

var Config = struct {
    APPName string `default:"app name"`

    DB struct {
        Name     string
        User     string `default:"root"`
        Password string `required:"true" env:"DBPassword"`
        Port     uint   `default:"3306"`
    }

    Contacts []struct {
        Name  string
        Email string `required:"true"`
    }
}{}

func main() {
    configor.Load(&Config, "config.yml")
    fmt.Printf("config: %#v", Config)
}

I would also give a corresponding example configuration file, such as config.yml:

APPName: test

DB:
    Name:     test
    User:     test
    Password: test
    Port:     1234

Contacts:
- Name: i test
  Email: [email protected]

default not supported in slice and map

Reproducible Example

type Config struct {
	Foo struct {
		Servers []struct {
			Name string
			Port int
			Host string `default:"0.0.0.0"`
		}
		Testing map[string]struct {
			Name string `default:"default"`
		}
	}
}

foo:
  servers:
    - name: dev
      port: 4000
    - name: alpha
      port: 5000
  testing:
    data1:

Description

The field in slice and map won't get default value when empty.

Bools not working

Bool variables not working.

config:

type Config struct {
	APPName        string `default:"app name"`
	InsecurePolicy bool

file:

appname: test
InsecurePolicy: true

output:

INFO[0000] {"APPName":"test","InsecurePolicy":false, ...

doesn't support camel, or _ - split style field name in yml file

server:
  id: 1
  name: ''

db:
  driverName: mysql
  url: ''
  demoDb: ''
  dataDb: ''
var Config = struct {
	Server struct {
		Id   int    `required:"true"`
		Name string `required:"true"`
	}

	DB struct {
		DriverName string `required:"true"`
		Url      string `required:"true"`
		DemoDb  string `required:"true"`
		DataDb      string `required:"true"`
	}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.