forked from vieter-v/vieter
				
			Merge pull request 'update to V 0.3.3' (#347) from Chewing_Bever/vieter:v-0.3.3 into dev
Reviewed-on: vieter-v/vieter#347remotes/1761201518397485255/dev
						commit
						69cc2404db
					
				|  | @ -10,6 +10,7 @@ skip_clone: true | ||||||
| pipeline: | pipeline: | ||||||
|   build: |   build: | ||||||
|     image: 'git.rustybever.be/vieter-v/vieter-builder' |     image: 'git.rustybever.be/vieter-v/vieter-builder' | ||||||
|  |     pull: true | ||||||
|     commands: |     commands: | ||||||
|       # Add the vieter repository so we can use the compiler |       # Add the vieter repository so we can use the compiler | ||||||
|       - echo -e '[vieter]\nServer = https://arch.r8r.be/$repo/$arch\nSigLevel = Optional' >> /etc/pacman.conf |       - echo -e '[vieter]\nServer = https://arch.r8r.be/$repo/$arch\nSigLevel = Optional' >> /etc/pacman.conf | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ skip_clone: true | ||||||
| pipeline: | pipeline: | ||||||
|   build: |   build: | ||||||
|     image: 'git.rustybever.be/vieter-v/vieter-builder' |     image: 'git.rustybever.be/vieter-v/vieter-builder' | ||||||
|  |     pull: true | ||||||
|     commands: |     commands: | ||||||
|       # Add the vieter repository so we can use the compiler |       # Add the vieter repository so we can use the compiler | ||||||
|       - echo -e '[vieter]\nServer = https://arch.r8r.be/$repo/$arch\nSigLevel = Optional' >> /etc/pacman.conf |       - echo -e '[vieter]\nServer = https://arch.r8r.be/$repo/$arch\nSigLevel = Optional' >> /etc/pacman.conf | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| variables: | variables: | ||||||
|   - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2-alpine3.17' |   - &vlang_image 'git.rustybever.be/vieter/vlang:5d4c9dc9fc11bf8648541c934adb64f27cb94e37-alpine3.17' | ||||||
| 
 | 
 | ||||||
| matrix: | matrix: | ||||||
|   PLATFORM: |   PLATFORM: | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| variables: | variables: | ||||||
|   - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2-alpine3.17' |   - &vlang_image 'git.rustybever.be/vieter/vlang:5d4c9dc9fc11bf8648541c934adb64f27cb94e37-alpine3.17' | ||||||
| 
 | 
 | ||||||
| platform: 'linux/amd64' | platform: 'linux/amd64' | ||||||
| branches: | branches: | ||||||
|  | @ -21,8 +21,9 @@ pipeline: | ||||||
|       - make api-docs |       - make api-docs | ||||||
| 
 | 
 | ||||||
|   slate-docs: |   slate-docs: | ||||||
|     image: 'slatedocs/slate' |     image: 'slatedocs/slate:v2.13.0' | ||||||
|     group: 'generate' |     group: 'generate' | ||||||
|  |     # Slate requires a specific directory to run in | ||||||
|     commands: |     commands: | ||||||
|       - cd docs/api |       - cd docs/api | ||||||
|       - bundle exec middleman build --clean |       - bundle exec middleman build --clean | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| variables: | variables: | ||||||
|   - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2-alpine3.17' |   - &vlang_image 'git.rustybever.be/vieter/vlang:5d4c9dc9fc11bf8648541c934adb64f27cb94e37-alpine3.17' | ||||||
| 
 | 
 | ||||||
| platform: 'linux/amd64' | platform: 'linux/amd64' | ||||||
| branches: [ 'main' ] | branches: [ 'main' ] | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| variables: | variables: | ||||||
|   - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2-alpine3.17' |   - &vlang_image 'git.rustybever.be/vieter/vlang:5d4c9dc9fc11bf8648541c934adb64f27cb94e37-alpine3.17' | ||||||
| 
 | 
 | ||||||
| # These checks already get performed on the feature branches | # These checks already get performed on the feature branches | ||||||
| branches: | branches: | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| variables: | variables: | ||||||
|   - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2-alpine3.17' |   - &vlang_image 'git.rustybever.be/vieter/vlang:5d4c9dc9fc11bf8648541c934adb64f27cb94e37-alpine3.17' | ||||||
| 
 | 
 | ||||||
| platform: 'linux/amd64' | platform: 'linux/amd64' | ||||||
| branches: | branches: | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| variables: | variables: | ||||||
|   - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2-alpine3.17' |   - &vlang_image 'git.rustybever.be/vieter/vlang:5d4c9dc9fc11bf8648541c934adb64f27cb94e37-alpine3.17' | ||||||
| 
 | 
 | ||||||
| matrix: | matrix: | ||||||
|   PLATFORM: |   PLATFORM: | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | ||||||
| ### Changed | ### Changed | ||||||
| 
 | 
 | ||||||
| * Rewrote cron expression logic in C | * Rewrote cron expression logic in C | ||||||
|  | * Updated codebase to V commit after 0.3.3 | ||||||
| 
 | 
 | ||||||
| ### Removed | ### Removed | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								Makefile
								
								
								
								
							|  | @ -3,7 +3,7 @@ SRC_DIR := src | ||||||
| SRCS != find '$(SRC_DIR)' -iname '*.v' | SRCS != find '$(SRC_DIR)' -iname '*.v' | ||||||
| 
 | 
 | ||||||
| V_PATH ?= v | V_PATH ?= v | ||||||
| V := $(V_PATH) -showcc -gc boehm -W -d use_openssl -skip-unused | V := $(V_PATH) -showcc -gc boehm -d use_openssl -skip-unused | ||||||
| 
 | 
 | ||||||
| all: vieter | all: vieter | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								PKGBUILD
								
								
								
								
							
							
						
						
									
										2
									
								
								PKGBUILD
								
								
								
								
							|  | @ -7,7 +7,7 @@ pkgver='0.5.0' | ||||||
| pkgrel=1 | pkgrel=1 | ||||||
| pkgdesc="Lightweight Arch repository server & package build system" | pkgdesc="Lightweight Arch repository server & package build system" | ||||||
| depends=('glibc' 'openssl' 'libarchive' 'sqlite') | depends=('glibc' 'openssl' 'libarchive' 'sqlite') | ||||||
| makedepends=('git' 'vlang') | makedepends=('git' 'vieter-vlang') | ||||||
| arch=('x86_64' 'aarch64') | arch=('x86_64' 'aarch64') | ||||||
| url='https://git.rustybever.be/vieter-v/vieter' | url='https://git.rustybever.be/vieter-v/vieter' | ||||||
| license=('AGPL3') | license=('AGPL3') | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ pkgver=0.2.0.r25.g20112b8 | ||||||
| pkgrel=1 | pkgrel=1 | ||||||
| pkgdesc="Lightweight Arch repository server & package build system (development version)" | pkgdesc="Lightweight Arch repository server & package build system (development version)" | ||||||
| depends=('glibc' 'openssl' 'libarchive' 'sqlite') | depends=('glibc' 'openssl' 'libarchive' 'sqlite') | ||||||
| makedepends=('git' 'vlang') | makedepends=('git' 'vieter-vlang') | ||||||
| arch=('x86_64' 'aarch64') | arch=('x86_64' 'aarch64') | ||||||
| url='https://git.rustybever.be/vieter-v/vieter' | url='https://git.rustybever.be/vieter-v/vieter' | ||||||
| license=('AGPL3') | license=('AGPL3') | ||||||
|  |  | ||||||
|  | @ -48,9 +48,9 @@ update`. | ||||||
| 
 | 
 | ||||||
| ### Compiler | ### Compiler | ||||||
| 
 | 
 | ||||||
| I used to maintain a mirror that tracked the latest master, but nowadays, I | V is developed using a specific compiler commit that is usually updated | ||||||
| maintain a Docker image containing the specific compiler version that Vieter | whenever a new version is released. Information on this can be found in the | ||||||
| builds with. Currently, this is V 0.3.2. | [tools](https://git.rustybever.be/vieter-v/tools) repository. | ||||||
| 
 | 
 | ||||||
| ## Contributing | ## Contributing | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,9 +23,9 @@ pub fn cmd() cli.Command { | ||||||
| 		description: 'Start an agent daemon.' | 		description: 'Start an agent daemon.' | ||||||
| 		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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 			conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 			agent(conf)! | 			agent(conf_)! | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ pub fn (mut d AgentDaemon) run() { | ||||||
| 
 | 
 | ||||||
| 	for { | 	for { | ||||||
| 		if sleep_time > 0 { | 		if sleep_time > 0 { | ||||||
| 			d.ldebug('Sleeping for $sleep_time') | 			d.ldebug('Sleeping for ${sleep_time}') | ||||||
| 			time.sleep(sleep_time) | 			time.sleep(sleep_time) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -80,14 +80,14 @@ pub fn (mut d AgentDaemon) run() { | ||||||
| 			d.ldebug('Polling for new jobs') | 			d.ldebug('Polling for new jobs') | ||||||
| 
 | 
 | ||||||
| 			new_configs := d.client.poll_jobs(d.conf.arch, finished + empty) or { | 			new_configs := d.client.poll_jobs(d.conf.arch, finished + empty) or { | ||||||
| 				d.lerror('Failed to poll jobs: $err.msg()') | 				d.lerror('Failed to poll jobs: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 				// TODO pick a better delay here | 				// TODO pick a better delay here | ||||||
| 				sleep_time = 5 * time.second | 				sleep_time = 5 * time.second | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			d.ldebug('Received $new_configs.len jobs') | 			d.ldebug('Received ${new_configs.len} jobs') | ||||||
| 
 | 
 | ||||||
| 			last_poll_time = time.now() | 			last_poll_time = time.now() | ||||||
| 
 | 
 | ||||||
|  | @ -95,7 +95,7 @@ pub fn (mut d AgentDaemon) run() { | ||||||
| 				// Make sure a recent build base image is available for | 				// Make sure a recent build base image is available for | ||||||
| 				// building the config | 				// building the config | ||||||
| 				if !d.images.up_to_date(config.base_image) { | 				if !d.images.up_to_date(config.base_image) { | ||||||
| 					d.linfo('Building builder image from base image $config.base_image') | 					d.linfo('Building builder image from base image ${config.base_image}') | ||||||
| 
 | 
 | ||||||
| 					// TODO handle this better than to just skip the config | 					// TODO handle this better than to just skip the config | ||||||
| 					d.images.refresh_image(config.base_image) or { | 					d.images.refresh_image(config.base_image) or { | ||||||
|  | @ -154,7 +154,7 @@ fn (mut d AgentDaemon) start_build(config BuildConfig) bool { | ||||||
| 			stdatomic.store_u64(&d.atomics[i], agent.build_running) | 			stdatomic.store_u64(&d.atomics[i], agent.build_running) | ||||||
| 			d.builds[i] = config | 			d.builds[i] = config | ||||||
| 
 | 
 | ||||||
| 			go d.run_build(i, config) | 			spawn d.run_build(i, config) | ||||||
| 
 | 
 | ||||||
| 			return true | 			return true | ||||||
| 		} | 		} | ||||||
|  | @ -165,7 +165,7 @@ fn (mut d AgentDaemon) start_build(config BuildConfig) bool { | ||||||
| 
 | 
 | ||||||
| // run_build actually starts the build process for a given target. | // run_build actually starts the build process for a given target. | ||||||
| fn (mut d AgentDaemon) run_build(build_index int, config BuildConfig) { | fn (mut d AgentDaemon) run_build(build_index int, config BuildConfig) { | ||||||
| 	d.linfo('started build: $config') | 	d.linfo('started build: ${config}') | ||||||
| 
 | 
 | ||||||
| 	// 0 means success, 1 means failure | 	// 0 means success, 1 means failure | ||||||
| 	mut status := 0 | 	mut status := 0 | ||||||
|  | @ -176,21 +176,21 @@ fn (mut d AgentDaemon) run_build(build_index int, config BuildConfig) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	res := build.build_config(d.client.address, d.client.api_key, new_config) or { | 	res := build.build_config(d.client.address, d.client.api_key, new_config) or { | ||||||
| 		d.ldebug('build_config error: $err.msg()') | 		d.ldebug('build_config error: ${err.msg()}') | ||||||
| 		status = 1 | 		status = 1 | ||||||
| 
 | 
 | ||||||
| 		build.BuildResult{} | 		build.BuildResult{} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if status == 0 { | 	if status == 0 { | ||||||
| 		d.linfo('Uploading build logs for $config') | 		d.linfo('Uploading build logs for ${config}') | ||||||
| 
 | 
 | ||||||
| 		// TODO use the arch value here | 		// TODO use the arch value here | ||||||
| 		build_arch := os.uname().machine | 		build_arch := os.uname().machine | ||||||
| 		d.client.add_build_log(config.target_id, res.start_time, res.end_time, build_arch, | 		d.client.add_build_log(config.target_id, res.start_time, res.end_time, build_arch, | ||||||
| 			res.exit_code, res.logs) or { d.lerror('Failed to upload logs for $config') } | 			res.exit_code, res.logs) or { d.lerror('Failed to upload logs for ${config}') } | ||||||
| 	} else { | 	} else { | ||||||
| 		d.lwarn('an error occurred during build: $config') | 		d.lwarn('an error occurred during build: ${config}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	stdatomic.store_u64(&d.atomics[build_index], agent.build_done) | 	stdatomic.store_u64(&d.atomics[build_index], agent.build_done) | ||||||
|  |  | ||||||
|  | @ -71,7 +71,7 @@ pub fn (mut m ImageManager) up_to_date(base_image string) bool { | ||||||
| fn (mut m ImageManager) refresh_image(base_image string) ! { | fn (mut m ImageManager) refresh_image(base_image string) ! { | ||||||
| 	// TODO use better image tags for built images | 	// TODO use better image tags for built images | ||||||
| 	new_image := build.create_build_image(base_image) or { | 	new_image := build.create_build_image(base_image) or { | ||||||
| 		return error('Failed to build builder image from base image $base_image') | 		return error('Failed to build builder image from base image ${base_image}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	m.images[base_image] << new_image | 	m.images[base_image] << new_image | ||||||
|  |  | ||||||
|  | @ -45,7 +45,7 @@ pub fn create_build_image(base_image string) !string { | ||||||
| 
 | 
 | ||||||
| 	c := docker.NewContainer{ | 	c := docker.NewContainer{ | ||||||
| 		image: base_image | 		image: base_image | ||||||
| 		env: ['BUILD_SCRIPT=$cmds_str'] | 		env: ['BUILD_SCRIPT=${cmds_str}'] | ||||||
| 		entrypoint: ['/bin/sh', '-c'] | 		entrypoint: ['/bin/sh', '-c'] | ||||||
| 		cmd: ['echo \$BUILD_SCRIPT | base64 -d | /bin/sh -e'] | 		cmd: ['echo \$BUILD_SCRIPT | base64 -d | /bin/sh -e'] | ||||||
| 	} | 	} | ||||||
|  | @ -118,10 +118,10 @@ pub fn build_config(address string, api_key string, config BuildConfig) !BuildRe | ||||||
| 	base64_script := base64.encode_str(build_script) | 	base64_script := base64.encode_str(build_script) | ||||||
| 
 | 
 | ||||||
| 	c := docker.NewContainer{ | 	c := docker.NewContainer{ | ||||||
| 		image: '$config.base_image' | 		image: '${config.base_image}' | ||||||
| 		env: [ | 		env: [ | ||||||
| 			'BUILD_SCRIPT=$base64_script', | 			'BUILD_SCRIPT=${base64_script}', | ||||||
| 			'API_KEY=$api_key', | 			'API_KEY=${api_key}', | ||||||
| 			// `archlinux:base-devel` does not correctly set the path variable, | 			// `archlinux:base-devel` does not correctly set the path variable, | ||||||
| 			// causing certain builds to fail. This fixes it. | 			// causing certain builds to fail. This fixes it. | ||||||
| 			'PATH=${build.path_dirs.join(':')}', | 			'PATH=${build.path_dirs.join(':')}', | ||||||
|  |  | ||||||
|  | @ -36,7 +36,7 @@ pub struct BuildJobQueue { | ||||||
| mut: | mut: | ||||||
| 	mutex shared util.Dummy | 	mutex shared util.Dummy | ||||||
| 	// For each architecture, a priority queue is tracked | 	// For each architecture, a priority queue is tracked | ||||||
| 	queues map[string]MinHeap<BuildJob> | 	queues map[string]MinHeap[BuildJob] | ||||||
| 	// When a target is removed from the server or edited, its previous build | 	// When a target is removed from the server or edited, its previous build | ||||||
| 	// configs will be invalid. This map allows for those to be simply skipped | 	// configs will be invalid. This map allows for those to be simply skipped | ||||||
| 	// by ignoring any build configs created before this timestamp. | 	// by ignoring any build configs created before this timestamp. | ||||||
|  | @ -74,7 +74,7 @@ pub struct InsertConfig { | ||||||
| pub fn (mut q BuildJobQueue) insert(input InsertConfig) ! { | pub fn (mut q BuildJobQueue) insert(input InsertConfig) ! { | ||||||
| 	lock q.mutex { | 	lock q.mutex { | ||||||
| 		if input.arch !in q.queues { | 		if input.arch !in q.queues { | ||||||
| 			q.queues[input.arch] = MinHeap<BuildJob>{} | 			q.queues[input.arch] = MinHeap[BuildJob]{} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		mut job := BuildJob{ | 		mut job := BuildJob{ | ||||||
|  | @ -86,7 +86,7 @@ pub fn (mut q BuildJobQueue) insert(input InsertConfig) ! { | ||||||
| 		if !input.now { | 		if !input.now { | ||||||
| 			ce := if input.target.schedule != '' { | 			ce := if input.target.schedule != '' { | ||||||
| 				cron.parse_expression(input.target.schedule) or { | 				cron.parse_expression(input.target.schedule) or { | ||||||
| 					return error("Error while parsing cron expression '$input.target.schedule' (id $input.target.id): $err.msg()") | 					return error("Error while parsing cron expression '${input.target.schedule}' (id ${input.target.id}): ${err.msg()}") | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				q.default_schedule | 				q.default_schedule | ||||||
|  | @ -143,7 +143,7 @@ pub fn (mut q BuildJobQueue) peek(arch string) ?BuildJob { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		q.pop_invalid(arch) | 		q.pop_invalid(arch) | ||||||
| 		job := q.queues[arch].peek()? | 		job := q.queues[arch].peek() or { return none } | ||||||
| 
 | 
 | ||||||
| 		if job.timestamp < time.now() { | 		if job.timestamp < time.now() { | ||||||
| 			return job | 			return job | ||||||
|  | @ -162,10 +162,10 @@ pub fn (mut q BuildJobQueue) pop(arch string) ?BuildJob { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		q.pop_invalid(arch) | 		q.pop_invalid(arch) | ||||||
| 		mut job := q.queues[arch].peek()? | 		mut job := q.queues[arch].peek() or { return none } | ||||||
| 
 | 
 | ||||||
| 		if job.timestamp < time.now() { | 		if job.timestamp < time.now() { | ||||||
| 			job = q.queues[arch].pop()? | 			job = q.queues[arch].pop() or { return none } | ||||||
| 
 | 
 | ||||||
| 			if !job.single { | 			if !job.single { | ||||||
| 				q.reschedule(job, arch) | 				q.reschedule(job, arch) | ||||||
|  |  | ||||||
|  | @ -24,12 +24,12 @@ pub fn echo_commands(cmds []string) []string { | ||||||
| 
 | 
 | ||||||
| // create_build_script generates a shell script that builds a given Target. | // create_build_script generates a shell script that builds a given Target. | ||||||
| fn create_build_script(address string, config BuildConfig, build_arch string) string { | fn create_build_script(address string, config BuildConfig, build_arch string) string { | ||||||
| 	repo_url := '$address/$config.repo' | 	repo_url := '${address}/${config.repo}' | ||||||
| 
 | 
 | ||||||
| 	mut commands := [ | 	mut commands := [ | ||||||
| 		// This will later be replaced by a proper setting for changing the | 		// This will later be replaced by a proper setting for changing the | ||||||
| 		// mirrorlist | 		// mirrorlist | ||||||
| 		"echo -e '[$config.repo]\\nServer = $address/\$repo/\$arch\\nSigLevel = Optional' >> /etc/pacman.conf" | 		"echo -e '[${config.repo}]\\nServer = ${address}/\$repo/\$arch\\nSigLevel = Optional' >> /etc/pacman.conf" | ||||||
| 		// We need to update the package list of the repo we just added above. | 		// We need to update the package list of the repo we just added above. | ||||||
| 		// This should however not pull in a lot of packages as long as the | 		// This should however not pull in a lot of packages as long as the | ||||||
| 		// builder image is rebuilt frequently. | 		// builder image is rebuilt frequently. | ||||||
|  | @ -42,18 +42,18 @@ fn create_build_script(address string, config BuildConfig, build_arch string) st | ||||||
| 		'git' { | 		'git' { | ||||||
| 			if config.branch == '' { | 			if config.branch == '' { | ||||||
| 				[ | 				[ | ||||||
| 					"git clone --single-branch --depth 1 '$config.url' repo", | 					"git clone --single-branch --depth 1 '${config.url}' repo", | ||||||
| 				] | 				] | ||||||
| 			} else { | 			} else { | ||||||
| 				[ | 				[ | ||||||
| 					"git clone --single-branch --depth 1 --branch $config.branch '$config.url' repo", | 					"git clone --single-branch --depth 1 --branch ${config.branch} '${config.url}' repo", | ||||||
| 				] | 				] | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		'url' { | 		'url' { | ||||||
| 			[ | 			[ | ||||||
| 				'mkdir repo', | 				'mkdir repo', | ||||||
| 				"curl -o repo/PKGBUILD -L '$config.url'", | 				"curl -o repo/PKGBUILD -L '${config.url}'", | ||||||
| 			] | 			] | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
|  | @ -62,7 +62,7 @@ fn create_build_script(address string, config BuildConfig, build_arch string) st | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	commands << if config.path != '' { | 	commands << if config.path != '' { | ||||||
| 		"cd 'repo/$config.path'" | 		"cd 'repo/${config.path}'" | ||||||
| 	} else { | 	} else { | ||||||
| 		'cd repo' | 		'cd repo' | ||||||
| 	} | 	} | ||||||
|  | @ -76,7 +76,7 @@ fn create_build_script(address string, config BuildConfig, build_arch string) st | ||||||
| 		// The build container checks whether the package is already present on | 		// The build container checks whether the package is already present on | ||||||
| 		// the server. | 		// the server. | ||||||
| 		commands << [ | 		commands << [ | ||||||
| 			'curl -s --head --fail $repo_url/$build_arch/\$pkgname-\$pkgver-\$pkgrel && exit 0', | 			'curl -s --head --fail ${repo_url}/${build_arch}/\$pkgname-\$pkgver-\$pkgrel && exit 0', | ||||||
| 			// If the above curl command succeeds, we don't need to rebuild the | 			// If the above curl command succeeds, we don't need to rebuild the | ||||||
| 			// package. However, because we're in a su shell, the exit command will | 			// package. However, because we're in a su shell, the exit command will | ||||||
| 			// drop us back into the root shell. Therefore, we must check whether | 			// drop us back into the root shell. Therefore, we must check whether | ||||||
|  | @ -86,7 +86,7 @@ fn create_build_script(address string, config BuildConfig, build_arch string) st | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	commands << [ | 	commands << [ | ||||||
| 		'MAKEFLAGS="-j\$(nproc)" makepkg -s --noconfirm --needed --noextract && for pkg in \$(ls -1 *.pkg*); do curl -XPOST -T "\$pkg" -H "X-API-KEY: \$API_KEY" $repo_url/publish; done', | 		'MAKEFLAGS="-j\$(nproc)" makepkg -s --noconfirm --needed --noextract && for pkg in \$(ls -1 *.pkg*); do curl -XPOST -T "\$pkg" -H "X-API-KEY: \$API_KEY" ${repo_url}/publish; done', | ||||||
| 	] | 	] | ||||||
| 
 | 
 | ||||||
| 	return echo_commands(commands).join('\n') | 	return echo_commands(commands).join('\n') | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ pub fn new(address string, api_key string) Client { | ||||||
| // send_request_raw sends an HTTP request, returning the http.Response object. | // send_request_raw sends an HTTP request, returning the http.Response object. | ||||||
| // It encodes the params so that they're safe to pass as HTTP query parameters. | // It encodes the params so that they're safe to pass as HTTP query parameters. | ||||||
| fn (c &Client) send_request_raw(method Method, url string, params map[string]string, body string) !http.Response { | fn (c &Client) send_request_raw(method Method, url string, params map[string]string, body string) !http.Response { | ||||||
| 	mut full_url := '$c.address$url' | 	mut full_url := '${c.address}${url}' | ||||||
| 
 | 
 | ||||||
| 	if params.len > 0 { | 	if params.len > 0 { | ||||||
| 		mut params_escaped := map[string]string{} | 		mut params_escaped := map[string]string{} | ||||||
|  | @ -33,9 +33,9 @@ fn (c &Client) send_request_raw(method Method, url string, params map[string]str | ||||||
| 			params_escaped[k] = urllib.query_escape(v) | 			params_escaped[k] = urllib.query_escape(v) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		params_str := params_escaped.keys().map('$it=${params_escaped[it]}').join('&') | 		params_str := params_escaped.keys().map('${it}=${params_escaped[it]}').join('&') | ||||||
| 
 | 
 | ||||||
| 		full_url = '$full_url?$params_str' | 		full_url = '${full_url}?${params_str}' | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Looking at the source code, this function doesn't actually fail, so I'm | 	// Looking at the source code, this function doesn't actually fail, so I'm | ||||||
|  | @ -49,13 +49,13 @@ fn (c &Client) send_request_raw(method Method, url string, params map[string]str | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // send_request<T> just calls send_request_with_body<T> with an empty body. | // send_request<T> just calls send_request_with_body<T> with an empty body. | ||||||
| fn (c &Client) send_request<T>(method Method, url string, params map[string]string) !Response<T> { | fn (c &Client) send_request[T](method Method, url string, params map[string]string) !Response[T] { | ||||||
| 	return c.send_request_with_body<T>(method, url, params, '') | 	return c.send_request_with_body[T](method, url, params, '') | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // send_request_with_body<T> calls send_request_raw_response & parses its | // send_request_with_body<T> calls send_request_raw_response & parses its | ||||||
| // output as a Response<T> object. | // output as a Response<T> object. | ||||||
| fn (c &Client) send_request_with_body<T>(method Method, url string, params map[string]string, body string) !Response<T> { | fn (c &Client) send_request_with_body[T](method Method, url string, params map[string]string, body string) !Response[T] { | ||||||
| 	res := c.send_request_raw(method, url, params, body)! | 	res := c.send_request_raw(method, url, params, body)! | ||||||
| 	status := res.status() | 	status := res.status() | ||||||
| 
 | 
 | ||||||
|  | @ -64,12 +64,12 @@ fn (c &Client) send_request_with_body<T>(method Method, url string, params map[s | ||||||
| 	if status.is_error() { | 	if status.is_error() { | ||||||
| 		// A non-successful status call will have an empty body | 		// A non-successful status call will have an empty body | ||||||
| 		if res.body == '' { | 		if res.body == '' { | ||||||
| 			return error('Error $res.status_code ($status.str()): (empty response)') | 			return error('Error ${res.status_code} (${status.str()}): (empty response)') | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		data := json.decode(Response<string>, res.body)! | 		data := json.decode(Response[string], res.body)! | ||||||
| 
 | 
 | ||||||
| 		return error('Status $res.status_code ($status.str()): $data.message') | 		return error('Status ${res.status_code} (${status.str()}): ${data.message}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Just return an empty successful response | 	// Just return an empty successful response | ||||||
|  | @ -77,7 +77,7 @@ fn (c &Client) send_request_with_body<T>(method Method, url string, params map[s | ||||||
| 		return new_data_response(T{}) | 		return new_data_response(T{}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	data := json.decode(Response<T>, res.body)! | 	data := json.decode(Response[T], res.body)! | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import models { BuildConfig } | ||||||
| 
 | 
 | ||||||
| // poll_jobs requests a list of new build jobs from the server. | // poll_jobs requests a list of new build jobs from the server. | ||||||
| pub fn (c &Client) poll_jobs(arch string, max int) ![]BuildConfig { | pub fn (c &Client) poll_jobs(arch string, max int) ![]BuildConfig { | ||||||
| 	data := c.send_request<[]BuildConfig>(.get, '/api/v1/jobs/poll', { | 	data := c.send_request[[]BuildConfig](.get, '/api/v1/jobs/poll', { | ||||||
| 		'arch': arch | 		'arch': arch | ||||||
| 		'max':  max.str() | 		'max':  max.str() | ||||||
| 	})! | 	})! | ||||||
|  | @ -15,7 +15,7 @@ pub fn (c &Client) poll_jobs(arch string, max int) ![]BuildConfig { | ||||||
| // queue_job adds a new one-time build job for the given target to the job | // queue_job adds a new one-time build job for the given target to the job | ||||||
| // queue. | // queue. | ||||||
| pub fn (c &Client) queue_job(target_id int, arch string, force bool) ! { | pub fn (c &Client) queue_job(target_id int, arch string, force bool) ! { | ||||||
| 	c.send_request<string>(.post, '/api/v1/jobs/queue', { | 	c.send_request[string](.post, '/api/v1/jobs/queue', { | ||||||
| 		'target': target_id.str() | 		'target': target_id.str() | ||||||
| 		'arch':   arch | 		'arch':   arch | ||||||
| 		'force':  force.str() | 		'force':  force.str() | ||||||
|  |  | ||||||
|  | @ -7,27 +7,27 @@ import time | ||||||
| // get_build_logs returns all build logs. | // get_build_logs returns all build logs. | ||||||
| pub fn (c &Client) get_build_logs(filter BuildLogFilter) ![]BuildLog { | pub fn (c &Client) get_build_logs(filter BuildLogFilter) ![]BuildLog { | ||||||
| 	params := models.params_from(filter) | 	params := models.params_from(filter) | ||||||
| 	data := c.send_request<[]BuildLog>(.get, '/api/v1/logs', params)! | 	data := c.send_request[[]BuildLog](.get, '/api/v1/logs', params)! | ||||||
| 
 | 
 | ||||||
| 	return data.data | 	return data.data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // get_build_log returns a specific build log. | // get_build_log returns a specific build log. | ||||||
| pub fn (c &Client) get_build_log(id int) !BuildLog { | pub fn (c &Client) get_build_log(id int) !BuildLog { | ||||||
| 	data := c.send_request<BuildLog>(.get, '/api/v1/logs/$id', {})! | 	data := c.send_request[BuildLog](.get, '/api/v1/logs/${id}', {})! | ||||||
| 
 | 
 | ||||||
| 	return data.data | 	return data.data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // get_build_log_content returns the contents of the build log file. | // get_build_log_content returns the contents of the build log file. | ||||||
| pub fn (c &Client) get_build_log_content(id int) !string { | pub fn (c &Client) get_build_log_content(id int) !string { | ||||||
| 	data := c.send_request_raw_response(.get, '/api/v1/logs/$id/content', {}, '')! | 	data := c.send_request_raw_response(.get, '/api/v1/logs/${id}/content', {}, '')! | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // add_build_log adds a new build log to the server. | // add_build_log adds a new build log to the server. | ||||||
| pub fn (c &Client) add_build_log(target_id int, start_time time.Time, end_time time.Time, arch string, exit_code int, content string) !Response<int> { | pub fn (c &Client) add_build_log(target_id int, start_time time.Time, end_time time.Time, arch string, exit_code int, content string) !Response[int] { | ||||||
| 	params := { | 	params := { | ||||||
| 		'target':    target_id.str() | 		'target':    target_id.str() | ||||||
| 		'startTime': start_time.unix_time().str() | 		'startTime': start_time.unix_time().str() | ||||||
|  | @ -36,12 +36,12 @@ pub fn (c &Client) add_build_log(target_id int, start_time time.Time, end_time t | ||||||
| 		'exitCode':  exit_code.str() | 		'exitCode':  exit_code.str() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	data := c.send_request_with_body<int>(.post, '/api/v1/logs', params, content)! | 	data := c.send_request_with_body[int](.post, '/api/v1/logs', params, content)! | ||||||
| 
 | 
 | ||||||
| 	return data | 	return data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // remove_build_log removes the build log with the given id from the server. | // remove_build_log removes the build log with the given id from the server. | ||||||
| pub fn (c &Client) remove_build_log(id int) ! { | pub fn (c &Client) remove_build_log(id int) ! { | ||||||
| 	c.send_request<string>(.delete, '/api/v1/logs/$id', {})! | 	c.send_request[string](.delete, '/api/v1/logs/${id}', {})! | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,15 +2,15 @@ module client | ||||||
| 
 | 
 | ||||||
| // remove_repo removes an entire repository. | // remove_repo removes an entire repository. | ||||||
| pub fn (c &Client) remove_repo(repo string) ! { | pub fn (c &Client) remove_repo(repo string) ! { | ||||||
| 	c.send_request<string>(.delete, '/$repo', {})! | 	c.send_request[string](.delete, '/${repo}', {})! | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // remove_arch_repo removes an entire arch-repo. | // remove_arch_repo removes an entire arch-repo. | ||||||
| pub fn (c &Client) remove_arch_repo(repo string, arch string) ! { | pub fn (c &Client) remove_arch_repo(repo string, arch string) ! { | ||||||
| 	c.send_request<string>(.delete, '/$repo/$arch', {})! | 	c.send_request[string](.delete, '/${repo}/${arch}', {})! | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // remove_package removes a single package from the given arch-repo. | // remove_package removes a single package from the given arch-repo. | ||||||
| pub fn (c &Client) remove_package(repo string, arch string, pkgname string) ! { | pub fn (c &Client) remove_package(repo string, arch string, pkgname string) ! { | ||||||
| 	c.send_request<string>(.delete, '/$repo/$arch/$pkgname', {})! | 	c.send_request[string](.delete, '/${repo}/${arch}/${pkgname}', {})! | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import models { Target, TargetFilter } | ||||||
| // get_targets returns a list of targets, given a filter object. | // get_targets returns a list of targets, given a filter object. | ||||||
| pub fn (c &Client) get_targets(filter TargetFilter) ![]Target { | pub fn (c &Client) get_targets(filter TargetFilter) ![]Target { | ||||||
| 	params := models.params_from(filter) | 	params := models.params_from(filter) | ||||||
| 	data := c.send_request<[]Target>(.get, '/api/v1/targets', params)! | 	data := c.send_request[[]Target](.get, '/api/v1/targets', params)! | ||||||
| 
 | 
 | ||||||
| 	return data.data | 	return data.data | ||||||
| } | } | ||||||
|  | @ -33,7 +33,7 @@ pub fn (c &Client) get_all_targets() ![]Target { | ||||||
| 
 | 
 | ||||||
| // get_target returns the target for a specific id. | // get_target returns the target for a specific id. | ||||||
| pub fn (c &Client) get_target(id int) !Target { | pub fn (c &Client) get_target(id int) !Target { | ||||||
| 	data := c.send_request<Target>(.get, '/api/v1/targets/$id', {})! | 	data := c.send_request[Target](.get, '/api/v1/targets/${id}', {})! | ||||||
| 
 | 
 | ||||||
| 	return data.data | 	return data.data | ||||||
| } | } | ||||||
|  | @ -49,15 +49,15 @@ pub struct NewTarget { | ||||||
| 
 | 
 | ||||||
| // add_target adds a new target to the server. | // add_target adds a new target to the server. | ||||||
| pub fn (c &Client) add_target(t NewTarget) !int { | pub fn (c &Client) add_target(t NewTarget) !int { | ||||||
| 	params := models.params_from<NewTarget>(t) | 	params := models.params_from[NewTarget](t) | ||||||
| 	data := c.send_request<int>(.post, '/api/v1/targets', params)! | 	data := c.send_request[int](.post, '/api/v1/targets', params)! | ||||||
| 
 | 
 | ||||||
| 	return data.data | 	return data.data | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // remove_target removes the target with the given id from the server. | // remove_target removes the target with the given id from the server. | ||||||
| pub fn (c &Client) remove_target(id int) !string { | pub fn (c &Client) remove_target(id int) !string { | ||||||
| 	data := c.send_request<string>(.delete, '/api/v1/targets/$id', {})! | 	data := c.send_request[string](.delete, '/api/v1/targets/${id}', {})! | ||||||
| 
 | 
 | ||||||
| 	return data.data | 	return data.data | ||||||
| } | } | ||||||
|  | @ -65,7 +65,7 @@ pub fn (c &Client) remove_target(id int) !string { | ||||||
| // patch_target sends a PATCH request to the given target with the params as | // patch_target sends a PATCH request to the given target with the params as | ||||||
| // payload. | // payload. | ||||||
| pub fn (c &Client) patch_target(id int, params map[string]string) !string { | pub fn (c &Client) patch_target(id int, params map[string]string) !string { | ||||||
| 	data := c.send_request<string>(.patch, '/api/v1/targets/$id', params)! | 	data := c.send_request[string](.patch, '/api/v1/targets/${id}', params)! | ||||||
| 
 | 
 | ||||||
| 	return data.data | 	return data.data | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -36,24 +36,24 @@ pub fn cmd() cli.Command { | ||||||
| 				required_args: 2 | 				required_args: 2 | ||||||
| 				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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					c := aur.new() | 					c := aur.new() | ||||||
| 					pkgs := c.info(cmd.args[1..])! | 					pkgs := c.info(cmd.args[1..])! | ||||||
| 
 | 
 | ||||||
| 					vc := client.new(conf.address, conf.api_key) | 					vc := client.new(conf_.address, conf_.api_key) | ||||||
| 
 | 
 | ||||||
| 					for pkg in pkgs { | 					for pkg in pkgs { | ||||||
| 						vc.add_target( | 						vc.add_target( | ||||||
| 							kind: 'git' | 							kind: 'git' | ||||||
| 							url: 'https://aur.archlinux.org/$pkg.package_base' + '.git' | 							url: 'https://aur.archlinux.org/${pkg.package_base}' + '.git' | ||||||
| 							repo: cmd.args[0] | 							repo: cmd.args[0] | ||||||
| 						) or { | 						) or { | ||||||
| 							println('Failed to add $pkg.name: $err.msg()') | 							println('Failed to add ${pkg.name}: ${err.msg()}') | ||||||
| 							continue | 							continue | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
| 						println('Added $pkg.name' + '.') | 						println('Added ${pkg.name}' + '.') | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
|  | @ -74,7 +74,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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					mut filter := BuildLogFilter{} | 					mut filter := BuildLogFilter{} | ||||||
| 
 | 
 | ||||||
|  | @ -146,7 +146,7 @@ pub fn cmd() cli.Command { | ||||||
| 
 | 
 | ||||||
| 					raw := cmd.flags.get_bool('raw')! | 					raw := cmd.flags.get_bool('raw')! | ||||||
| 
 | 
 | ||||||
| 					list(conf, filter, raw)! | 					list(conf_, filter, raw)! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -156,9 +156,9 @@ pub fn cmd() cli.Command { | ||||||
| 				description: 'Remove a build log that matches the given id.' | 				description: 'Remove a build log that matches the given id.' | ||||||
| 				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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					remove(conf, cmd.args[0])! | 					remove(conf_, cmd.args[0])! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -168,10 +168,10 @@ 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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					id := cmd.args[0].int() | 					id := cmd.args[0].int() | ||||||
| 					info(conf, id)! | 					info(conf_, id)! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -181,10 +181,10 @@ 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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					id := cmd.args[0].int() | 					id := cmd.args[0].int() | ||||||
| 					content(conf, id)! | 					content(conf_, id)! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 		] | 		] | ||||||
|  | @ -204,16 +204,16 @@ fn print_log_list(logs []BuildLog, raw bool) ! { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // list prints a list of all build logs. | // list prints a list of all build logs. | ||||||
| fn list(conf Config, filter BuildLogFilter, raw bool) ! { | fn list(conf_ Config, filter BuildLogFilter, raw bool) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	logs := c.get_build_logs(filter)! | 	logs := c.get_build_logs(filter)! | ||||||
| 
 | 
 | ||||||
| 	print_log_list(logs, raw)! | 	print_log_list(logs, raw)! | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // info print the detailed info for a given build log. | // info print the detailed info for a given build log. | ||||||
| fn info(conf Config, id int) ! { | fn info(conf_ Config, id int) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	log := c.get_build_log(id)! | 	log := c.get_build_log(id)! | ||||||
| 
 | 
 | ||||||
| 	print(log) | 	print(log) | ||||||
|  | @ -221,15 +221,15 @@ fn info(conf Config, id int) ! { | ||||||
| 
 | 
 | ||||||
| // content outputs the contents of the log file for a given build log to | // content outputs the contents of the log file for a given build log to | ||||||
| // stdout. | // stdout. | ||||||
| fn content(conf Config, id int) ! { | fn content(conf_ Config, id int) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	content := c.get_build_log_content(id)! | 	content := c.get_build_log_content(id)! | ||||||
| 
 | 
 | ||||||
| 	println(content) | 	println(content) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // remove removes a build log from the server's list. | // remove removes a build log from the server's list. | ||||||
| fn remove(conf Config, id string) ! { | fn remove(conf_ Config, id string) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	c.remove_build_log(id.int())! | 	c.remove_build_log(id.int())! | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -28,7 +28,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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					if cmd.args.len < 3 { | 					if cmd.args.len < 3 { | ||||||
| 						if !cmd.flags.get_bool('force')! { | 						if !cmd.flags.get_bool('force')! { | ||||||
|  | @ -36,14 +36,14 @@ pub fn cmd() cli.Command { | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					client := client.new(conf.address, conf.api_key) | 					client_ := client.new(conf_.address, conf_.api_key) | ||||||
| 
 | 
 | ||||||
| 					if cmd.args.len == 1 { | 					if cmd.args.len == 1 { | ||||||
| 						client.remove_repo(cmd.args[0])! | 						client_.remove_repo(cmd.args[0])! | ||||||
| 					} else if cmd.args.len == 2 { | 					} else if cmd.args.len == 2 { | ||||||
| 						client.remove_arch_repo(cmd.args[0], cmd.args[1])! | 						client_.remove_arch_repo(cmd.args[0], cmd.args[1])! | ||||||
| 					} else { | 					} else { | ||||||
| 						client.remove_package(cmd.args[0], cmd.args[1], cmd.args[2])! | 						client_.remove_package(cmd.args[0], cmd.args[1], cmd.args[2])! | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ import os | ||||||
| import build | import build | ||||||
| 
 | 
 | ||||||
| // build locally builds the target with the given id. | // build locally builds the target with the given id. | ||||||
| fn build(conf Config, target_id int, force bool) ! { | fn build_target(conf Config, target_id int, force bool) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf.address, conf.api_key) | ||||||
| 	target := c.get_target(target_id)! | 	target := c.get_target(target_id)! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -54,7 +54,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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					mut filter := TargetFilter{} | 					mut filter := TargetFilter{} | ||||||
| 
 | 
 | ||||||
|  | @ -85,7 +85,7 @@ pub fn cmd() cli.Command { | ||||||
| 
 | 
 | ||||||
| 					raw := cmd.flags.get_bool('raw')! | 					raw := cmd.flags.get_bool('raw')! | ||||||
| 
 | 
 | ||||||
| 					list(conf, filter, raw)! | 					list(conf_, filter, raw)! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -113,7 +113,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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					t := NewTarget{ | 					t := NewTarget{ | ||||||
| 						kind: cmd.flags.get_string('kind')! | 						kind: cmd.flags.get_string('kind')! | ||||||
|  | @ -125,7 +125,7 @@ pub fn cmd() cli.Command { | ||||||
| 
 | 
 | ||||||
| 					raw := cmd.flags.get_bool('raw')! | 					raw := cmd.flags.get_bool('raw')! | ||||||
| 
 | 
 | ||||||
| 					add(conf, t, raw)! | 					add(conf_, t, raw)! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -135,9 +135,9 @@ pub fn cmd() cli.Command { | ||||||
| 				description: 'Remove a target that matches the given id.' | 				description: 'Remove a target that matches the given id.' | ||||||
| 				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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					remove(conf, cmd.args[0])! | 					remove(conf_, cmd.args[0])! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -147,9 +147,9 @@ pub fn cmd() cli.Command { | ||||||
| 				description: 'Show detailed information for the target matching the id.' | 				description: 'Show detailed information for the target matching the id.' | ||||||
| 				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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					info(conf, cmd.args[0])! | 					info(conf_, cmd.args[0])! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -196,7 +196,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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					found := cmd.flags.get_all_found() | 					found := cmd.flags.get_all_found() | ||||||
| 
 | 
 | ||||||
|  | @ -208,7 +208,7 @@ pub fn cmd() cli.Command { | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					patch(conf, cmd.args[0], params)! | 					patch(conf_, cmd.args[0], params)! | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
| 			cli.Command{ | 			cli.Command{ | ||||||
|  | @ -235,7 +235,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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 					conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 					remote := cmd.flags.get_bool('remote')! | 					remote := cmd.flags.get_bool('remote')! | ||||||
| 					force := cmd.flags.get_bool('force')! | 					force := cmd.flags.get_bool('force')! | ||||||
|  | @ -248,10 +248,10 @@ pub fn cmd() cli.Command { | ||||||
| 							return error('When scheduling the build remotely, you have to specify an architecture.') | 							return error('When scheduling the build remotely, you have to specify an architecture.') | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
| 						c := client.new(conf.address, conf.api_key) | 						c := client.new(conf_.address, conf_.api_key) | ||||||
| 						c.queue_job(target_id, arch, force)! | 						c.queue_job(target_id, arch, force)! | ||||||
| 					} else { | 					} else { | ||||||
| 						build(conf, target_id, force)! | 						build_target(conf_, target_id, force)! | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
|  | @ -260,8 +260,8 @@ pub fn cmd() cli.Command { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // list prints out a list of all repositories. | // list prints out a list of all repositories. | ||||||
| fn list(conf Config, filter TargetFilter, raw bool) ! { | fn list(conf_ Config, filter TargetFilter, raw bool) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	targets := c.get_targets(filter)! | 	targets := c.get_targets(filter)! | ||||||
| 	data := targets.map([it.id.str(), it.kind, it.url, it.repo]) | 	data := targets.map([it.id.str(), it.kind, it.url, it.repo]) | ||||||
| 
 | 
 | ||||||
|  | @ -273,40 +273,40 @@ fn list(conf Config, filter TargetFilter, raw bool) ! { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // add adds a new target to the server's list. | // add adds a new target to the server's list. | ||||||
| fn add(conf Config, t &NewTarget, raw bool) ! { | fn add(conf_ Config, t &NewTarget, raw bool) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	target_id := c.add_target(t)! | 	target_id := c.add_target(t)! | ||||||
| 
 | 
 | ||||||
| 	if raw { | 	if raw { | ||||||
| 		println(target_id) | 		println(target_id) | ||||||
| 	} else { | 	} else { | ||||||
| 		println('Target added with id $target_id') | 		println('Target added with id ${target_id}') | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // remove removes a target from the server's list. | // remove removes a target from the server's list. | ||||||
| fn remove(conf Config, id string) ! { | fn remove(conf_ Config, id string) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	c.remove_target(id.int())! | 	c.remove_target(id.int())! | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // patch patches a given target with the provided params. | // patch patches a given target with the provided params. | ||||||
| fn patch(conf Config, id string, params map[string]string) ! { | fn patch(conf_ Config, id string, params map[string]string) ! { | ||||||
| 	// We check the cron expression first because it's useless to send an | 	// We check the cron expression first because it's useless to send an | ||||||
| 	// invalid one to the server. | 	// invalid one to the server. | ||||||
| 	if 'schedule' in params && params['schedule'] != '' { | 	if 'schedule' in params && params['schedule'] != '' { | ||||||
| 		cron.parse_expression(params['schedule']) or { | 		cron.parse_expression(params['schedule']) or { | ||||||
| 			return error('Invalid cron expression: $err.msg()') | 			return error('Invalid cron expression: ${err.msg()}') | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	c.patch_target(id.int(), params)! | 	c.patch_target(id.int(), params)! | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // info shows detailed information for a given target. | // info shows detailed information for a given target. | ||||||
| fn info(conf Config, id string) ! { | fn info(conf_ Config, id string) ! { | ||||||
| 	c := client.new(conf.address, conf.api_key) | 	c := client.new(conf_.address, conf_.api_key) | ||||||
| 	target := c.get_target(id.int())! | 	target := c.get_target(id.int())! | ||||||
| 	println(target) | 	println(target) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -25,7 +25,7 @@ fn test_not_allowed() { | ||||||
| 	for exp in illegal_expressions { | 	for exp in illegal_expressions { | ||||||
| 		res = false | 		res = false | ||||||
| 		parse_expression(exp) or { res = true } | 		parse_expression(exp) or { res = true } | ||||||
| 		assert res, "'$exp' should produce an error" | 		assert res, "'${exp}' should produce an error" | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| module db | module dbms | ||||||
| 
 | 
 | ||||||
| import sqlite | import db.sqlite | ||||||
| import time | import time | ||||||
| 
 | 
 | ||||||
| pub struct VieterDb { | pub struct VieterDb { | ||||||
|  | @ -49,13 +49,13 @@ pub fn init(db_path string) !VieterDb { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Apply each migration in order | 	// Apply each migration in order | ||||||
| 	for i in cur_version.version .. db.migrations_up.len { | 	for i in cur_version.version .. dbms.migrations_up.len { | ||||||
| 		migration := db.migrations_up[i].to_string() | 		migration := dbms.migrations_up[i].to_string() | ||||||
| 
 | 
 | ||||||
| 		version_num := i + 1 | 		version_num := i + 1 | ||||||
| 
 | 
 | ||||||
| 		// vfmt does not like these dots | 		// vfmt does not like these dots | ||||||
| 		println('Applying migration $version_num' + '...') | 		println('Applying migration ${version_num}' + '...') | ||||||
| 
 | 
 | ||||||
| 		// The sqlite library seems to not like it when multiple statements are | 		// The sqlite library seems to not like it when multiple statements are | ||||||
| 		// passed in a single exec. Therefore, we split them & run them all | 		// passed in a single exec. Therefore, we split them & run them all | ||||||
|  | @ -64,7 +64,7 @@ pub fn init(db_path string) !VieterDb { | ||||||
| 			res := conn.exec_none(part) | 			res := conn.exec_none(part) | ||||||
| 
 | 
 | ||||||
| 			if res != sqlite.sqlite_done { | 			if res != sqlite.sqlite_done { | ||||||
| 				return error('An error occurred while applying migration $version_num: SQLite error code $res') | 				return error('An error occurred while applying migration ${version_num}: SQLite error code ${res}') | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -80,9 +80,9 @@ pub fn init(db_path string) !VieterDb { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // row_into<T> converts an sqlite.Row into a given type T by parsing each field | // row_into[T] converts an sqlite.Row into a given type T by parsing each field | ||||||
| // from a string according to its type. | // from a string according to its type. | ||||||
| pub fn row_into<T>(row sqlite.Row) T { | pub fn row_into[T](row sqlite.Row) T { | ||||||
| 	mut i := 0 | 	mut i := 0 | ||||||
| 	mut out := T{} | 	mut out := T{} | ||||||
| 
 | 
 | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| module db | module dbms | ||||||
| 
 | 
 | ||||||
| import models { BuildLog, BuildLogFilter } | import models { BuildLog, BuildLogFilter } | ||||||
| import time | import time | ||||||
|  | @ -8,20 +8,20 @@ pub fn (db &VieterDb) get_build_logs(filter BuildLogFilter) []BuildLog { | ||||||
| 	mut where_parts := []string{} | 	mut where_parts := []string{} | ||||||
| 
 | 
 | ||||||
| 	if filter.target != 0 { | 	if filter.target != 0 { | ||||||
| 		where_parts << 'target_id == $filter.target' | 		where_parts << 'target_id == ${filter.target}' | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if filter.before != time.Time{} { | 	if filter.before != time.Time{} { | ||||||
| 		where_parts << 'start_time < $filter.before.unix_time()' | 		where_parts << 'start_time < ${filter.before.unix_time()}' | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if filter.after != time.Time{} { | 	if filter.after != time.Time{} { | ||||||
| 		where_parts << 'start_time > $filter.after.unix_time()' | 		where_parts << 'start_time > ${filter.after.unix_time()}' | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// NOTE: possible SQL injection | 	// NOTE: possible SQL injection | ||||||
| 	if filter.arch != '' { | 	if filter.arch != '' { | ||||||
| 		where_parts << "arch == '$filter.arch'" | 		where_parts << "arch == '${filter.arch}'" | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mut parts := []string{} | 	mut parts := []string{} | ||||||
|  | @ -30,27 +30,27 @@ pub fn (db &VieterDb) get_build_logs(filter BuildLogFilter) []BuildLog { | ||||||
| 		if exp[0] == `!` { | 		if exp[0] == `!` { | ||||||
| 			code := exp[1..].int() | 			code := exp[1..].int() | ||||||
| 
 | 
 | ||||||
| 			parts << 'exit_code != $code' | 			parts << 'exit_code != ${code}' | ||||||
| 		} else { | 		} else { | ||||||
| 			code := exp.int() | 			code := exp.int() | ||||||
| 
 | 
 | ||||||
| 			parts << 'exit_code == $code' | 			parts << 'exit_code == ${code}' | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if parts.len > 0 { | 	if parts.len > 0 { | ||||||
| 		where_parts << parts.map('($it)').join(' or ') | 		where_parts << parts.map('(${it})').join(' or ') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mut where_str := '' | 	mut where_str := '' | ||||||
| 
 | 
 | ||||||
| 	if where_parts.len > 0 { | 	if where_parts.len > 0 { | ||||||
| 		where_str = 'where ' + where_parts.map('($it)').join(' and ') | 		where_str = 'where ' + where_parts.map('(${it})').join(' and ') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	query := 'select * from BuildLog $where_str limit $filter.limit offset $filter.offset' | 	query := 'select * from BuildLog ${where_str} limit ${filter.limit} offset ${filter.offset}' | ||||||
| 	rows, _ := db.conn.exec(query) | 	rows, _ := db.conn.exec(query) | ||||||
| 	res := rows.map(row_into<BuildLog>(it)) | 	res := rows.map(row_into[BuildLog](it)) | ||||||
| 
 | 
 | ||||||
| 	return res | 	return res | ||||||
| } | } | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| module db | module dbms | ||||||
| 
 | 
 | ||||||
| import models { Target, TargetArch } | import models { Target, TargetArch } | ||||||
| 
 | 
 | ||||||
|  | @ -49,13 +49,13 @@ pub fn (db &VieterDb) update_target(target_id int, params map[string]string) { | ||||||
| 		if field.name in params { | 		if field.name in params { | ||||||
| 			// Any fields that are array types require their own update method | 			// Any fields that are array types require their own update method | ||||||
| 			$if field.typ is string { | 			$if field.typ is string { | ||||||
| 				values << "$field.name = '${params[field.name]}'" | 				values << "${field.name} = '${params[field.name]}'" | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	values_str := values.join(', ') | 	values_str := values.join(', ') | ||||||
| 	// I think this is actual SQL & not the ORM language | 	// I think this is actual SQL & not the ORM language | ||||||
| 	query := 'update Target set $values_str where id == $target_id' | 	query := 'update Target set ${values_str} where id == ${target_id}' | ||||||
| 
 | 
 | ||||||
| 	db.conn.exec_none(query) | 	db.conn.exec_none(query) | ||||||
| } | } | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| module db | module dbms | ||||||
| 
 | 
 | ||||||
| import models { Target, TargetFilter } | import models { Target, TargetFilter } | ||||||
| import sqlite | import db.sqlite | ||||||
| 
 | 
 | ||||||
| // Iterator providing a filtered view into the list of targets currently stored | // Iterator providing a filtered view into the list of targets currently stored | ||||||
| // in the database. It replaces functionality usually performed in the database | // in the database. It replaces functionality usually performed in the database | ||||||
|  | @ -14,5 +14,5 @@ pub: | ||||||
| 
 | 
 | ||||||
| // str return a single-line string representation of a build log | // str return a single-line string representation of a build log | ||||||
| pub fn (c BuildConfig) str() string { | pub fn (c BuildConfig) str() string { | ||||||
| 	return '{ target: $c.target_id, kind: $c.kind, url: $c.url, branch: $c.branch, path: $c.path, repo: $c.repo, base_image: $c.base_image, force: $c.force }' | 	return '{ target: ${c.target_id}, kind: ${c.kind}, url: ${c.url}, branch: ${c.branch}, path: ${c.path}, repo: ${c.repo}, base_image: ${c.base_image}, force: ${c.force} }' | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,13 +16,13 @@ pub mut: | ||||||
| // str returns a string representation. | // str returns a string representation. | ||||||
| pub fn (bl &BuildLog) str() string { | pub fn (bl &BuildLog) str() string { | ||||||
| 	mut parts := [ | 	mut parts := [ | ||||||
| 		'id: $bl.id', | 		'id: ${bl.id}', | ||||||
| 		'target id: $bl.target_id', | 		'target id: ${bl.target_id}', | ||||||
| 		'start time: $bl.start_time.local()', | 		'start time: ${bl.start_time.local()}', | ||||||
| 		'end time: $bl.end_time.local()', | 		'end time: ${bl.end_time.local()}', | ||||||
| 		'duration: ${bl.end_time - bl.start_time}', | 		'duration: ${bl.end_time - bl.start_time}', | ||||||
| 		'arch: $bl.arch', | 		'arch: ${bl.arch}', | ||||||
| 		'exit code: $bl.exit_code', | 		'exit code: ${bl.exit_code}', | ||||||
| 	] | 	] | ||||||
| 	str := parts.join('\n') | 	str := parts.join('\n') | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,19 +2,19 @@ module models | ||||||
| 
 | 
 | ||||||
| import time | import time | ||||||
| 
 | 
 | ||||||
| // from_params<T> creates a new instance of T from the given map by parsing all | // from_params[T] creates a new instance of T from the given map by parsing all | ||||||
| // of its fields from the map. | // of its fields from the map. | ||||||
| pub fn from_params<T>(params map[string]string) ?T { | pub fn from_params[T](params map[string]string) ?T { | ||||||
| 	mut o := T{} | 	mut o := T{} | ||||||
| 
 | 
 | ||||||
| 	patch_from_params<T>(mut o, params)? | 	patch_from_params[T](mut o, params)? | ||||||
| 
 | 
 | ||||||
| 	return o | 	return o | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // patch_from_params<T> updates the given T object with the params defined in | // patch_from_params[T] updates the given T object with the params defined in | ||||||
| // the map. | // the map. | ||||||
| pub fn patch_from_params<T>(mut o T, params map[string]string) ? { | pub fn patch_from_params[T](mut o T, params map[string]string) ? { | ||||||
| 	$for field in T.fields { | 	$for field in T.fields { | ||||||
| 		if field.name in params && params[field.name] != '' { | 		if field.name in params && params[field.name] != '' { | ||||||
| 			$if field.typ is string { | 			$if field.typ is string { | ||||||
|  | @ -36,8 +36,8 @@ pub fn patch_from_params<T>(mut o T, params map[string]string) ? { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // params_from<T> converts a given T struct into a map of strings. | // params_from[T] converts a given T struct into a map of strings. | ||||||
| pub fn params_from<T>(o &T) map[string]string { | pub fn params_from[T](o &T) map[string]string { | ||||||
| 	mut out := map[string]string{} | 	mut out := map[string]string{} | ||||||
| 
 | 
 | ||||||
| 	$for field in T.fields { | 	$for field in T.fields { | ||||||
|  |  | ||||||
|  | @ -38,13 +38,13 @@ pub mut: | ||||||
| // str returns a string representation. | // str returns a string representation. | ||||||
| pub fn (t &Target) str() string { | pub fn (t &Target) str() string { | ||||||
| 	mut parts := [ | 	mut parts := [ | ||||||
| 		'id: $t.id', | 		'id: ${t.id}', | ||||||
| 		'kind: $t.kind', | 		'kind: ${t.kind}', | ||||||
| 		'url: $t.url', | 		'url: ${t.url}', | ||||||
| 		'branch: $t.branch', | 		'branch: ${t.branch}', | ||||||
| 		'path: $t.path', | 		'path: ${t.path}', | ||||||
| 		'repo: $t.repo', | 		'repo: ${t.repo}', | ||||||
| 		'schedule: $t.schedule', | 		'schedule: ${t.schedule}', | ||||||
| 		'arch: ${t.arch.map(it.value).join(', ')}', | 		'arch: ${t.arch.map(it.value).join(', ')}', | ||||||
| 	] | 	] | ||||||
| 	str := parts.join('\n') | 	str := parts.join('\n') | ||||||
|  |  | ||||||
|  | @ -3,14 +3,14 @@ module package | ||||||
| // format_entry returns a string properly formatted to be added to a desc file. | // format_entry returns a string properly formatted to be added to a desc file. | ||||||
| [inline] | [inline] | ||||||
| fn format_entry(key string, value string) string { | fn format_entry(key string, value string) string { | ||||||
| 	return '\n%$key%\n$value\n' | 	return '\n%${key}%\n${value}\n' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // full_name returns the properly formatted name for the package, including | // full_name returns the properly formatted name for the package, including | ||||||
| // version & architecture | // version & architecture | ||||||
| pub fn (pkg &Pkg) full_name() string { | pub fn (pkg &Pkg) full_name() string { | ||||||
| 	p := pkg.info | 	p := pkg.info | ||||||
| 	return '$p.name-$p.version-$p.arch' | 	return '${p.name}-${p.version}-${p.arch}' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // filename returns the correct filename of the package file | // filename returns the correct filename of the package file | ||||||
|  | @ -20,10 +20,10 @@ pub fn (pkg &Pkg) filename() string { | ||||||
| 		1 { '.tar.gz' } | 		1 { '.tar.gz' } | ||||||
| 		6 { '.tar.xz' } | 		6 { '.tar.xz' } | ||||||
| 		14 { '.tar.zst' } | 		14 { '.tar.zst' } | ||||||
| 		else { panic("Another compression code shouldn't be possible. Faulty code: $pkg.compression") } | 		else { panic("Another compression code shouldn't be possible. Faulty code: ${pkg.compression}") } | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return '${pkg.full_name()}.pkg$ext' | 	return '${pkg.full_name()}.pkg${ext}' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // to_desc returns a desc file valid string representation | // to_desc returns a desc file valid string representation | ||||||
|  | @ -31,7 +31,7 @@ pub fn (pkg &Pkg) to_desc() !string { | ||||||
| 	p := pkg.info | 	p := pkg.info | ||||||
| 
 | 
 | ||||||
| 	// filename | 	// filename | ||||||
| 	mut desc := '%FILENAME%\n$pkg.filename()\n' | 	mut desc := '%FILENAME%\n${pkg.filename()}\n' | ||||||
| 
 | 
 | ||||||
| 	desc += format_entry('NAME', p.name) | 	desc += format_entry('NAME', p.name) | ||||||
| 	desc += format_entry('BASE', p.base) | 	desc += format_entry('BASE', p.base) | ||||||
|  | @ -94,10 +94,10 @@ pub fn (pkg &Pkg) to_desc() !string { | ||||||
| 		desc += format_entry('CHECKDEPENDS', p.checkdepends.join_lines()) | 		desc += format_entry('CHECKDEPENDS', p.checkdepends.join_lines()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return '$desc\n' | 	return '${desc}\n' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // to_files returns a files file valid string representation | // to_files returns a files file valid string representation | ||||||
| pub fn (pkg &Pkg) to_files() string { | pub fn (pkg &Pkg) to_files() string { | ||||||
| 	return '%FILES%\n$pkg.files.join_lines()\n' | 	return '%FILES%\n${pkg.files.join_lines()}\n' | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -103,7 +103,7 @@ fn parse_pkg_info_string(pkg_info_str &string) !PkgInfo { | ||||||
| // NOTE: this command only supports zstd-, xz- & gzip-compressed tarballs. | // NOTE: this command only supports zstd-, xz- & gzip-compressed tarballs. | ||||||
| pub fn read_pkg_archive(pkg_path string) !Pkg { | pub fn read_pkg_archive(pkg_path string) !Pkg { | ||||||
| 	if !os.is_file(pkg_path) { | 	if !os.is_file(pkg_path) { | ||||||
| 		return error("'$pkg_path' doesn't exist or isn't a file.") | 		return error("'${pkg_path}' doesn't exist or isn't a file.") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	a := C.archive_read_new() | 	a := C.archive_read_new() | ||||||
|  |  | ||||||
|  | @ -31,11 +31,15 @@ pub: | ||||||
| // new creates a new RepoGroupManager & creates the directories as needed | // new creates a new RepoGroupManager & creates the directories as needed | ||||||
| pub fn new(repos_dir string, pkg_dir string, default_arch string) !RepoGroupManager { | pub fn new(repos_dir string, pkg_dir string, default_arch string) !RepoGroupManager { | ||||||
| 	if !os.is_dir(repos_dir) { | 	if !os.is_dir(repos_dir) { | ||||||
| 		os.mkdir_all(repos_dir) or { return error('Failed to create repos directory: $err.msg()') } | 		os.mkdir_all(repos_dir) or { | ||||||
|  | 			return error('Failed to create repos directory: ${err.msg()}') | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !os.is_dir(pkg_dir) { | 	if !os.is_dir(pkg_dir) { | ||||||
| 		os.mkdir_all(pkg_dir) or { return error('Failed to create package directory: $err.msg()') } | 		os.mkdir_all(pkg_dir) or { | ||||||
|  | 			return error('Failed to create package directory: ${err.msg()}') | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return RepoGroupManager{ | 	return RepoGroupManager{ | ||||||
|  | @ -51,7 +55,7 @@ pub fn new(repos_dir string, pkg_dir string, default_arch string) !RepoGroupMana | ||||||
| // the right subdirectories in r.pkg_dir if it was successfully added. | // the right subdirectories in r.pkg_dir if it was successfully added. | ||||||
| pub fn (r &RepoGroupManager) add_pkg_from_path(repo string, pkg_path string) !RepoAddResult { | pub fn (r &RepoGroupManager) add_pkg_from_path(repo string, pkg_path string) !RepoAddResult { | ||||||
| 	pkg := package.read_pkg_archive(pkg_path) or { | 	pkg := package.read_pkg_archive(pkg_path) or { | ||||||
| 		return error('Failed to read package file: $err.msg()') | 		return error('Failed to read package file: ${err.msg()}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	archs := r.add_pkg_in_repo(repo, pkg)! | 	archs := r.add_pkg_in_repo(repo, pkg)! | ||||||
|  | @ -129,7 +133,7 @@ fn (r &RepoGroupManager) add_pkg_in_repo(repo string, pkg &package.Pkg) ![]strin | ||||||
| // files, and afterwards updates the db & files archives to reflect these | // files, and afterwards updates the db & files archives to reflect these | ||||||
| // changes. | // changes. | ||||||
| fn (r &RepoGroupManager) add_pkg_in_arch_repo(repo string, arch string, pkg &package.Pkg) ! { | fn (r &RepoGroupManager) add_pkg_in_arch_repo(repo string, arch string, pkg &package.Pkg) ! { | ||||||
| 	pkg_dir := os.join_path(r.repos_dir, repo, arch, '$pkg.info.name-$pkg.info.version') | 	pkg_dir := os.join_path(r.repos_dir, repo, arch, '${pkg.info.name}-${pkg.info.version}') | ||||||
| 
 | 
 | ||||||
| 	// Remove the previous version of the package, if present | 	// Remove the previous version of the package, if present | ||||||
| 	r.remove_pkg_from_arch_repo(repo, arch, pkg.info.name, false)! | 	r.remove_pkg_from_arch_repo(repo, arch, pkg.info.name, false)! | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import os | ||||||
| // remove_pkg_from_arch_repo removes a package from an arch-repo's database. It | // remove_pkg_from_arch_repo removes a package from an arch-repo's database. It | ||||||
| // returns false if the package wasn't present in the database. It also | // returns false if the package wasn't present in the database. It also | ||||||
| // optionally re-syncs the repo archives. | // optionally re-syncs the repo archives. | ||||||
| pub fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, pkg_name string, sync bool) !bool { | pub fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, pkg_name string, perform_sync bool) !bool { | ||||||
| 	repo_dir := os.join_path(r.repos_dir, repo, arch) | 	repo_dir := os.join_path(r.repos_dir, repo, arch) | ||||||
| 
 | 
 | ||||||
| 	// If the repository doesn't exist yet, the result is automatically false | 	// If the repository doesn't exist yet, the result is automatically false | ||||||
|  | @ -39,7 +39,7 @@ pub fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// Sync the db archives if requested | 			// Sync the db archives if requested | ||||||
| 			if sync { | 			if perform_sync { | ||||||
| 				r.sync(repo, arch)! | 				r.sync(repo, arch)! | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ module server | ||||||
| import web | import web | ||||||
| import net.urllib | import net.urllib | ||||||
| import web.response { new_data_response, new_response } | import web.response { new_data_response, new_response } | ||||||
| import db |  | ||||||
| import time | import time | ||||||
| import os | import os | ||||||
| import util | import util | ||||||
|  | @ -13,7 +12,7 @@ import models { BuildLog, BuildLogFilter } | ||||||
| // optionally be added to limit the list of build logs to that repository. | // optionally be added to limit the list of build logs to that repository. | ||||||
| ['/api/v1/logs'; auth; get; markused] | ['/api/v1/logs'; auth; get; markused] | ||||||
| fn (mut app App) v1_get_logs() web.Result { | fn (mut app App) v1_get_logs() web.Result { | ||||||
| 	filter := models.from_params<BuildLogFilter>(app.query) or { | 	filter := models.from_params[BuildLogFilter](app.query) or { | ||||||
| 		return app.json(.bad_request, new_response('Invalid query parameters.')) | 		return app.json(.bad_request, new_response('Invalid query parameters.')) | ||||||
| 	} | 	} | ||||||
| 	logs := app.db.get_build_logs(filter) | 	logs := app.db.get_build_logs(filter) | ||||||
|  | @ -101,7 +100,7 @@ fn (mut app App) v1_post_log() web.Result { | ||||||
| 	// Create the logs directory of it doesn't exist | 	// Create the logs directory of it doesn't exist | ||||||
| 	if !os.exists(os.dir(log_file_path)) { | 	if !os.exists(os.dir(log_file_path)) { | ||||||
| 		os.mkdir_all(os.dir(log_file_path)) or { | 		os.mkdir_all(os.dir(log_file_path)) or { | ||||||
| 			app.lerror('Error while creating log file: $err.msg()') | 			app.lerror('Error while creating log file: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 			return app.status(.internal_server_error) | 			return app.status(.internal_server_error) | ||||||
| 		} | 		} | ||||||
|  | @ -109,7 +108,7 @@ fn (mut app App) v1_post_log() web.Result { | ||||||
| 
 | 
 | ||||||
| 	if length := app.req.header.get(.content_length) { | 	if length := app.req.header.get(.content_length) { | ||||||
| 		util.reader_to_file(mut app.reader, length.int(), log_file_path) or { | 		util.reader_to_file(mut app.reader, length.int(), log_file_path) or { | ||||||
| 			app.lerror('An error occured while receiving logs: $err.msg()') | 			app.lerror('An error occured while receiving logs: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 			return app.status(.internal_server_error) | 			return app.status(.internal_server_error) | ||||||
| 		} | 		} | ||||||
|  | @ -127,7 +126,7 @@ fn (mut app App) v1_delete_log(id int) web.Result { | ||||||
| 	full_path := os.join_path(app.conf.data_dir, logs_dir_name, log.path()) | 	full_path := os.join_path(app.conf.data_dir, logs_dir_name, log.path()) | ||||||
| 
 | 
 | ||||||
| 	os.rm(full_path) or { | 	os.rm(full_path) or { | ||||||
| 		app.lerror('Failed to remove log file $full_path: $err.msg()') | 		app.lerror('Failed to remove log file ${full_path}: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 		return app.status(.internal_server_error) | 		return app.status(.internal_server_error) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -2,13 +2,12 @@ module server | ||||||
| 
 | 
 | ||||||
| import web | import web | ||||||
| import web.response { new_data_response, new_response } | import web.response { new_data_response, new_response } | ||||||
| import db |  | ||||||
| import models { Target, TargetArch, TargetFilter } | import models { Target, TargetArch, TargetFilter } | ||||||
| 
 | 
 | ||||||
| // v1_get_targets returns the current list of targets. | // v1_get_targets returns the current list of targets. | ||||||
| ['/api/v1/targets'; auth; get; markused] | ['/api/v1/targets'; auth; get; markused] | ||||||
| fn (mut app App) v1_get_targets() web.Result { | fn (mut app App) v1_get_targets() web.Result { | ||||||
| 	filter := models.from_params<TargetFilter>(app.query) or { | 	filter := models.from_params[TargetFilter](app.query) or { | ||||||
| 		return app.json(.bad_request, new_response('Invalid query parameters.')) | 		return app.json(.bad_request, new_response('Invalid query parameters.')) | ||||||
| 	} | 	} | ||||||
| 	mut iter := app.db.targets(filter) | 	mut iter := app.db.targets(filter) | ||||||
|  | @ -35,7 +34,7 @@ fn (mut app App) v1_post_target() web.Result { | ||||||
| 		params['arch'] = app.conf.default_arch | 		params['arch'] = app.conf.default_arch | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mut new_target := models.from_params<Target>(params) or { | 	mut new_target := models.from_params[Target](params) or { | ||||||
| 		return app.json(.bad_request, new_response(err.msg())) | 		return app.json(.bad_request, new_response(err.msg())) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,9 +25,9 @@ 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 := vconf.load<Config>(prefix: 'VIETER_', default_path: config_file)! | 			conf_ := vconf.load[Config](prefix: 'VIETER_', default_path: config_file)! | ||||||
| 
 | 
 | ||||||
| 			server(conf)! | 			server(conf_)! | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ fn (mut app App) log_removal_daemon(schedule &cron.Expression) { | ||||||
| 	for { | 	for { | ||||||
| 		mut too_old_timestamp := time.now().add_days(-app.conf.max_log_age) | 		mut too_old_timestamp := time.now().add_days(-app.conf.max_log_age) | ||||||
| 
 | 
 | ||||||
| 		app.linfo('Cleaning logs before $too_old_timestamp') | 		app.linfo('Cleaning logs before ${too_old_timestamp}') | ||||||
| 
 | 
 | ||||||
| 		mut logs := []BuildLog{} | 		mut logs := []BuildLog{} | ||||||
| 		mut counter := 0 | 		mut counter := 0 | ||||||
|  | @ -29,7 +29,7 @@ fn (mut app App) log_removal_daemon(schedule &cron.Expression) { | ||||||
| 				log_file_path := os.join_path(app.conf.data_dir, logs_dir_name, log.path()) | 				log_file_path := os.join_path(app.conf.data_dir, logs_dir_name, log.path()) | ||||||
| 
 | 
 | ||||||
| 				os.rm(log_file_path) or { | 				os.rm(log_file_path) or { | ||||||
| 					app.lerror('Failed to remove log file $log_file_path: $err.msg()') | 					app.lerror('Failed to remove log file ${log_file_path}: ${err.msg()}') | ||||||
| 					failed += 1 | 					failed += 1 | ||||||
| 
 | 
 | ||||||
| 					continue | 					continue | ||||||
|  | @ -44,7 +44,7 @@ fn (mut app App) log_removal_daemon(schedule &cron.Expression) { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		app.linfo('Cleaned $counter logs ($failed failed)') | 		app.linfo('Cleaned ${counter} logs (${failed} failed)') | ||||||
| 
 | 
 | ||||||
| 		// Sleep until the next cycle | 		// Sleep until the next cycle | ||||||
| 		next_time := schedule.next_from_now() | 		next_time := schedule.next_from_now() | ||||||
|  |  | ||||||
|  | @ -19,15 +19,15 @@ pub fn (mut app App) healthcheck() web.Result { | ||||||
| // repository's archives, but also package archives or the contents of a | // repository's archives, but also package archives or the contents of a | ||||||
| // package's desc file. | // package's desc file. | ||||||
| ['/:repo/:arch/:filename'; get; head; markused] | ['/:repo/:arch/:filename'; get; head; markused] | ||||||
| fn (mut app App) get_repo_file(repo string, arch string, filename string) web.Result { | fn (mut app App) get_repo_file(repo_ string, arch string, filename string) web.Result { | ||||||
| 	mut full_path := '' | 	mut full_path := '' | ||||||
| 
 | 
 | ||||||
| 	db_exts := ['.db', '.files', '.db.tar.gz', '.files.tar.gz'] | 	db_exts := ['.db', '.files', '.db.tar.gz', '.files.tar.gz'] | ||||||
| 
 | 
 | ||||||
| 	// There's no point in having the ability to serve db archives with wrong | 	// There's no point in having the ability to serve db archives with wrong | ||||||
| 	// filenames | 	// filenames | ||||||
| 	if db_exts.any(filename == '$repo$it') { | 	if db_exts.any(filename == '${repo_}${it}') { | ||||||
| 		full_path = os.join_path(app.repo.repos_dir, repo, arch, filename) | 		full_path = os.join_path(app.repo.repos_dir, repo_, arch, filename) | ||||||
| 
 | 
 | ||||||
| 		// repo-add does this using symlinks, but we just change the requested | 		// repo-add does this using symlinks, but we just change the requested | ||||||
| 		// path | 		// path | ||||||
|  | @ -35,13 +35,13 @@ fn (mut app App) get_repo_file(repo string, arch string, filename string) web.Re | ||||||
| 			full_path += '.tar.gz' | 			full_path += '.tar.gz' | ||||||
| 		} | 		} | ||||||
| 	} else if filename.contains('.pkg') { | 	} else if filename.contains('.pkg') { | ||||||
| 		full_path = os.join_path(app.repo.pkg_dir, repo, arch, filename) | 		full_path = os.join_path(app.repo.pkg_dir, repo_, arch, filename) | ||||||
| 	} | 	} | ||||||
| 	// Default behavior is to return the desc file for the package, if present. | 	// Default behavior is to return the desc file for the package, if present. | ||||||
| 	// This can then also be used by the build system to properly check whether | 	// This can then also be used by the build system to properly check whether | ||||||
| 	// a package is present in an arch-repo. | 	// a package is present in an arch-repo. | ||||||
| 	else { | 	else { | ||||||
| 		full_path = os.join_path(app.repo.repos_dir, repo, arch, filename, 'desc') | 		full_path = os.join_path(app.repo.repos_dir, repo_, arch, filename, 'desc') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return app.file(full_path) | 	return app.file(full_path) | ||||||
|  | @ -49,10 +49,10 @@ fn (mut app App) get_repo_file(repo string, arch string, filename string) web.Re | ||||||
| 
 | 
 | ||||||
| // put_package handles publishing a package to a repository. | // put_package handles publishing a package to a repository. | ||||||
| ['/:repo/publish'; auth; markused; post] | ['/:repo/publish'; auth; markused; post] | ||||||
| fn (mut app App) put_package(repo string) web.Result { | fn (mut app App) put_package(repo_ string) web.Result { | ||||||
| 	// api is a reserved keyword for api routes & should never be allowed to be | 	// api is a reserved keyword for api routes & should never be allowed to be | ||||||
| 	// a repository. | 	// a repository. | ||||||
| 	if repo.to_lower() == 'api' { | 	if repo_.to_lower() == 'api' { | ||||||
| 		return app.json(.bad_request, new_response("'api' is a reserved keyword & cannot be used as a repository name.")) | 		return app.json(.bad_request, new_response("'api' is a reserved keyword & cannot be used as a repository name.")) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -62,19 +62,19 @@ fn (mut app App) put_package(repo string) web.Result { | ||||||
| 		// Generate a random filename for the temp file | 		// Generate a random filename for the temp file | ||||||
| 		pkg_path = os.join_path_single(app.repo.pkg_dir, rand.uuid_v4()) | 		pkg_path = os.join_path_single(app.repo.pkg_dir, rand.uuid_v4()) | ||||||
| 
 | 
 | ||||||
| 		app.ldebug("Uploading $length bytes (${util.pretty_bytes(length.int())}) to '$pkg_path'.") | 		app.ldebug("Uploading ${length} bytes (${util.pretty_bytes(length.int())}) to '${pkg_path}'.") | ||||||
| 
 | 
 | ||||||
| 		// This is used to time how long it takes to upload a file | 		// This is used to time how long it takes to upload a file | ||||||
| 		mut sw := time.new_stopwatch(time.StopWatchOptions{ auto_start: true }) | 		mut sw := time.new_stopwatch(time.StopWatchOptions{ auto_start: true }) | ||||||
| 
 | 
 | ||||||
| 		util.reader_to_file(mut app.reader, length.int(), pkg_path) or { | 		util.reader_to_file(mut app.reader, length.int(), pkg_path) or { | ||||||
| 			app.lwarn("Failed to upload '$pkg_path'") | 			app.lwarn("Failed to upload '${pkg_path}'") | ||||||
| 
 | 
 | ||||||
| 			return app.status(.internal_server_error) | 			return app.status(.internal_server_error) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		sw.stop() | 		sw.stop() | ||||||
| 		app.ldebug("Upload of '$pkg_path' completed in ${sw.elapsed().seconds():.3}s.") | 		app.ldebug("Upload of '${pkg_path}' completed in ${sw.elapsed().seconds():.3}s.") | ||||||
| 	} else { | 	} else { | ||||||
| 		app.lwarn('Tried to upload package without specifying a Content-Length.') | 		app.lwarn('Tried to upload package without specifying a Content-Length.') | ||||||
| 
 | 
 | ||||||
|  | @ -82,15 +82,15 @@ fn (mut app App) put_package(repo string) web.Result { | ||||||
| 		return app.status(.length_required) | 		return app.status(.length_required) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	res := app.repo.add_pkg_from_path(repo, pkg_path) or { | 	res := app.repo.add_pkg_from_path(repo_, pkg_path) or { | ||||||
| 		app.lerror('Error while adding package: $err.msg()') | 		app.lerror('Error while adding package: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 		os.rm(pkg_path) or { app.lerror("Failed to remove download '$pkg_path': $err.msg()") } | 		os.rm(pkg_path) or { app.lerror("Failed to remove download '${pkg_path}': ${err.msg()}") } | ||||||
| 
 | 
 | ||||||
| 		return app.status(.internal_server_error) | 		return app.status(.internal_server_error) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	app.linfo("Added '$res.name-$res.version' to '$repo (${res.archs.join(',')})'.") | 	app.linfo("Added '${res.name}-${res.version}' to '${repo_} (${res.archs.join(',')})'.") | ||||||
| 
 | 
 | ||||||
| 	return app.json(.ok, new_data_response(res)) | 	return app.json(.ok, new_data_response(res)) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,17 +6,17 @@ import web | ||||||
| ['/:repo/:arch/:pkg'; auth; delete; markused] | ['/:repo/:arch/:pkg'; auth; delete; markused] | ||||||
| fn (mut app App) delete_package(repo string, arch string, pkg string) web.Result { | fn (mut app App) delete_package(repo string, arch string, pkg string) web.Result { | ||||||
| 	res := app.repo.remove_pkg_from_arch_repo(repo, arch, pkg, true) or { | 	res := app.repo.remove_pkg_from_arch_repo(repo, arch, pkg, true) or { | ||||||
| 		app.lerror('Error while deleting package: $err.msg()') | 		app.lerror('Error while deleting package: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 		return app.status(.internal_server_error) | 		return app.status(.internal_server_error) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if res { | 	if res { | ||||||
| 		app.linfo("Removed package '$pkg' from '$repo/$arch'") | 		app.linfo("Removed package '${pkg}' from '${repo}/${arch}'") | ||||||
| 
 | 
 | ||||||
| 		return app.status(.ok) | 		return app.status(.ok) | ||||||
| 	} else { | 	} else { | ||||||
| 		app.linfo("Tried removing package '$pkg' from '$repo/$arch', but it doesn't exist.") | 		app.linfo("Tried removing package '${pkg}' from '${repo}/${arch}', but it doesn't exist.") | ||||||
| 
 | 
 | ||||||
| 		return app.status(.not_found) | 		return app.status(.not_found) | ||||||
| 	} | 	} | ||||||
|  | @ -26,17 +26,17 @@ fn (mut app App) delete_package(repo string, arch string, pkg string) web.Result | ||||||
| ['/:repo/:arch'; auth; delete; markused] | ['/:repo/:arch'; auth; delete; markused] | ||||||
| fn (mut app App) delete_arch_repo(repo string, arch string) web.Result { | fn (mut app App) delete_arch_repo(repo string, arch string) web.Result { | ||||||
| 	res := app.repo.remove_arch_repo(repo, arch) or { | 	res := app.repo.remove_arch_repo(repo, arch) or { | ||||||
| 		app.lerror('Error while deleting arch-repo: $err.msg()') | 		app.lerror('Error while deleting arch-repo: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 		return app.status(.internal_server_error) | 		return app.status(.internal_server_error) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if res { | 	if res { | ||||||
| 		app.linfo("Removed arch-repo '$repo/$arch'") | 		app.linfo("Removed arch-repo '${repo}/${arch}'") | ||||||
| 
 | 
 | ||||||
| 		return app.status(.ok) | 		return app.status(.ok) | ||||||
| 	} else { | 	} else { | ||||||
| 		app.linfo("Tried removing '$repo/$arch', but it doesn't exist.") | 		app.linfo("Tried removing '${repo}/${arch}', but it doesn't exist.") | ||||||
| 
 | 
 | ||||||
| 		return app.status(.not_found) | 		return app.status(.not_found) | ||||||
| 	} | 	} | ||||||
|  | @ -46,17 +46,17 @@ fn (mut app App) delete_arch_repo(repo string, arch string) web.Result { | ||||||
| ['/:repo'; auth; delete; markused] | ['/:repo'; auth; delete; markused] | ||||||
| fn (mut app App) delete_repo(repo string) web.Result { | fn (mut app App) delete_repo(repo string) web.Result { | ||||||
| 	res := app.repo.remove_repo(repo) or { | 	res := app.repo.remove_repo(repo) or { | ||||||
| 		app.lerror('Error while deleting repo: $err.msg()') | 		app.lerror('Error while deleting repo: ${err.msg()}') | ||||||
| 
 | 
 | ||||||
| 		return app.status(.internal_server_error) | 		return app.status(.internal_server_error) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if res { | 	if res { | ||||||
| 		app.linfo("Removed repo '$repo'") | 		app.linfo("Removed repo '${repo}'") | ||||||
| 
 | 
 | ||||||
| 		return app.status(.ok) | 		return app.status(.ok) | ||||||
| 	} else { | 	} else { | ||||||
| 		app.linfo("Tried removing '$repo', but it doesn't exist.") | 		app.linfo("Tried removing '${repo}', but it doesn't exist.") | ||||||
| 
 | 
 | ||||||
| 		return app.status(.not_found) | 		return app.status(.not_found) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import os | ||||||
| import log | import log | ||||||
| import repo | import repo | ||||||
| import util | import util | ||||||
| import db | import dbms | ||||||
| import build { BuildJobQueue } | import build { BuildJobQueue } | ||||||
| import cron | import cron | ||||||
| import metrics | import metrics | ||||||
|  | @ -25,7 +25,7 @@ pub mut: | ||||||
| 	repo repo.RepoGroupManager [required; web_global] | 	repo repo.RepoGroupManager [required; web_global] | ||||||
| 	// Keys are the various architectures for packages | 	// Keys are the various architectures for packages | ||||||
| 	job_queue BuildJobQueue [required; web_global] | 	job_queue BuildJobQueue [required; web_global] | ||||||
| 	db        db.VieterDb | 	db        dbms.VieterDb | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // init_job_queue populates a fresh job queue with all the targets currently | // init_job_queue populates a fresh job queue with all the targets currently | ||||||
|  | @ -44,11 +44,11 @@ pub fn server(conf Config) ! { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	global_ce := cron.parse_expression(conf.global_schedule) or { | 	global_ce := cron.parse_expression(conf.global_schedule) or { | ||||||
| 		util.exit_with_message(1, 'Invalid global cron expression: $err.msg()') | 		util.exit_with_message(1, 'Invalid global cron expression: ${err.msg()}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	log_removal_ce := cron.parse_expression(conf.log_removal_schedule) or { | 	log_removal_ce := cron.parse_expression(conf.log_removal_schedule) or { | ||||||
| 		util.exit_with_message(1, 'Invalid log removal cron expression: $err.msg()') | 		util.exit_with_message(1, 'Invalid log removal cron expression: ${err.msg()}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Configure logger | 	// Configure logger | ||||||
|  | @ -82,14 +82,14 @@ pub fn server(conf Config) ! { | ||||||
| 
 | 
 | ||||||
| 	repo_dir := os.join_path_single(conf.data_dir, server.repo_dir_name) | 	repo_dir := os.join_path_single(conf.data_dir, server.repo_dir_name) | ||||||
| 	// This also creates the directories if needed | 	// This also creates the directories if needed | ||||||
| 	repo := repo.new(repo_dir, conf.pkg_dir, conf.default_arch) or { | 	repo_ := repo.new(repo_dir, conf.pkg_dir, conf.default_arch) or { | ||||||
| 		logger.error(err.msg()) | 		logger.error(err.msg()) | ||||||
| 		exit(1) | 		exit(1) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	db_file := os.join_path_single(conf.data_dir, server.db_file_name) | 	db_file := os.join_path_single(conf.data_dir, server.db_file_name) | ||||||
| 	db := db.init(db_file) or { | 	db := dbms.init(db_file) or { | ||||||
| 		util.exit_with_message(1, 'Failed to initialize database: $err.msg()') | 		util.exit_with_message(1, 'Failed to initialize database: ${err.msg()}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mut collector := if conf.collect_metrics { | 	mut collector := if conf.collect_metrics { | ||||||
|  | @ -98,24 +98,24 @@ pub fn server(conf Config) ! { | ||||||
| 		&metrics.MetricsCollector(metrics.new_null_collector()) | 		&metrics.MetricsCollector(metrics.new_null_collector()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	collector.histogram_buckets_set('http_requests_duration_seconds', [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, | 	collector.histogram_buckets_set('http_requests_duration_seconds', [0.001, 0.005, 0.01, 0.05, | ||||||
| 		10] ) | 		0.1, 0.5, 1, 5, 10]) | ||||||
| 
 | 
 | ||||||
| 	mut app := &App{ | 	mut app := &App{ | ||||||
| 		logger: logger | 		logger: logger | ||||||
| 		api_key: conf.api_key | 		api_key: conf.api_key | ||||||
| 		conf: conf | 		conf: conf | ||||||
| 		repo: repo | 		repo: repo_ | ||||||
| 		db: db | 		db: db | ||||||
| 		collector: collector | 		collector: collector | ||||||
| 		job_queue: build.new_job_queue(global_ce, conf.base_image) | 		job_queue: build.new_job_queue(global_ce, conf.base_image) | ||||||
| 	} | 	} | ||||||
| 	app.init_job_queue() or { | 	app.init_job_queue() or { | ||||||
| 		util.exit_with_message(1, 'Failed to inialize job queue: $err.msg()') | 		util.exit_with_message(1, 'Failed to inialize job queue: ${err.msg()}') | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if conf.max_log_age > 0 { | 	if conf.max_log_age > 0 { | ||||||
| 		go app.log_removal_daemon(log_removal_ce) | 		spawn app.log_removal_daemon(log_removal_ce) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	web.run(app, conf.port) | 	web.run(app, conf.port) | ||||||
|  |  | ||||||
|  | @ -48,10 +48,10 @@ pub fn reader_to_file(mut reader io.BufferedReader, length int, path string) ! { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // match_array_in_array<T> returns how many elements of a2 overlap with a1. For | // match_array_in_array[T] returns how many elements of a2 overlap with a1. For | ||||||
| // example, if a1 = "abcd" & a2 = "cd", the result will be 2. If the match is | // example, if a1 = "abcd" & a2 = "cd", the result will be 2. If the match is | ||||||
| // not at the end of a1, the result is 0. | // not at the end of a1, the result is 0. | ||||||
| pub fn match_array_in_array<T>(a1 []T, a2 []T) int { | pub fn match_array_in_array[T](a1 []T, a2 []T) int { | ||||||
| 	mut i := 0 | 	mut i := 0 | ||||||
| 	mut match_len := 0 | 	mut match_len := 0 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ const attrs_to_ignore = ['auth', 'markused'] | ||||||
| // Parsing function attributes for methods and path. | // Parsing function attributes for methods and path. | ||||||
| fn parse_attrs(name string, attrs []string) !([]http.Method, string) { | fn parse_attrs(name string, attrs []string) !([]http.Method, string) { | ||||||
| 	if attrs.len == 0 { | 	if attrs.len == 0 { | ||||||
| 		return [http.Method.get], '/$name' | 		return [http.Method.get], '/${name}' | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mut x := attrs.clone() | 	mut x := attrs.clone() | ||||||
|  | @ -45,7 +45,7 @@ fn parse_attrs(name string, attrs []string) !([]http.Method, string) { | ||||||
| 		methods = [http.Method.get] | 		methods = [http.Method.get] | ||||||
| 	} | 	} | ||||||
| 	if path == '' { | 	if path == '' { | ||||||
| 		path = '/$name' | 		path = '/${name}' | ||||||
| 	} | 	} | ||||||
| 	// Make path lowercase for case-insensitive comparisons | 	// Make path lowercase for case-insensitive comparisons | ||||||
| 	return methods, path.to_lower() | 	return methods, path.to_lower() | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| module response | module response | ||||||
| 
 | 
 | ||||||
| pub struct Response<T> { | pub struct Response[T] { | ||||||
| pub: | pub: | ||||||
| 	message string | 	message string | ||||||
| 	data    T | 	data    T | ||||||
|  | @ -8,26 +8,26 @@ pub: | ||||||
| 
 | 
 | ||||||
| // new_response constructs a new Response<String> object with the given message | // new_response constructs a new Response<String> object with the given message | ||||||
| // & an empty data field. | // & an empty data field. | ||||||
| pub fn new_response(message string) Response<string> { | pub fn new_response(message string) Response[string] { | ||||||
| 	return Response<string>{ | 	return Response[string]{ | ||||||
| 		message: message | 		message: message | ||||||
| 		data: '' | 		data: '' | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // new_data_response<T> constructs a new Response<T> object with the given data | // new_data_response[T] constructs a new Response<T> object with the given data | ||||||
| // & an empty message field. | // & an empty message field. | ||||||
| pub fn new_data_response<T>(data T) Response<T> { | pub fn new_data_response[T](data T) Response[T] { | ||||||
| 	return Response<T>{ | 	return Response[T]{ | ||||||
| 		message: '' | 		message: '' | ||||||
| 		data: data | 		data: data | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // new_full_response<T> constructs a new Response<T> object with the given | // new_full_response[T] constructs a new Response<T> object with the given | ||||||
| // message & data. | // message & data. | ||||||
| pub fn new_full_response<T>(message string, data T) Response<T> { | pub fn new_full_response[T](message string, data T) Response[T] { | ||||||
| 	return Response<T>{ | 	return Response[T]{ | ||||||
| 		message: message | 		message: message | ||||||
| 		data: data | 		data: data | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -44,7 +44,7 @@ pub mut: | ||||||
| 	// Files from multipart-form. | 	// Files from multipart-form. | ||||||
| 	files map[string][]http.FileData | 	files map[string][]http.FileData | ||||||
| 	// Allows reading the request body | 	// Allows reading the request body | ||||||
| 	reader io.BufferedReader | 	reader &io.BufferedReader = unsafe { nil } | ||||||
| 	// RESPONSE | 	// RESPONSE | ||||||
| 	status       http.Status = http.Status.ok | 	status       http.Status = http.Status.ok | ||||||
| 	content_type string      = 'text/plain' | 	content_type string      = 'text/plain' | ||||||
|  | @ -157,8 +157,8 @@ pub fn (mut ctx Context) body(status http.Status, content_type string, body stri | ||||||
| 	return Result{} | 	return Result{} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // json<T> HTTP_OK with json_s as payload with content-type `application/json` | // json[T] HTTP_OK with json_s as payload with content-type `application/json` | ||||||
| pub fn (mut ctx Context) json<T>(status http.Status, j T) Result { | pub fn (mut ctx Context) json[T](status http.Status, j T) Result { | ||||||
| 	ctx.status = status | 	ctx.status = status | ||||||
| 	ctx.content_type = 'application/json' | 	ctx.content_type = 'application/json' | ||||||
| 
 | 
 | ||||||
|  | @ -278,14 +278,14 @@ interface DbInterface { | ||||||
| 
 | 
 | ||||||
| // run runs the app | // run runs the app | ||||||
| [manualfree] | [manualfree] | ||||||
| pub fn run<T>(global_app &T, port int) { | pub fn run[T](global_app &T, port int) { | ||||||
| 	mut l := net.listen_tcp(.ip6, ':$port') or { panic('failed to listen $err.code() $err') } | 	mut l := net.listen_tcp(.ip6, ':${port}') or { panic('failed to listen ${err.code()} ${err}') } | ||||||
| 
 | 
 | ||||||
| 	// Parsing methods attributes | 	// Parsing methods attributes | ||||||
| 	mut routes := map[string]Route{} | 	mut routes := map[string]Route{} | ||||||
| 	$for method in T.methods { | 	$for method in T.methods { | ||||||
| 		http_methods, route_path := parse_attrs(method.name, method.attrs) or { | 		http_methods, route_path := parse_attrs(method.name, method.attrs) or { | ||||||
| 			eprintln('error parsing method attributes: $err') | 			eprintln('error parsing method attributes: ${err}') | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -294,7 +294,7 @@ pub fn run<T>(global_app &T, port int) { | ||||||
| 			path: route_path | 			path: route_path | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	println('[Vweb] Running app on http://localhost:$port') | 	println('[Vweb] Running app on http://localhost:${port}') | ||||||
| 	for { | 	for { | ||||||
| 		// Create a new app object for each connection, copy global data like db connections | 		// Create a new app object for each connection, copy global data like db connections | ||||||
| 		mut request_app := &T{} | 		mut request_app := &T{} | ||||||
|  | @ -311,16 +311,16 @@ pub fn run<T>(global_app &T, port int) { | ||||||
| 		request_app.Context = global_app.Context // copy the context ref that contains static files map etc | 		request_app.Context = global_app.Context // copy the context ref that contains static files map etc | ||||||
| 		mut conn := l.accept() or { | 		mut conn := l.accept() or { | ||||||
| 			// failures should not panic | 			// failures should not panic | ||||||
| 			eprintln('accept() failed with error: $err.msg()') | 			eprintln('accept() failed with error: ${err.msg()}') | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		go handle_conn<T>(mut conn, mut request_app, routes) | 		spawn handle_conn[T](mut conn, mut request_app, routes) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // handle_conn handles a connection | // handle_conn handles a connection | ||||||
| [manualfree] | [manualfree] | ||||||
| fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) { | fn handle_conn[T](mut conn net.TcpConn, mut app T, routes map[string]Route) { | ||||||
| 	conn.set_read_timeout(30 * time.second) | 	conn.set_read_timeout(30 * time.second) | ||||||
| 	conn.set_write_timeout(30 * time.second) | 	conn.set_write_timeout(30 * time.second) | ||||||
| 
 | 
 | ||||||
|  | @ -362,8 +362,8 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) { | ||||||
| 	// Request parse | 	// Request parse | ||||||
| 	head := http.parse_request_head(mut reader) or { | 	head := http.parse_request_head(mut reader) or { | ||||||
| 		// Prevents errors from being thrown when BufferedReader is empty | 		// Prevents errors from being thrown when BufferedReader is empty | ||||||
| 		if '$err' != 'none' { | 		if '${err}' != 'none' { | ||||||
| 			eprintln('error parsing request head: $err') | 			eprintln('error parsing request head: ${err}') | ||||||
| 		} | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | @ -371,7 +371,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) { | ||||||
| 	// The healthcheck spams the logs, which isn't very useful | 	// The healthcheck spams the logs, which isn't very useful | ||||||
| 	if head.url != '/health' { | 	if head.url != '/health' { | ||||||
| 		lock app.logger { | 		lock app.logger { | ||||||
| 			app.logger.debug('$head.method $head.url $head.version') | 			app.logger.debug('${head.method} ${head.url} ${head.version}') | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -385,7 +385,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) { | ||||||
| 
 | 
 | ||||||
| 	// URL Parse | 	// URL Parse | ||||||
| 	url := urllib.parse(head.url) or { | 	url := urllib.parse(head.url) or { | ||||||
| 		eprintln('error parsing path: $err') | 		eprintln('error parsing path: ${err}') | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -423,7 +423,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) { | ||||||
| 	$for method in T.methods { | 	$for method in T.methods { | ||||||
| 		$if method.return_type is Result { | 		$if method.return_type is Result { | ||||||
| 			route := routes[method.name] or { | 			route := routes[method.name] or { | ||||||
| 				eprintln('parsed attributes for the `$method.name` are not found, skipping...') | 				eprintln('parsed attributes for the `${method.name}` are not found, skipping...') | ||||||
| 				Route{} | 				Route{} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -455,7 +455,7 @@ fn handle_conn<T>(mut conn net.TcpConn, mut app T, routes map[string]Route) { | ||||||
| 
 | 
 | ||||||
| 					method_args := params.clone() | 					method_args := params.clone() | ||||||
| 					if method_args.len != method.args.len { | 					if method_args.len != method.args.len { | ||||||
| 						eprintln('warning: uneven parameters count ($method.args.len) in `$method.name`, compared to the web route `$method.attrs` ($method_args.len)') | 						eprintln('warning: uneven parameters count (${method.args.len}) in `${method.name}`, compared to the web route `${method.attrs}` (${method_args.len})') | ||||||
| 					} | 					} | ||||||
| 					app.$method(method_args) | 					app.$method(method_args) | ||||||
| 					return | 					return | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue