feat: allow setting empty env var value

main
Jef Roosens 2022-12-28 18:36:58 +01:00
parent 997e9611eb
commit 6678040d30
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 108 additions and 35 deletions

24
conf.v
View File

@ -17,20 +17,18 @@ pub struct LoadConfig {
// looks for either `${env.prefix}${field_name.to_upper()}` or
// `${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
// function returns an error.
fn (ld LoadConfig) get_env_var(field_name string) !string {
// function returns an error. It returns two values, with the first indicating
// 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_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 == '' && env_file == '' {
return ''
if env_var_name !in ld.env && env_file_name !in ld.env {
return false, ''
}
// 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.')
}
@ -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.
// VIETER_LOG_FILE) from being mistakingely read as an _FILE suffixed env
// var.
if env_var != '' {
return env_var
if env_var_name in ld.env {
return true, ld.env[env_var_name]
}
// 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()}.')
}
}
@ -86,11 +84,11 @@ pub fn load<T>(ld LoadConfig) !T {
}
$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
// file.
if env_value != '' {
if env_present {
$if field.typ is string {
res.$(field.name) = env_value
} $else $if field.typ is int {

View File

@ -8,29 +8,47 @@ struct SingleConfDefault {
some_string string = 'default'
}
const env = {
'SOME_STRING': 'env'
}
const prefix_env = {
'TEST_SOME_STRING': 'env'
}
fn test_string_present_no_default() {
conf := load<SingleConf>(default_path: 'test/string.toml')!
assert conf == SingleConf{
some_string: 'hi'
}
conf2 := load<SingleConf>(default_path: 'test/string_empty.toml')!
assert conf2 == SingleConf{
some_string: ''
}
}
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{
some_string: 'env'
}
conf2 := load<SingleConf>(default_path: 'test/string.toml', env: .prefix_env, prefix: 'TEST_')!
assert conf2 == SingleConf{
conf = load<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'
}
}
@ -41,13 +59,34 @@ fn test_string_absent_no_default() {
}
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{
some_string: 'env'
}
conf2 := load<SingleConf>(default_path: 'test/string.toml', env: .prefix_env, prefix: 'TEST_')!
assert conf2 == SingleConf{
conf = load<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'
}
}
@ -60,17 +99,34 @@ fn test_string_present_default() {
}
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{
some_string: 'env'
}
conf2 := load<SingleConfDefault>(
conf = load<SingleConfDefault>(
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_'
)!
assert conf2 == SingleConfDefault{
assert conf == SingleConfDefault{
some_string: 'env'
}
}
@ -83,17 +139,34 @@ fn test_string_absent_default() {
}
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{
some_string: 'env'
}
conf2 := load<SingleConfDefault>(
conf = load<SingleConfDefault>(
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_'
)!
assert conf2 == SingleConfDefault{
assert conf == SingleConfDefault{
some_string: 'env'
}
}

1
test/int.toml 100644
View File

@ -0,0 +1 @@
some_int = "hi"

View File

@ -0,0 +1 @@
some_string = ""