feat: allow setting empty env var value
parent
997e9611eb
commit
6678040d30
24
conf.v
24
conf.v
|
@ -17,20 +17,18 @@ pub struct LoadConfig {
|
||||||
// looks for either `${env.prefix}${field_name.to_upper()}` or
|
// looks for either `${env.prefix}${field_name.to_upper()}` or
|
||||||
// `${env.prefix}${field_name.to_upper()}${env.file_suffix}`, returning the
|
// `${env.prefix}${field_name.to_upper()}${env.file_suffix}`, returning the
|
||||||
// contents of the file instead if the latter. If both or neither exist, the
|
// contents of the file instead if the latter. If both or neither exist, the
|
||||||
// function returns an error.
|
// function returns an error. It returns two values, with the first indicating
|
||||||
fn (ld LoadConfig) get_env_var(field_name string) !string {
|
// whether the env vars were actually present.
|
||||||
|
fn (ld LoadConfig) get_env_var(field_name string) !(bool, string) {
|
||||||
env_var_name := '$ld.prefix$field_name.to_upper()'
|
env_var_name := '$ld.prefix$field_name.to_upper()'
|
||||||
env_file_name := '$ld.prefix$field_name.to_upper()$ld.file_suffix'
|
env_file_name := '$ld.prefix$field_name.to_upper()$ld.file_suffix'
|
||||||
env_var := ld.env[env_var_name] or { '' }
|
|
||||||
env_file := ld.env[env_file_name] or { '' }
|
|
||||||
|
|
||||||
// If both are missing, we return an empty string
|
if env_var_name !in ld.env && env_file_name !in ld.env {
|
||||||
if env_var == '' && env_file == '' {
|
return false, ''
|
||||||
return ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If they're both set, we report a conflict
|
// If they're both set, we report a conflict
|
||||||
if env_var != '' && env_file != '' {
|
if env_var_name in ld.env && env_file_name in ld.env {
|
||||||
return error('Only one of $env_var_name or $env_file_name can be defined.')
|
return error('Only one of $env_var_name or $env_file_name can be defined.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,12 +36,12 @@ fn (ld LoadConfig) get_env_var(field_name string) !string {
|
||||||
// I'm pretty sure this also prevents variable ending in _FILE (e.g.
|
// I'm pretty sure this also prevents variable ending in _FILE (e.g.
|
||||||
// VIETER_LOG_FILE) from being mistakingely read as an _FILE suffixed env
|
// VIETER_LOG_FILE) from being mistakingely read as an _FILE suffixed env
|
||||||
// var.
|
// var.
|
||||||
if env_var != '' {
|
if env_var_name in ld.env {
|
||||||
return env_var
|
return true, ld.env[env_var_name]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we process the file
|
// Otherwise, we process the file
|
||||||
return os.read_file(env_file) or {
|
return true, os.read_file(ld.env[env_file_name]) or {
|
||||||
error('Failed to read file defined in $env_file_name: ${err.msg()}.')
|
error('Failed to read file defined in $env_file_name: ${err.msg()}.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,11 +84,11 @@ pub fn load<T>(ld LoadConfig) !T {
|
||||||
}
|
}
|
||||||
|
|
||||||
$for field in T.fields {
|
$for field in T.fields {
|
||||||
env_value := ld.get_env_var(field.name)!
|
env_present, env_value := ld.get_env_var(field.name)!
|
||||||
|
|
||||||
// The value of an env var will always take precedence over the toml
|
// The value of an env var will always take precedence over the toml
|
||||||
// file.
|
// file.
|
||||||
if env_value != '' {
|
if env_present {
|
||||||
$if field.typ is string {
|
$if field.typ is string {
|
||||||
res.$(field.name) = env_value
|
res.$(field.name) = env_value
|
||||||
} $else $if field.typ is int {
|
} $else $if field.typ is int {
|
||||||
|
|
117
string_test.v
117
string_test.v
|
@ -8,29 +8,47 @@ struct SingleConfDefault {
|
||||||
some_string string = 'default'
|
some_string string = 'default'
|
||||||
}
|
}
|
||||||
|
|
||||||
const env = {
|
|
||||||
'SOME_STRING': 'env'
|
|
||||||
}
|
|
||||||
|
|
||||||
const prefix_env = {
|
|
||||||
'TEST_SOME_STRING': 'env'
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_string_present_no_default() {
|
fn test_string_present_no_default() {
|
||||||
conf := load<SingleConf>(default_path: 'test/string.toml')!
|
conf := load<SingleConf>(default_path: 'test/string.toml')!
|
||||||
assert conf == SingleConf{
|
assert conf == SingleConf{
|
||||||
some_string: 'hi'
|
some_string: 'hi'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conf2 := load<SingleConf>(default_path: 'test/string_empty.toml')!
|
||||||
|
assert conf2 == SingleConf{
|
||||||
|
some_string: ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_string_present_no_default_env() {
|
fn test_string_present_no_default_env() {
|
||||||
conf := load<SingleConf>(default_path: 'test/string.toml', env: .env)!
|
mut conf := load<SingleConf>(
|
||||||
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'SOME_STRING': 'env'
|
||||||
|
}
|
||||||
|
)!
|
||||||
assert conf == SingleConf{
|
assert conf == SingleConf{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
|
|
||||||
conf2 := load<SingleConf>(default_path: 'test/string.toml', env: .prefix_env, prefix: 'TEST_')!
|
conf = load<SingleConf>(
|
||||||
assert conf2 == SingleConf{
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'SOME_STRING': ''
|
||||||
|
}
|
||||||
|
)!
|
||||||
|
assert conf == SingleConf{
|
||||||
|
some_string: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
conf = load<SingleConf>(
|
||||||
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'TEST_SOME_STRING': 'env'
|
||||||
|
}
|
||||||
|
prefix: 'TEST_'
|
||||||
|
)!
|
||||||
|
assert conf == SingleConf{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,13 +59,34 @@ fn test_string_absent_no_default() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_string_absent_no_default_env() {
|
fn test_string_absent_no_default_env() {
|
||||||
conf := load<SingleConf>(default_path: 'test/string.toml', env: .env)!
|
mut conf := load<SingleConf>(
|
||||||
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'SOME_STRING': 'env'
|
||||||
|
}
|
||||||
|
)!
|
||||||
assert conf == SingleConf{
|
assert conf == SingleConf{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
|
|
||||||
conf2 := load<SingleConf>(default_path: 'test/string.toml', env: .prefix_env, prefix: 'TEST_')!
|
conf = load<SingleConf>(
|
||||||
assert conf2 == SingleConf{
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'SOME_STRING': ''
|
||||||
|
}
|
||||||
|
)!
|
||||||
|
assert conf == SingleConf{
|
||||||
|
some_string: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
conf = load<SingleConf>(
|
||||||
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'TEST_SOME_STRING': 'env'
|
||||||
|
}
|
||||||
|
prefix: 'TEST_'
|
||||||
|
)!
|
||||||
|
assert conf == SingleConf{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,17 +99,34 @@ fn test_string_present_default() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_string_present_default_env() {
|
fn test_string_present_default_env() {
|
||||||
conf := load<SingleConfDefault>(default_path: 'test/string.toml', env: .env)!
|
mut conf := load<SingleConfDefault>(
|
||||||
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'SOME_STRING': 'env'
|
||||||
|
}
|
||||||
|
)!
|
||||||
assert conf == SingleConfDefault{
|
assert conf == SingleConfDefault{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
|
|
||||||
conf2 := load<SingleConfDefault>(
|
conf = load<SingleConfDefault>(
|
||||||
default_path: 'test/string.toml'
|
default_path: 'test/string.toml'
|
||||||
env: .prefix_env
|
env: {
|
||||||
|
'SOME_STRING': ''
|
||||||
|
}
|
||||||
|
)!
|
||||||
|
assert conf == SingleConfDefault{
|
||||||
|
some_string: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
conf = load<SingleConfDefault>(
|
||||||
|
default_path: 'test/string.toml'
|
||||||
|
env: {
|
||||||
|
'TEST_SOME_STRING': 'env'
|
||||||
|
}
|
||||||
prefix: 'TEST_'
|
prefix: 'TEST_'
|
||||||
)!
|
)!
|
||||||
assert conf2 == SingleConfDefault{
|
assert conf == SingleConfDefault{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,17 +139,34 @@ fn test_string_absent_default() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_string_absent_default_env() {
|
fn test_string_absent_default_env() {
|
||||||
conf := load<SingleConfDefault>(default_path: 'test/empty.toml', env: .env)!
|
mut conf := load<SingleConfDefault>(
|
||||||
|
default_path: 'test/empty.toml'
|
||||||
|
env: {
|
||||||
|
'SOME_STRING': 'env'
|
||||||
|
}
|
||||||
|
)!
|
||||||
assert conf == SingleConfDefault{
|
assert conf == SingleConfDefault{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
|
|
||||||
conf2 := load<SingleConfDefault>(
|
conf = load<SingleConfDefault>(
|
||||||
default_path: 'test/empty.toml'
|
default_path: 'test/empty.toml'
|
||||||
env: .prefix_env
|
env: {
|
||||||
|
'SOME_STRING': ''
|
||||||
|
}
|
||||||
|
)!
|
||||||
|
assert conf == SingleConfDefault{
|
||||||
|
some_string: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
conf = load<SingleConfDefault>(
|
||||||
|
default_path: 'test/empty.toml'
|
||||||
|
env: {
|
||||||
|
'TEST_SOME_STRING': 'env'
|
||||||
|
}
|
||||||
prefix: 'TEST_'
|
prefix: 'TEST_'
|
||||||
)!
|
)!
|
||||||
assert conf2 == SingleConfDefault{
|
assert conf == SingleConfDefault{
|
||||||
some_string: 'env'
|
some_string: 'env'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
some_int = "hi"
|
|
@ -0,0 +1 @@
|
||||||
|
some_string = ""
|
Loading…
Reference in New Issue