kkyr / fig Goto Github PK
View Code? Open in Web Editor NEWA minimalist Go configuration library
License: Apache License 2.0
A minimalist Go configuration library
License: Apache License 2.0
Hi,
I would like it, if it would be possible to search for different file names (same as dirs).
ex allow ./config.json ./config.yaml and ./config.toml
Thanks for the nice work.
fig uses the very powerful mapstructure under the hood just like viper. But unlike viper or uconfig it does not expose some sort of hook/middleware mechanism so that user defined logic can be executed as part of loading config
Introducing such a behavior might break backwards compatibility but it would be worth it in the long run.
I am writing an app that looks for a config.yaml
in
What I wish to add is an option to auto-create file on the initial startup. Of course, I can make it on my own before fig.Load()
but it will duplicate the code in the package (like methods findCfgFiles). Besides that, since I store all config properties under fig annotations it will be simple and more convenient.
Do you mind adding that kind of feature? I can open the PR soon
It would be nice to have an option/function to explicitly load the config file that was provided by user.
The idea is to have smth like:
package main
var configFile = flag.String("config", "app.yaml", "Config file to use") // so it may have the value like `/usr/local/etc/name_by_user.yaml`
func main() {
flag.Parse()
err := fig.Load(&cfg, fig.File(*configFile))
}
In the current implementation it wouldn't work because fig will search for the file in the current directory (.
) only by default. But it also can check for the file existence using only given path:
func (f *fig) findCfgFile() (path string, err error) {
for _, dir := range f.dirs {
path = filepath.Join(dir, f.filename)
if fileExists(path) {
return
}
}
if path = f.filename; fileExists(path) {
return
}
return "", fmt.Errorf("%s: %w", f.filename, ErrFileNotFound)
}
Hello and thanks for your great package.
I have a specific use case in which env var is using another names which is different with the name generated by the fig
for that field.
Can we add a new feature to achieve this.
Something like this:
type Config struct {
Field int `fig:"field" env:"DIFFERENT_KEY"`
}
This way, the config is loaded from a file using the current approach. But if the DIFFERENT_KEY
env is set, its value will be used for this field.
Howdy,
According to the documentation:
A default key in the field tag makes fig fill the field with the value specified when the field is not otherwise set.
Given the following config.yaml
:
itemone:
enabled: false
With the following program:
package main
import (
"fmt"
"github.com/kkyr/fig"
)
type Config struct {
ItemOne ItemOne `default:{}`
ItemTwo ItemTwo `default:{}`
}
type ItemOne struct {
Enabled bool `fig:"enabled" default:true`
}
type ItemTwo struct {
Enabled bool `fig:"enabled" default:true`
}
func main() {
var conf Config
err := fig.Load(&conf)
if err != nil {
panic(err)
}
fmt.Printf("Config %+v", conf)
}
What was expected:
Field ItemTwo.Enabled
would be set to boolean true
.
What actually happened:
Field ItemTwo.Enabled
is set to boolean false
:
Config {ItemOne:{Enabled:false} ItemTwo:{Enabled:false}}
I've slimmed down an existing program to this most basic PoC to rule out other code in my application being a problem, though my usage is perhaps still incorrect.
It would be nice to have something akin to json.DisallowUnknownFields and yaml.UnmarshalStrict to catch configuration invalid configurations earlier and make them an error.
I propose to add a new flag fig.UseStrict
, when set fig.Load
will return an error upon encountering unknown (i.e: extra) fields.
For example. given:
---
log_level: debug
host: "0.0.0.0"
type Config struct {
Host string `fig:"host"`
LogLevel string `fig:"logLevel"`
}
var cfg Server
fig.Load(&cfg, UseStrict()) // Returns error because the key `log_level` is unknown
I use fig to initialize a map of structs.
The fields in the struct have a "required" validation tag. However, fig does not enforce this validation.
E.g.
type Config struct {
Elements map[string]Element fig:"chartConfigs" validate:"required"
}
type Element struct {
Name string fig:"name" validate:"required"
}
var cfg Config
fig.Load(&cfg)
First of all, I love fig. It's such a versatile tool, thanks for this!
I was wondering if there would be a posibility to add config parsing/unmarshaling for custom types, like encode/json
allows to provide a UnmarshalJSON()
method. This would help i. e. with custom "enums" type that are set up via iota
.
Here is an example:
Let's say I have a custom type ListenerType
and I pre-define 3 types via const:
// ListenerType is an enumeration wrapper for the different listener types
type ListenerType uint
const (
ListenerUnix ListenerType = iota
ListenerTCP
ListenerTLS
)
In my config struct, I would then define my config setting with the corresponding ListenerType
and a default value:
// Config holds all the global configuration settings that are parsed by fig
type Config struct {
// Server holds server specific configuration values
Server struct {
PIDFile string `fig:"pid_file" default:"/var/run/app.pid"`
ListenerType ListenerType `fig:"listener_type" default:"unix"`
}
}
By default this would of course not work, as the default or provided setting in the config file would be a string, not an uint. But here comes my request into play. fig defines an interface like this:
type Unmarshaler interface {
UnmarshalType(string) error
}
and checks if the corresponding type provides a method that satisfies this interface. For my example it could look like this:
func (l *ListenerType) UnmarshalType(v string) error {
switch strings.ToLower(v) {
case "unix":
*l = ListenerUnix
case "tcp":
*l = ListenerTCP
case "tls":
*l = ListenerTLS
default:
return fmt.Errorf("unknown listener type: %s", v)
}
return nil
}
This way, I can keep my iota
type but fill the values via fig with the actual string values instead of the user having to provide "0", "1" or "2".
Hope this makes sense and is something you would consider adding.
Thank you for the library. It is something I've been planning to write myself. But I'd still hope for one more feature. Especially for projects packaged as docker images. Could you support some sort of environment variable interpolation syntax? Like ${FOOBAR}
being read from the environment variable FOOBAR?
The duration parser provided by the standard library fails when it's input doesn't include a time unit. As expected, fig also fails in such a case, but it doesn't when the input is not wrapped in quotes because it's interpreted as an integer and not a string.
For example, given:
// config.yaml
timeout: 1
// main.go
package main
import (
"fmt"
"log"
"time"
"github.com/kkyr/fig"
)
type Config struct {
Timeout time.Duration `fig:"timeout" validate:"required"`
}
func main() {
var cfg Config
if err := fig.Load(&cfg); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", cfg)
}
I would expect it to fail because timeout: 1
doesn't have a time unit, instead the config is parsed without errors and the set value is 1ns.
Maybe this could be fixed by adding a check of Int (and maybe float?) values in StringToTimeDurationHookFunc
, although I may be missing some other cases.
I really enjoy fig for my configuration, because it is simpler than other solutions, but I found a problem with it that is more than a nuance.
Imagine you have a config value set like below, and then in the config file you want to set it to 0: log_level: 0
LogLevel int `fig:"log_level" default:"1"` // -1:trace 0: debug, 1: info, 2: warn, 3: error, 4: fatal, 5: panic
The default value will be used, I assume because at the point it looks if it is set, it thinks it is not because it is set to the "zero" value of the type
Currently, environment variables can't be used as a full replacement for a config file, only in addition to one. If no config file exists, I think it should just use the defaults from the struct, check environment variables if UseEnv
is set, and then return an error if required stuff is not set (e.g. port: required validation failed (using only environment as no config file could be found)
).
Default values are not being applied if the config file does not exist
It would be nice to have an API to create/update a configuration file, keeping constraints in mind.
The call would be something like:
// do something with the settings' attributes
// ....
// Update the configuration file and check the constraints
fig.Update(&cfg, fig.File("settings.json"), fig.Dir("/app/conf"))
As sub plz.
The goal would be to avoid the dependency on one of them if a project uses only the other.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.