Merge pull request 'Migrated env module to own Git repository' (#244) from Chewing_Bever/vieter:split-env into dev
	
		
			
	
		
	
	
		
			
				
	
				ci/woodpecker/push/test Pipeline is pending
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/build Pipeline failed
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docs Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/lint Pipeline failed
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docker unknown status
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/man unknown status
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/deploy unknown status
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/arch Pipeline failed
				
					Details
				
			
		
	
				
					
				
			
				
	
				ci/woodpecker/push/test Pipeline is pending
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/build Pipeline failed
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docs Pipeline was successful
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/lint Pipeline failed
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/docker unknown status
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/man unknown status
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/deploy unknown status
				
					Details
				
			
		
			
				
	
				ci/woodpecker/push/arch Pipeline failed
				
					Details
				
			
		
	Reviewed-on: vieter/vieter#244pull/248/head
						commit
						ae04fe63a7
					
				|  | @ -6,10 +6,19 @@ matrix: | ||||||
| platform: ${PLATFORM} | platform: ${PLATFORM} | ||||||
| 
 | 
 | ||||||
| pipeline: | pipeline: | ||||||
|   debug: |   install-modules: | ||||||
|     image: 'chewingbever/vlang:latest' |     image: 'chewingbever/vlang:latest' | ||||||
|     pull: true |     pull: true | ||||||
|     commands: |     commands: | ||||||
|  |       - export VMODULES=$PWD/.vmodules | ||||||
|  |       - 'cd src && v install' | ||||||
|  |     when: | ||||||
|  |       event: [pull_request] | ||||||
|  | 
 | ||||||
|  |   debug: | ||||||
|  |     image: 'chewingbever/vlang:latest' | ||||||
|  |     commands: | ||||||
|  |       - export VMODULES=$PWD/.vmodules | ||||||
|       - make |       - make | ||||||
|     when: |     when: | ||||||
|       event: [pull_request] |       event: [pull_request] | ||||||
|  | @ -18,10 +27,10 @@ pipeline: | ||||||
| 
 | 
 | ||||||
|   prod: |   prod: | ||||||
|     image: 'chewingbever/vlang:latest' |     image: 'chewingbever/vlang:latest' | ||||||
|     pull: true |  | ||||||
|     environment: |     environment: | ||||||
|       - LDFLAGS=-lz -lbz2 -llzma -lexpat -lzstd -llz4 -lsqlite3 -static |       - LDFLAGS=-lz -lbz2 -llzma -lexpat -lzstd -llz4 -lsqlite3 -static | ||||||
|     commands: |     commands: | ||||||
|  |       - export VMODULES=$PWD/.vmodules | ||||||
|       # Apparently this -D is *very* important |       # Apparently this -D is *very* important | ||||||
|       - CFLAGS='-DGC_THREADS=1' make prod |       - CFLAGS='-DGC_THREADS=1' make prod | ||||||
|       # Make sure the binary is actually statically built |       # Make sure the binary is actually statically built | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								PKGBUILD
								
								
								
								
							
							
						
						
									
										8
									
								
								PKGBUILD
								
								
								
								
							|  | @ -14,7 +14,15 @@ license=('AGPL3') | ||||||
| source=("$pkgname::git+https://git.rustybever.be/vieter/vieter#tag=${pkgver//_/-}") | source=("$pkgname::git+https://git.rustybever.be/vieter/vieter#tag=${pkgver//_/-}") | ||||||
| md5sums=('SKIP') | md5sums=('SKIP') | ||||||
| 
 | 
 | ||||||
|  | prepare() { | ||||||
|  |     export VMODULES="$srcdir/.vmodules" | ||||||
|  | 
 | ||||||
|  |     cd "$pkgname/src" && v install | ||||||
|  | } | ||||||
|  | 
 | ||||||
| build() { | build() { | ||||||
|  |     export VMODULES="$srcdir/.vmodules" | ||||||
|  | 
 | ||||||
|     cd "$pkgname" |     cd "$pkgname" | ||||||
| 
 | 
 | ||||||
|     make prod |     make prod | ||||||
|  |  | ||||||
|  | @ -22,7 +22,15 @@ pkgver() { | ||||||
|     git describe --long --tags | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' |     git describe --long --tags | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | prepare() { | ||||||
|  |     export VMODULES="$srcdir/.vmodules" | ||||||
|  | 
 | ||||||
|  |     cd "$pkgname/src" && v install | ||||||
|  | } | ||||||
|  | 
 | ||||||
| build() { | build() { | ||||||
|  |     export VMODULES="$srcdir/.vmodules" | ||||||
|  | 
 | ||||||
|     cd "$pkgname" |     cd "$pkgname" | ||||||
| 
 | 
 | ||||||
|     make prod |     make prod | ||||||
|  |  | ||||||
|  | @ -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