spf13 / viper

Go configuration with fangs
MIT License
27.36k stars 2.02k forks source link

Support environment variable expansion in config files #315

Open F21 opened 7 years ago

F21 commented 7 years ago

Let's say I have some yaml and environment variables like so:

service:
  parameters: ${VARIABLE_1}-${VARIABLE_2}
VARIABLE_1=test1
VARIABLE_2=test2

It would be nice if viper can perform environment variable expansion, so that the result is:

service:
  parameters: test1-test2
bubunyo commented 7 years ago

+1

ufoscout commented 6 years ago

If you would consider it, this library of mine has among the various features, the one you are asking for: https://github.com/ufoscout/go-up

Nevertheless, it reads only from properties file at the moment. I will evaluate alternative formats (e.g. yaml or toml) but only if they does not add too many dependencies.

luisdavim commented 1 year ago

This would be a useful feature but maybe it could be achieved in a easy to implement and maintain way by just adding a pre unmarshall hook. This way users can implement any kind of templating themselves.

luisdavim commented 1 year ago

Here's how I solved this on my end. Created a custom string type that can hold a template and has a custom unmarshall function that triggers the rendering https://github.com/luisdavim/synthetic-checker/blob/main/pkg/config/templated_string.go

And I've also added a mapstructure hook to do the same https://github.com/luisdavim/synthetic-checker/blob/main/pkg/config/hooks.go#L38

The render function makes the environment variables available to the templates https://github.com/luisdavim/synthetic-checker/blob/main/pkg/template/template.go

You can see an example in the integration tests in https://github.com/luisdavim/synthetic-checker/blob/main/scripts/test.sh#L20

This works well but it could be more efficient if we had a pre hook to allow tapping in to the data before passing it to mapstructure, that would allow to process the whole file at once instead of a field at a time....

sagikazarmark commented 1 year ago

Something I have planned for quite a while now is creating a less file-centric interface interface for Viper. It doesn't mean the high-level API would Go away, but a lower level (eg. Reader-based) API would allow way more extensions without having to build everything right into Viper.

This would be a perfect example of such an extension.

SVilgelm commented 1 year ago

I have implemented the viper-template library to use the go templates in the configs and this should solve your issue:

service:
  parameters: {{ Getenv "VARIABLE_1" }}-{{ Genenv "VARIABLE_2"}}
funcs := template.FuncMap{
    "Getenv": os.Getenv,
}
val, err := vipertemplate.Get(
    "service.parameters",
    vipertemplate.WithFuncs(funcs),
)
amorey commented 1 year ago

Environment variable expansion in config files would be extremely useful. How about implementing it as a method like .AutomaticEnv() except for variable expansion (e.g. .AutomaticExpandEnv())?