refactor: migrated env code to own external module
parent
4866cfa635
commit
44696fc11b
|
@ -41,6 +41,10 @@ Besides a V installer, Vieter also requires the following libraries to work:
|
||||||
* openssl
|
* openssl
|
||||||
* sqlite3
|
* sqlite3
|
||||||
|
|
||||||
|
Vieter also depends on some external V modules which you can install using `cd
|
||||||
|
src && v install`. Make sure to keep these dependencies up to date using `v
|
||||||
|
update`.
|
||||||
|
|
||||||
### Compiler
|
### Compiler
|
||||||
|
|
||||||
Vieter compiles with the standard Vlang compiler. However, I do maintain a
|
Vieter compiles with the standard Vlang compiler. However, I do maintain a
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module git
|
module git
|
||||||
|
|
||||||
import cli
|
import cli
|
||||||
import env
|
import vieter.vconf
|
||||||
import cron.expression { parse_expression }
|
import cron.expression { parse_expression }
|
||||||
import client
|
import client
|
||||||
import console
|
import console
|
||||||
|
@ -41,7 +41,7 @@ pub fn cmd() cli.Command {
|
||||||
]
|
]
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
mut filter := GitRepoFilter{}
|
mut filter := GitRepoFilter{}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Add a new repository.'
|
description: 'Add a new repository.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
add(conf, cmd.args[0], cmd.args[1], cmd.args[2])?
|
add(conf, cmd.args[0], cmd.args[1], cmd.args[2])?
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Remove a repository that matches the given ID prefix.'
|
description: 'Remove a repository that matches the given ID prefix.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
remove(conf, cmd.args[0])?
|
remove(conf, cmd.args[0])?
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Show detailed information for the repo matching the ID prefix.'
|
description: 'Show detailed information for the repo matching the ID prefix.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
info(conf, cmd.args[0])?
|
info(conf, cmd.args[0])?
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ pub fn cmd() cli.Command {
|
||||||
]
|
]
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
found := cmd.flags.get_all_found()
|
found := cmd.flags.get_all_found()
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Build the repo with the given id & publish it.'
|
description: 'Build the repo with the given id & publish it.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
build(conf, cmd.args[0].int())?
|
build(conf, cmd.args[0].int())?
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module logs
|
module logs
|
||||||
|
|
||||||
import cli
|
import cli
|
||||||
import env
|
import vieter.vconf
|
||||||
import client
|
import client
|
||||||
import console
|
import console
|
||||||
import time
|
import time
|
||||||
|
@ -65,7 +65,7 @@ pub fn cmd() cli.Command {
|
||||||
]
|
]
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
mut filter := BuildLogFilter{}
|
mut filter := BuildLogFilter{}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Show all info for a specific build log.'
|
description: 'Show all info for a specific build log.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
id := cmd.args[0].int()
|
id := cmd.args[0].int()
|
||||||
info(conf, id)?
|
info(conf, id)?
|
||||||
|
@ -156,7 +156,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Output the content of a build log to stdout.'
|
description: 'Output the content of a build log to stdout.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
id := cmd.args[0].int()
|
id := cmd.args[0].int()
|
||||||
content(conf, id)?
|
content(conf, id)?
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module cron
|
module cron
|
||||||
|
|
||||||
import cli
|
import cli
|
||||||
import env
|
import vieter.vconf
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
pub:
|
pub:
|
||||||
|
@ -24,7 +24,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Start the cron service that periodically runs builds.'
|
description: 'Start the cron service that periodically runs builds.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
cron(conf)?
|
cron(conf)?
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
This module provides a framework for parsing a configuration, defined as a
|
|
||||||
struct, from both a TOML configuration file & environment variables. Some
|
|
||||||
notable features are:
|
|
||||||
|
|
||||||
* Overwrite values in config file using environment variables
|
|
||||||
* Allow default values in config struct
|
|
||||||
* Read environment variable value from file
|
|
|
@ -1,102 +0,0 @@
|
||||||
module env
|
|
||||||
|
|
||||||
import os
|
|
||||||
import toml
|
|
||||||
|
|
||||||
const (
|
|
||||||
// The prefix that every environment variable should have
|
|
||||||
prefix = 'VIETER_'
|
|
||||||
// The suffix an environment variable in order for it to be loaded from a file
|
|
||||||
// instead
|
|
||||||
file_suffix = '_FILE'
|
|
||||||
)
|
|
||||||
|
|
||||||
// get_env_var tries to read the contents of the given environment variable. It
|
|
||||||
// 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 get_env_var(field_name string) ?string {
|
|
||||||
env_var_name := '$env.prefix$field_name.to_upper()'
|
|
||||||
env_file_name := '$env.prefix$field_name.to_upper()$env.file_suffix'
|
|
||||||
env_var := os.getenv(env_var_name)
|
|
||||||
env_file := os.getenv(env_file_name)
|
|
||||||
|
|
||||||
// If both are missing, we return an empty string
|
|
||||||
if env_var == '' && env_file == '' {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// If they're both set, we report a conflict
|
|
||||||
if env_var != '' && env_file != '' {
|
|
||||||
return error('Only one of $env_var_name or $env_file_name can be defined.')
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it's the env var itself, we return it.
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we process the file
|
|
||||||
return os.read_file(env_file) or {
|
|
||||||
error('Failed to read file defined in $env_file_name: ${err.msg()}.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// load<T> attempts to create an object of type T from the given path to a toml
|
|
||||||
// file & environment variables. For each field, it will select either a value
|
|
||||||
// given from an environment variable, a value defined in the config file or a
|
|
||||||
// configured default if present, in that order.
|
|
||||||
pub fn load<T>(path string) ?T {
|
|
||||||
mut res := T{}
|
|
||||||
|
|
||||||
if os.exists(path) {
|
|
||||||
// We don't use reflect here because reflect also sets any fields not
|
|
||||||
// in the toml back to their zero value, which we don't want
|
|
||||||
doc := toml.parse_file(path)?
|
|
||||||
|
|
||||||
$for field in T.fields {
|
|
||||||
s := doc.value(field.name)
|
|
||||||
|
|
||||||
if s !is toml.Null {
|
|
||||||
$if field.typ is string {
|
|
||||||
res.$(field.name) = s.string()
|
|
||||||
} $else $if field.typ is int {
|
|
||||||
res.$(field.name) = s.int()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$for field in T.fields {
|
|
||||||
env_value := get_env_var(field.name)?
|
|
||||||
|
|
||||||
// The value of an env var will always take precedence over the toml
|
|
||||||
// file.
|
|
||||||
if env_value != '' {
|
|
||||||
$if field.typ is string {
|
|
||||||
res.$(field.name) = env_value
|
|
||||||
} $else $if field.typ is int {
|
|
||||||
res.$(field.name) = env_value.int()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, we check whether a value is present. If there isn't, that means
|
|
||||||
// it isn't in the config file, nor is there a default or an env var.
|
|
||||||
mut has_value := false
|
|
||||||
|
|
||||||
$if field.typ is string {
|
|
||||||
has_value = res.$(field.name) != ''
|
|
||||||
} $else $if field.typ is int {
|
|
||||||
has_value = res.$(field.name) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has_value {
|
|
||||||
return error("Missing config variable '$field.name' with no provided default. Either add it to the config file or provide it using an environment variable.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
module server
|
module server
|
||||||
|
|
||||||
import cli
|
import cli
|
||||||
import env
|
import vieter.vconf
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
pub:
|
pub:
|
||||||
|
@ -19,7 +19,7 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Start the Vieter server.'
|
description: 'Start the Vieter server.'
|
||||||
execute: fn (cmd cli.Command) ? {
|
execute: fn (cmd cli.Command) ? {
|
||||||
config_file := cmd.flags.get_string('config-file')?
|
config_file := cmd.flags.get_string('config-file')?
|
||||||
conf := env.load<Config>(config_file)?
|
conf := vconf.load<Config>(default_path: config_file)?
|
||||||
|
|
||||||
server(conf)?
|
server(conf)?
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue