diff --git a/.gitignore b/.gitignore index aaec9ef..a2804fe 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,6 @@ gdb.txt # Generated docs _docs/ -docs/resources/_gen/ /man/ # VLS logs diff --git a/.woodpecker/arch-rel.yml b/.woodpecker/arch-rel.yml index f727486..f5f228e 100644 --- a/.woodpecker/arch-rel.yml +++ b/.woodpecker/arch-rel.yml @@ -9,7 +9,7 @@ skip_clone: true pipeline: build: - image: 'git.rustybever.be/vieter-v/vieter-builder' + image: 'menci/archlinuxarm:base-devel' commands: # 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 diff --git a/.woodpecker/arch.yml b/.woodpecker/arch.yml index f5f8432..8f1a6ff 100644 --- a/.woodpecker/arch.yml +++ b/.woodpecker/arch.yml @@ -9,7 +9,7 @@ skip_clone: true pipeline: build: - image: 'git.rustybever.be/vieter-v/vieter-builder' + image: 'menci/archlinuxarm:base-devel' commands: # 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 diff --git a/.woodpecker/build.yml b/.woodpecker/build.yml index f10e2a5..9ee8085 100644 --- a/.woodpecker/build.yml +++ b/.woodpecker/build.yml @@ -1,5 +1,5 @@ variables: - - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2' + - &vlang_image 'chewingbever/vlang:0.3' matrix: PLATFORM: diff --git a/.woodpecker/docs.yml b/.woodpecker/docs.yml index cf4874e..048b1ad 100644 --- a/.woodpecker/docs.yml +++ b/.woodpecker/docs.yml @@ -1,5 +1,5 @@ variables: - - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2' + - &vlang_image 'chewingbever/vlang:0.3' platform: 'linux/amd64' branches: diff --git a/.woodpecker/gitea.yml b/.woodpecker/gitea.yml index 9034f33..8e3b9d4 100644 --- a/.woodpecker/gitea.yml +++ b/.woodpecker/gitea.yml @@ -1,5 +1,5 @@ variables: - - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2' + - &vlang_image 'chewingbever/vlang:0.3' platform: 'linux/amd64' branches: [ 'main' ] diff --git a/.woodpecker/lint.yml b/.woodpecker/lint.yml index ec64d13..c80ce33 100644 --- a/.woodpecker/lint.yml +++ b/.woodpecker/lint.yml @@ -1,5 +1,5 @@ variables: - - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2' + - &vlang_image 'chewingbever/vlang:0.3' # These checks already get performed on the feature branches branches: @@ -7,21 +7,10 @@ branches: platform: 'linux/amd64' pipeline: - # vfmt seems to get confused if these aren't present - install-modules: - image: *vlang_image - pull: true - commands: - - export VMODULES=$PWD/.vmodules - - 'cd src && v install' - when: - event: [pull_request] - lint: image: *vlang_image pull: true commands: - - export VMODULES=$PWD/.vmodules - make lint when: - event: [pull_request] + event: [ pull_request ] diff --git a/.woodpecker/man.yml b/.woodpecker/man.yml index 8c6ca06..86a1bd8 100644 --- a/.woodpecker/man.yml +++ b/.woodpecker/man.yml @@ -1,5 +1,5 @@ variables: - - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2' + - &vlang_image 'chewingbever/vlang:0.3' platform: 'linux/amd64' branches: diff --git a/.woodpecker/test.yml b/.woodpecker/test.yml index 39cb9f9..08b7534 100644 --- a/.woodpecker/test.yml +++ b/.woodpecker/test.yml @@ -1,5 +1,5 @@ variables: - - &vlang_image 'git.rustybever.be/chewing_bever/vlang:0.3.2' + - &vlang_image 'chewingbever/vlang:0.3' matrix: PLATFORM: diff --git a/CHANGELOG.md b/CHANGELOG.md index e2d6987..426ac8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -* Migrated codebase to V 0.3.2 * Cron expression parser now uses bitfields instead of bool arrays ## [0.4.0](https://git.rustybever.be/vieter-v/vieter/src/tag/0.4.0) diff --git a/Dockerfile b/Dockerfile index 210ae66..7aed917 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM git.rustybever.be/chewing_bever/vlang:0.3.2 AS builder +FROM chewingbever/vlang:0.3 AS builder ARG TARGETPLATFORM ARG CI_COMMIT_SHA diff --git a/Makefile b/Makefile index e716807..69bd795 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ SRC_DIR := src SOURCES != find '$(SRC_DIR)' -iname '*.v' V_PATH ?= v -V := $(V_PATH) -showcc -gc boehm -W -d use_openssl +V := $(V_PATH) -showcc -gc boehm all: vieter @@ -92,9 +92,9 @@ clean: .PHONY: autofree autofree: afvieter afvieter: $(SOURCES) - $(V) -showcc -autofree -o afvieter $(SRC_DIR) + $(V_PATH) -showcc -autofree -o afvieter $(SRC_DIR) .PHONY: skip-unused skip-unused: suvieter suvieter: $(SOURCES) - $(V) -skip-unused -o suvieter $(SRC_DIR) + $(V_PATH) -showcc -skip-unused -o suvieter $(SRC_DIR) diff --git a/src/build/build.v b/src/build/build.v index 247df6e..2ad70a6 100644 --- a/src/build/build.v +++ b/src/build/build.v @@ -1,6 +1,6 @@ module build -import docker +import vieter_v.docker import encoding.base64 import time import os @@ -21,8 +21,8 @@ const ( // system, install some necessary packages & creates a non-root user to run // makepkg with. The base image should be some Linux distribution that uses // Pacman as its package manager. -pub fn create_build_image(base_image string) !string { - mut dd := docker.new_conn()! +pub fn create_build_image(base_image string) ?string { + mut dd := docker.new_conn()? defer { dd.close() or {} @@ -57,15 +57,15 @@ pub fn create_build_image(base_image string) !string { image_tag := if image_parts.len > 1 { image_parts[1] } else { 'latest' } // We pull the provided image - dd.pull_image(image_name, image_tag)! + dd.pull_image(image_name, image_tag)? - id := dd.container_create(c)!.id - // id := docker.create_container(c)! - dd.container_start(id)! + id := dd.container_create(c)?.id + // id := docker.create_container(c)? + dd.container_start(id)? // This loop waits until the container has stopped, so we can remove it after for { - data := dd.container_inspect(id)! + data := dd.container_inspect(id)? if !data.state.running { break @@ -79,8 +79,8 @@ pub fn create_build_image(base_image string) !string { // TODO also add the base image's name into the image name to prevent // conflicts. tag := time.sys_mono_now().str() - image := dd.create_image_from_container(id, 'vieter-build', tag)! - dd.container_remove(id)! + image := dd.create_image_from_container(id, 'vieter-build', tag)? + dd.container_remove(id)? return image.id } @@ -96,8 +96,8 @@ pub: // build_target builds, packages & publishes a given Arch package based on the // provided target. The base image ID should be of an image previously created // by create_build_image. It returns the logs of the container. -pub fn build_target(address string, api_key string, base_image_id string, target &Target) !BuildResult { - mut dd := docker.new_conn()! +pub fn build_target(address string, api_key string, base_image_id string, target &Target) ?BuildResult { + mut dd := docker.new_conn()? defer { dd.close() or {} @@ -125,25 +125,25 @@ pub fn build_target(address string, api_key string, base_image_id string, target user: '0:0' } - id := dd.container_create(c)!.id - dd.container_start(id)! + id := dd.container_create(c)?.id + dd.container_start(id)? - mut data := dd.container_inspect(id)! + mut data := dd.container_inspect(id)? // This loop waits until the container has stopped, so we can remove it after for data.state.running { time.sleep(1 * time.second) - data = dd.container_inspect(id)! + data = dd.container_inspect(id)? } - mut logs_stream := dd.container_get_logs(id)! + mut logs_stream := dd.container_get_logs(id)? // Read in the entire stream mut logs_builder := strings.new_builder(10 * 1024) - util.reader_to_writer(mut logs_stream, mut logs_builder)! + util.reader_to_writer(mut logs_stream, mut logs_builder)? - dd.container_remove(id)! + dd.container_remove(id)? return BuildResult{ start_time: data.state.start_time diff --git a/src/client/client.v b/src/client/client.v index aa6094a..d68ff18 100644 --- a/src/client/client.v +++ b/src/client/client.v @@ -21,7 +21,7 @@ pub fn new(address string, api_key string) Client { // 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. -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' if params.len > 0 { @@ -38,33 +38,31 @@ fn (c &Client) send_request_raw(method Method, url string, params map[string]str full_url = '$full_url?$params_str' } - // Looking at the source code, this function doesn't actually fail, so I'm - // not sure why it returns an optional - mut req := http.new_request(method, full_url, body) or { return error('') } - req.add_custom_header('X-Api-Key', c.api_key)! + mut req := http.new_request(method, full_url, body)? + req.add_custom_header('X-Api-Key', c.api_key)? - res := req.do()! + res := req.do()? return res } // send_request just calls send_request_with_body with an empty body. -fn (c &Client) send_request(method Method, url string, params map[string]string) !Response { +fn (c &Client) send_request(method Method, url string, params map[string]string) ?Response { return c.send_request_with_body(method, url, params, '') } // send_request_with_body calls send_request_raw_response & parses its // output as a Response object. -fn (c &Client) send_request_with_body(method Method, url string, params map[string]string, body string) !Response { - res_text := c.send_request_raw_response(method, url, params, body)! - data := json.decode(Response, res_text)! +fn (c &Client) send_request_with_body(method Method, url string, params map[string]string, body string) ?Response { + res_text := c.send_request_raw_response(method, url, params, body)? + data := json.decode(Response, res_text)? return data } // send_request_raw_response returns the raw text response for an HTTP request. -fn (c &Client) send_request_raw_response(method Method, url string, params map[string]string, body string) !string { - res := c.send_request_raw(method, url, params, body)! +fn (c &Client) send_request_raw_response(method Method, url string, params map[string]string, body string) ?string { + res := c.send_request_raw(method, url, params, body)? return res.body } diff --git a/src/client/logs.v b/src/client/logs.v index eaddc8c..b414245 100644 --- a/src/client/logs.v +++ b/src/client/logs.v @@ -6,40 +6,40 @@ import web.response { Response } import time // get_build_logs returns all build logs. -pub fn (c &Client) get_build_logs(filter BuildLogFilter) !Response<[]BuildLog> { +pub fn (c &Client) get_build_logs(filter BuildLogFilter) ?Response<[]BuildLog> { params := models.params_from(filter) - data := c.send_request<[]BuildLog>(Method.get, '/api/v1/logs', params)! + data := c.send_request<[]BuildLog>(Method.get, '/api/v1/logs', params)? return data } // get_build_logs_for_target returns all build logs for a given target. -pub fn (c &Client) get_build_logs_for_target(target_id int) !Response<[]BuildLog> { +pub fn (c &Client) get_build_logs_for_target(target_id int) ?Response<[]BuildLog> { params := { 'repo': target_id.str() } - data := c.send_request<[]BuildLog>(Method.get, '/api/v1/logs', params)! + data := c.send_request<[]BuildLog>(Method.get, '/api/v1/logs', params)? return data } // get_build_log returns a specific build log. -pub fn (c &Client) get_build_log(id int) !Response { - data := c.send_request(Method.get, '/api/v1/logs/$id', {})! +pub fn (c &Client) get_build_log(id int) ?Response { + data := c.send_request(Method.get, '/api/v1/logs/$id', {})? return data } // get_build_log_content returns the contents of the build log file. -pub fn (c &Client) get_build_log_content(id int) !string { - data := c.send_request_raw_response(Method.get, '/api/v1/logs/$id/content', {}, '')! +pub fn (c &Client) get_build_log_content(id int) ?string { + data := c.send_request_raw_response(Method.get, '/api/v1/logs/$id/content', {}, '')? return data } // 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 { +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 { params := { 'target': target_id.str() 'startTime': start_time.unix_time().str() @@ -48,7 +48,7 @@ pub fn (c &Client) add_build_log(target_id int, start_time time.Time, end_time t 'exitCode': exit_code.str() } - data := c.send_request_with_body(Method.post, '/api/v1/logs', params, content)! + data := c.send_request_with_body(Method.post, '/api/v1/logs', params, content)? return data } diff --git a/src/client/targets.v b/src/client/targets.v index fd4254c..c5e44fe 100644 --- a/src/client/targets.v +++ b/src/client/targets.v @@ -5,21 +5,21 @@ import net.http { Method } import web.response { Response } // 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) - data := c.send_request<[]Target>(Method.get, '/api/v1/targets', params)! + data := c.send_request<[]Target>(Method.get, '/api/v1/targets', params)? return data.data } // get_all_targets retrieves *all* targs from the API using the default // limit. -pub fn (c &Client) get_all_targets() ![]Target { +pub fn (c &Client) get_all_targets() ?[]Target { mut targets := []Target{} mut offset := u64(0) for { - sub_targets := c.get_targets(offset: offset)! + sub_targets := c.get_targets(offset: offset)? if sub_targets.len == 0 { break @@ -34,8 +34,8 @@ pub fn (c &Client) get_all_targets() ![]Target { } // get_target returns the target for a specific id. -pub fn (c &Client) get_target(id int) !Target { - data := c.send_request(Method.get, '/api/v1/targets/$id', {})! +pub fn (c &Client) get_target(id int) ?Target { + data := c.send_request(Method.get, '/api/v1/targets/$id', {})? return data.data } @@ -49,24 +49,24 @@ pub struct NewTarget { } // add_target adds a new target to the server. -pub fn (c &Client) add_target(t NewTarget) !Response { +pub fn (c &Client) add_target(t NewTarget) ?Response { params := models.params_from(t) - data := c.send_request(Method.post, '/api/v1/targets', params)! + data := c.send_request(Method.post, '/api/v1/targets', params)? return data } // remove_target removes the target with the given id from the server. -pub fn (c &Client) remove_target(id int) !Response { - data := c.send_request(Method.delete, '/api/v1/targets/$id', {})! +pub fn (c &Client) remove_target(id int) ?Response { + data := c.send_request(Method.delete, '/api/v1/targets/$id', {})? return data } // patch_target sends a PATCH request to the given target with the params as // payload. -pub fn (c &Client) patch_target(id int, params map[string]string) !Response { - data := c.send_request(Method.patch, '/api/v1/targets/$id', params)! +pub fn (c &Client) patch_target(id int, params map[string]string) ?Response { + data := c.send_request(Method.patch, '/api/v1/targets/$id', params)? return data } diff --git a/src/console/aur/aur.v b/src/console/aur/aur.v index a6a3324..c98f8e6 100644 --- a/src/console/aur/aur.v +++ b/src/console/aur/aur.v @@ -3,8 +3,8 @@ module aur import cli import console import client -import aur -import conf as vconf +import vieter_v.aur +import vieter_v.conf as vconf struct Config { address string [required] @@ -21,12 +21,12 @@ pub fn cmd() cli.Command { name: 'search' description: 'Search for packages.' required_args: 1 - execute: fn (cmd cli.Command) ! { + execute: fn (cmd cli.Command) ? { c := aur.new() - pkgs := c.search(cmd.args[0])! + pkgs := c.search(cmd.args[0])? data := pkgs.map([it.name, it.description]) - println(console.pretty_table(['name', 'description'], data)!) + println(console.pretty_table(['name', 'description'], data)?) } }, cli.Command{ @@ -34,12 +34,12 @@ pub fn cmd() cli.Command { usage: 'repo pkg-name [pkg-name...]' description: 'Add the given AUR package(s) to Vieter. Non-existent packages will be silently ignored.' required_args: 2 - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? c := aur.new() - pkgs := c.info(cmd.args[1..])! + pkgs := c.info(cmd.args[1..])? vc := client.new(conf.address, conf.api_key) diff --git a/src/console/console.v b/src/console/console.v index 5c40de8..caf4cca 100644 --- a/src/console/console.v +++ b/src/console/console.v @@ -13,7 +13,7 @@ pub fn tabbed_table(data [][]string) string { // pretty_table converts a list of string data into a pretty table. Many thanks // to @hungrybluedev in the Vlang Discord for providing this code! // https://ptb.discord.com/channels/592103645835821068/592106336838352923/970278787143045192 -pub fn pretty_table(header []string, data [][]string) !string { +pub fn pretty_table(header []string, data [][]string) ?string { column_count := header.len mut column_widths := []int{len: column_count, init: header[it].len} @@ -26,7 +26,7 @@ pub fn pretty_table(header []string, data [][]string) !string { } } - single_line_length := arrays.sum(column_widths)! + (column_count + 1) * 3 - 4 + single_line_length := arrays.sum(column_widths)? + (column_count + 1) * 3 - 4 horizontal_line := '+' + strings.repeat(`-`, single_line_length) + '+' mut buffer := strings.new_builder(data.len * single_line_length) @@ -64,12 +64,12 @@ pub fn pretty_table(header []string, data [][]string) !string { // export_man_pages recursively generates all man pages for the given // cli.Command & writes them to the given directory. -pub fn export_man_pages(cmd cli.Command, path string) ! { +pub fn export_man_pages(cmd cli.Command, path string) ? { man := cmd.manpage() os.write_file(os.join_path_single(path, cmd.full_name().replace(' ', '-') + '.1'), - man)! + man)? for sub_cmd in cmd.commands { - export_man_pages(sub_cmd, path)! + export_man_pages(sub_cmd, path)? } } diff --git a/src/console/logs/logs.v b/src/console/logs/logs.v index 1330dd0..41830c2 100644 --- a/src/console/logs/logs.v +++ b/src/console/logs/logs.v @@ -1,7 +1,7 @@ module logs import cli -import conf as vconf +import vieter_v.conf as vconf import client import console import time @@ -63,30 +63,30 @@ pub fn cmd() cli.Command { flag: cli.FlagType.string }, ] - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? mut filter := BuildLogFilter{} - limit := cmd.flags.get_int('limit')! + limit := cmd.flags.get_int('limit')? if limit != 0 { filter.limit = u64(limit) } - offset := cmd.flags.get_int('offset')! + offset := cmd.flags.get_int('offset')? if offset != 0 { filter.offset = u64(offset) } - target_id := cmd.flags.get_int('target')! + target_id := cmd.flags.get_int('target')? if target_id != 0 { filter.target = target_id } tz_offset := time.offset() - if cmd.flags.get_bool('today')! { + if cmd.flags.get_bool('today')? { today := time.now() filter.after = time.new_time(time.Time{ @@ -98,12 +98,12 @@ pub fn cmd() cli.Command { } // The -today flag overwrites any of the other date flags. else { - day_str := cmd.flags.get_string('day')! - before_str := cmd.flags.get_string('before')! - after_str := cmd.flags.get_string('after')! + day_str := cmd.flags.get_string('day')? + before_str := cmd.flags.get_string('before')? + after_str := cmd.flags.get_string('after')? if day_str != '' { - day := time.parse_rfc3339(day_str)! + day := time.parse_rfc3339(day_str)? day_utc := time.new_time(time.Time{ year: day.year month: day.month @@ -118,24 +118,24 @@ pub fn cmd() cli.Command { filter.before = day_utc.add_days(1) } else { if before_str != '' { - filter.before = time.parse(before_str)!.add_seconds(-tz_offset) + filter.before = time.parse(before_str)?.add_seconds(-tz_offset) } if after_str != '' { - filter.after = time.parse(after_str)!.add_seconds(-tz_offset) + filter.after = time.parse(after_str)?.add_seconds(-tz_offset) } } } - if cmd.flags.get_bool('failed')! { + if cmd.flags.get_bool('failed')? { filter.exit_codes = [ '!0', ] } - raw := cmd.flags.get_bool('raw')! + raw := cmd.flags.get_bool('raw')? - list(conf, filter, raw)! + list(conf, filter, raw)? } }, cli.Command{ @@ -143,12 +143,12 @@ pub fn cmd() cli.Command { required_args: 1 usage: 'id' description: 'Show all info for a specific build log.' - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? id := cmd.args[0].int() - info(conf, id)! + info(conf, id)? } }, cli.Command{ @@ -156,12 +156,12 @@ pub fn cmd() cli.Command { required_args: 1 usage: 'id' description: 'Output the content of a build log to stdout.' - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? id := cmd.args[0].int() - content(conf, id)! + content(conf, id)? } }, ] @@ -169,46 +169,46 @@ pub fn cmd() cli.Command { } // print_log_list prints a list of logs. -fn print_log_list(logs []BuildLog, raw bool) ! { +fn print_log_list(logs []BuildLog, raw bool) ? { data := logs.map([it.id.str(), it.target_id.str(), it.start_time.local().str(), it.exit_code.str()]) if raw { println(console.tabbed_table(data)) } else { - println(console.pretty_table(['id', 'target', 'start time', 'exit code'], data)!) + println(console.pretty_table(['id', 'target', 'start time', 'exit code'], data)?) } } // 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) - logs := c.get_build_logs(filter)!.data + logs := c.get_build_logs(filter)?.data - print_log_list(logs, raw)! + print_log_list(logs, raw)? } // list prints a list of all build logs for a given target. -fn list_for_target(conf Config, target_id int, raw bool) ! { +fn list_for_target(conf Config, target_id int, raw bool) ? { c := client.new(conf.address, conf.api_key) - logs := c.get_build_logs_for_target(target_id)!.data + logs := c.get_build_logs_for_target(target_id)?.data - print_log_list(logs, raw)! + print_log_list(logs, raw)? } // 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) - log := c.get_build_log(id)!.data + log := c.get_build_log(id)?.data print(log) } // content outputs the contents of the log file for a given build log to // stdout. -fn content(conf Config, id int) ! { +fn content(conf Config, id int) ? { c := client.new(conf.address, conf.api_key) - content := c.get_build_log_content(id)! + content := c.get_build_log_content(id)? println(content) } diff --git a/src/console/man/man.v b/src/console/man/man.v index 22cb5f7..d91a140 100644 --- a/src/console/man/man.v +++ b/src/console/man/man.v @@ -11,11 +11,11 @@ pub fn cmd() cli.Command { description: 'Generate all man pages & save them in the given directory.' usage: 'dir' required_args: 1 - execute: fn (cmd cli.Command) ! { + execute: fn (cmd cli.Command) ? { root := cmd.root() - os.mkdir_all(cmd.args[0])! + os.mkdir_all(cmd.args[0])? - console.export_man_pages(root, cmd.args[0])! + console.export_man_pages(root, cmd.args[0])? } } } diff --git a/src/console/schedule/schedule.v b/src/console/schedule/schedule.v index 7ce0516..8fceddd 100644 --- a/src/console/schedule/schedule.v +++ b/src/console/schedule/schedule.v @@ -18,11 +18,11 @@ pub fn cmd() cli.Command { default_value: ['5'] }, ] - execute: fn (cmd cli.Command) ! { - ce := parse_expression(cmd.args.join(' '))! - count := cmd.flags.get_int('count')! + execute: fn (cmd cli.Command) ? { + ce := parse_expression(cmd.args.join(' '))? + count := cmd.flags.get_int('count')? - for t in ce.next_n(time.now(), count)! { + for t in ce.next_n(time.now(), count)? { println(t) } } diff --git a/src/console/targets/build.v b/src/console/targets/build.v index 9368558..6337aa3 100644 --- a/src/console/targets/build.v +++ b/src/console/targets/build.v @@ -1,34 +1,34 @@ module targets import client -import docker +import vieter_v.docker import os import build // build locally builds the target with the given id. -fn build(conf Config, target_id int) ! { +fn build(conf Config, target_id int) ? { c := client.new(conf.address, conf.api_key) - target := c.get_target(target_id)! + target := c.get_target(target_id)? build_arch := os.uname().machine println('Creating base image...') - image_id := build.create_build_image(conf.base_image)! + image_id := build.create_build_image(conf.base_image)? println('Running build...') - res := build.build_target(conf.address, conf.api_key, image_id, target)! + res := build.build_target(conf.address, conf.api_key, image_id, target)? println('Removing build image...') - mut dd := docker.new_conn()! + mut dd := docker.new_conn()? defer { dd.close() or {} } - dd.remove_image(image_id)! + dd.remove_image(image_id)? println('Uploading logs to Vieter...') c.add_build_log(target.id, res.start_time, res.end_time, build_arch, res.exit_code, - res.logs)! + res.logs)? } diff --git a/src/console/targets/targets.v b/src/console/targets/targets.v index 521ca23..5640011 100644 --- a/src/console/targets/targets.v +++ b/src/console/targets/targets.v @@ -1,7 +1,7 @@ module targets import cli -import conf as vconf +import vieter_v.conf as vconf import cron.expression { parse_expression } import client { NewTarget } import console @@ -39,30 +39,30 @@ pub fn cmd() cli.Command { flag: cli.FlagType.string }, ] - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? mut filter := TargetFilter{} - limit := cmd.flags.get_int('limit')! + limit := cmd.flags.get_int('limit')? if limit != 0 { filter.limit = u64(limit) } - offset := cmd.flags.get_int('offset')! + offset := cmd.flags.get_int('offset')? if offset != 0 { filter.offset = u64(offset) } - repo := cmd.flags.get_string('repo')! + repo := cmd.flags.get_string('repo')? if repo != '' { filter.repo = repo } - raw := cmd.flags.get_bool('raw')! + raw := cmd.flags.get_bool('raw')? - list(conf, filter, raw)! + list(conf, filter, raw)? } }, cli.Command{ @@ -83,20 +83,20 @@ pub fn cmd() cli.Command { flag: cli.FlagType.string }, ] - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? t := NewTarget{ - kind: cmd.flags.get_string('kind')! + kind: cmd.flags.get_string('kind')? url: cmd.args[0] repo: cmd.args[1] branch: cmd.flags.get_string('branch') or { '' } } - raw := cmd.flags.get_bool('raw')! + raw := cmd.flags.get_bool('raw')? - add(conf, t, raw)! + add(conf, t, raw)? } }, cli.Command{ @@ -104,11 +104,11 @@ pub fn cmd() cli.Command { required_args: 1 usage: 'id' description: 'Remove a target that matches the given id.' - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? - remove(conf, cmd.args[0])! + remove(conf, cmd.args[0])? } }, cli.Command{ @@ -116,11 +116,11 @@ pub fn cmd() cli.Command { required_args: 1 usage: 'id' description: 'Show detailed information for the target matching the id.' - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? - info(conf, cmd.args[0])! + info(conf, cmd.args[0])? } }, cli.Command{ @@ -160,9 +160,9 @@ pub fn cmd() cli.Command { flag: cli.FlagType.string }, ] - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? found := cmd.flags.get_all_found() @@ -170,11 +170,11 @@ pub fn cmd() cli.Command { for f in found { if f.name != 'config-file' { - params[f.name] = f.get_string()! + params[f.name] = f.get_string()? } } - patch(conf, cmd.args[0], params)! + patch(conf, cmd.args[0], params)? } }, cli.Command{ @@ -182,11 +182,11 @@ pub fn cmd() cli.Command { required_args: 1 usage: 'id' description: 'Build the target with the given id & publish it.' - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? - build(conf, cmd.args[0].int())! + build(conf, cmd.args[0].int())? } }, ] @@ -197,22 +197,22 @@ pub fn cmd() cli.Command { // ID. If multiple or none are found, an error is raised. // 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) - repos := c.get_targets(filter)! + repos := c.get_targets(filter)? data := repos.map([it.id.str(), it.kind, it.url, it.repo]) if raw { println(console.tabbed_table(data)) } else { - println(console.pretty_table(['id', 'kind', 'url', 'repo'], data)!) + println(console.pretty_table(['id', 'kind', 'url', 'repo'], data)?) } } // add adds a new repository 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) - res := c.add_target(t)! + res := c.add_target(t)? if raw { println(res.data) @@ -222,18 +222,18 @@ fn add(conf Config, t &NewTarget, raw bool) ! { } // remove removes a repository from the server's list. -fn remove(conf Config, id string) ! { +fn remove(conf Config, id string) ? { id_int := id.int() if id_int != 0 { c := client.new(conf.address, conf.api_key) - res := c.remove_target(id_int)! + res := c.remove_target(id_int)? println(res.message) } } // patch patches a given repository 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 // invalid one to the server. if 'schedule' in params && params['schedule'] != '' { @@ -245,14 +245,14 @@ fn patch(conf Config, id string, params map[string]string) ! { id_int := id.int() if id_int != 0 { c := client.new(conf.address, conf.api_key) - res := c.patch_target(id_int, params)! + res := c.patch_target(id_int, params)? println(res.message) } } // info shows detailed information for a given repo. -fn info(conf Config, id string) ! { +fn info(conf Config, id string) ? { id_int := id.int() if id_int == 0 { @@ -260,6 +260,6 @@ fn info(conf Config, id string) ! { } c := client.new(conf.address, conf.api_key) - repo := c.get_target(id_int)! + repo := c.get_target(id_int)? println(repo) } diff --git a/src/cron/cli.v b/src/cron/cli.v index 16a3537..4d95833 100644 --- a/src/cron/cli.v +++ b/src/cron/cli.v @@ -1,7 +1,7 @@ module cron import cli -import conf as vconf +import vieter_v.conf as vconf struct Config { pub: @@ -22,11 +22,11 @@ pub fn cmd() cli.Command { return cli.Command{ name: 'cron' description: 'Start the cron service that periodically runs builds.' - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? - cron(conf)! + cron(conf)? } } } diff --git a/src/cron/cron.v b/src/cron/cron.v index f1d6b7b..5f128cf 100644 --- a/src/cron/cron.v +++ b/src/cron/cron.v @@ -8,7 +8,7 @@ import os const log_file_name = 'vieter.cron.log' // cron starts a cron daemon & starts periodically scheduling builds. -pub fn cron(conf Config) ! { +pub fn cron(conf Config) ? { // Configure logger log_level := log.level_from_tag(conf.log_level) or { return error('Invalid log level. The allowed values are FATAL, ERROR, WARN, INFO & DEBUG.') @@ -27,7 +27,7 @@ pub fn cron(conf Config) ! { } mut d := daemon.init_daemon(logger, conf.address, conf.api_key, conf.base_image, ce, - conf.max_concurrent_builds, conf.api_update_frequency, conf.image_rebuild_frequency)! + conf.max_concurrent_builds, conf.api_update_frequency, conf.image_rebuild_frequency)? d.run() } diff --git a/src/cron/daemon/daemon.v b/src/cron/daemon/daemon.v index 0d30a23..934d35a 100644 --- a/src/cron/daemon/daemon.v +++ b/src/cron/daemon/daemon.v @@ -6,7 +6,7 @@ import datatypes { MinHeap } import cron.expression { CronExpression, parse_expression } import math import build -import docker +import vieter_v.docker import os import client import models { Target } @@ -53,7 +53,7 @@ mut: // init_daemon initializes a new Daemon object. It renews the targets & // populates the build queue for the first time. -pub fn init_daemon(logger log.Log, address string, api_key string, base_image string, global_schedule CronExpression, max_concurrent_builds int, api_update_frequency int, image_rebuild_frequency int) !Daemon { +pub fn init_daemon(logger log.Log, address string, api_key string, base_image string, global_schedule CronExpression, max_concurrent_builds int, api_update_frequency int, image_rebuild_frequency int) ?Daemon { mut d := Daemon{ client: client.new(address, api_key) base_image: base_image @@ -207,7 +207,7 @@ fn (mut d Daemon) renew_queue() { // For some reason, using // ```v - // for d.queue.len() > 0 && d.queue.peek() !.timestamp < now { + // for d.queue.len() > 0 && d.queue.peek() ?.timestamp < now { //``` // here causes the function to prematurely just exit, without any errors or anything, very weird // https://github.com/vlang/v/issues/14042 diff --git a/src/cron/daemon/log.v b/src/cron/daemon/log.v index 95a50e7..003898b 100644 --- a/src/cron/daemon/log.v +++ b/src/cron/daemon/log.v @@ -3,33 +3,33 @@ module daemon import log // log reate a log message with the given level -pub fn (mut d Daemon) log(msg string, level log.Level) { +pub fn (mut d Daemon) log(msg &string, level log.Level) { lock d.logger { d.logger.send_output(msg, level) } } // lfatal create a log message with the fatal level -pub fn (mut d Daemon) lfatal(msg string) { +pub fn (mut d Daemon) lfatal(msg &string) { d.log(msg, log.Level.fatal) } // lerror create a log message with the error level -pub fn (mut d Daemon) lerror(msg string) { +pub fn (mut d Daemon) lerror(msg &string) { d.log(msg, log.Level.error) } // lwarn create a log message with the warn level -pub fn (mut d Daemon) lwarn(msg string) { +pub fn (mut d Daemon) lwarn(msg &string) { d.log(msg, log.Level.warn) } // linfo create a log message with the info level -pub fn (mut d Daemon) linfo(msg string) { +pub fn (mut d Daemon) linfo(msg &string) { d.log(msg, log.Level.info) } // ldebug create a log message with the debug level -pub fn (mut d Daemon) ldebug(msg string) { +pub fn (mut d Daemon) ldebug(msg &string) { d.log(msg, log.Level.debug) } diff --git a/src/cron/expression/expression.v b/src/cron/expression/expression.v index c3ff8c5..092375a 100644 --- a/src/cron/expression/expression.v +++ b/src/cron/expression/expression.v @@ -12,7 +12,7 @@ pub struct CronExpression { // next calculates the earliest time this cron expression is valid. It will // always pick a moment in the future, even if ref matches completely up to the // minute. This function conciously does not take gap years into account. -pub fn (ce &CronExpression) next(ref time.Time) !time.Time { +pub fn (ce &CronExpression) next(ref time.Time) ?time.Time { // If the given ref matches the next cron occurence up to the minute, it // will return that value. Because we always want to return a value in the // future, we artifically shift the ref 60 seconds to make sure we always @@ -117,19 +117,19 @@ pub fn (ce &CronExpression) next(ref time.Time) !time.Time { // next_from_now returns the result of ce.next(ref) where ref is the result of // time.now(). -pub fn (ce &CronExpression) next_from_now() !time.Time { +pub fn (ce &CronExpression) next_from_now() ?time.Time { return ce.next(time.now()) } // next_n returns the n next occurences of the expression, given a starting // time. -pub fn (ce &CronExpression) next_n(ref time.Time, n int) ![]time.Time { +pub fn (ce &CronExpression) next_n(ref time.Time, n int) ?[]time.Time { mut times := []time.Time{cap: n} - times << ce.next(ref)! + times << ce.next(ref)? for i in 1 .. n { - times << ce.next(times[i - 1])! + times << ce.next(times[i - 1])? } return times diff --git a/src/cron/expression/expression_parse.v b/src/cron/expression/expression_parse.v index 4aaec5b..b0cbd5b 100644 --- a/src/cron/expression/expression_parse.v +++ b/src/cron/expression/expression_parse.v @@ -4,7 +4,7 @@ import bitfield // parse_range parses a given string into a range of sorted integers. Its // result is a BitField with set bits for all numbers in the result. -fn parse_range(s string, min int, max int) !bitfield.BitField { +fn parse_range(s string, min int, max int) ?bitfield.BitField { mut start := min mut end := max mut interval := 1 @@ -98,11 +98,11 @@ fn bf_to_ints(bf bitfield.BitField, min int) []int { // parse_part parses a given part of a cron expression & returns the // corresponding array of ints. -fn parse_part(s string, min int, max int) ![]int { +fn parse_part(s string, min int, max int) ?[]int { mut bf := bitfield.new(max - min + 1) for range in s.split(',') { - bf2 := parse_range(range, min, max)! + bf2 := parse_range(range, min, max)? bf = bitfield.bf_or(bf, bf2) } @@ -111,7 +111,7 @@ fn parse_part(s string, min int, max int) ![]int { // parse_expression parses an entire cron expression string into a // CronExpression object, if possible. -pub fn parse_expression(exp string) !CronExpression { +pub fn parse_expression(exp string) ?CronExpression { // The filter allows for multiple spaces between parts mut parts := exp.split(' ').filter(it != '') diff --git a/src/cron/expression/expression_parse_test.v b/src/cron/expression/expression_parse_test.v index f8eee62..5da3b3b 100644 --- a/src/cron/expression/expression_parse_test.v +++ b/src/cron/expression/expression_parse_test.v @@ -9,81 +9,81 @@ fn parse_range_error(s string, min int, max int) string { } // =====parse_range===== -fn test_range_star_range() ! { - bf := parse_range('*', 0, 5)! +fn test_range_star_range() ? { + bf := parse_range('*', 0, 5)? assert bf_to_ints(bf, 0) == [0, 1, 2, 3, 4, 5] } -fn test_range_number() ! { - bf := parse_range('4', 0, 5)! +fn test_range_number() ? { + bf := parse_range('4', 0, 5)? assert bf_to_ints(bf, 0) == [4] } -fn test_range_number_too_large() ! { +fn test_range_number_too_large() ? { assert parse_range_error('10', 0, 6) == 'Out of range.' } -fn test_range_number_too_small() ! { +fn test_range_number_too_small() ? { assert parse_range_error('0', 2, 6) == 'Out of range.' } -fn test_range_number_invalid() ! { +fn test_range_number_invalid() ? { assert parse_range_error('x', 0, 6) == 'Invalid number.' } -fn test_range_step_star_1() ! { +fn test_range_step_star_1() ? { bf := parse_range('*/4', 0, 20)? assert bf_to_ints(bf, 0) == [0, 4, 8, 12, 16, 20] } -fn test_range_step_star_2() ! { - bf := parse_range('*/3', 1, 8)! +fn test_range_step_star_2() ? { + bf := parse_range('*/3', 1, 8)? assert bf_to_ints(bf, 1) == [1, 4, 7] } -fn test_range_step_star_too_large() ! { +fn test_range_step_star_too_large() ? { assert parse_range_error('*/21', 0, 20) == 'Step size too large.' } -fn test_range_step_zero() ! { +fn test_range_step_zero() ? { assert parse_range_error('*/0', 0, 20) == 'Step size zero not allowed.' } -fn test_range_step_number() ! { - bf := parse_range('5/4', 2, 22)! +fn test_range_step_number() ? { + bf := parse_range('5/4', 2, 22)? assert bf_to_ints(bf, 2) == [5, 9, 13, 17, 21] } -fn test_range_step_number_too_large() ! { +fn test_range_step_number_too_large() ? { assert parse_range_error('10/4', 0, 5) == 'Out of range.' } -fn test_range_step_number_too_small() ! { +fn test_range_step_number_too_small() ? { assert parse_range_error('2/4', 5, 10) == 'Out of range.' } -fn test_range_dash() ! { - bf := parse_range('4-8', 0, 9)! +fn test_range_dash() ? { + bf := parse_range('4-8', 0, 9)? assert bf_to_ints(bf, 0) == [4, 5, 6, 7, 8] } -fn test_range_dash_step() ! { +fn test_range_dash_step() ? { bf := parse_range('4-8/2', 0, 9)? assert bf_to_ints(bf, 0) == [4, 6, 8] } // =====parse_part===== -fn test_part_single() ! { - assert parse_part('*', 0, 5)! == [0, 1, 2, 3, 4, 5] +fn test_part_single() ? { + assert parse_part('*', 0, 5)? == [0, 1, 2, 3, 4, 5] } -fn test_part_multiple() ! { - assert parse_part('*/2,2/3', 1, 8)! == [1, 2, 3, 5, 7, 8] +fn test_part_multiple() ? { + assert parse_part('*/2,2/3', 1, 8)? == [1, 2, 3, 5, 7, 8] } diff --git a/src/cron/expression/expression_test.v b/src/cron/expression/expression_test.v index 82bf959..9e25e92 100644 --- a/src/cron/expression/expression_test.v +++ b/src/cron/expression/expression_test.v @@ -2,12 +2,12 @@ module expression import time { parse } -fn util_test_time(exp string, t1_str string, t2_str string) ! { - ce := parse_expression(exp)! - t1 := parse(t1_str)! - t2 := parse(t2_str)! +fn util_test_time(exp string, t1_str string, t2_str string) ? { + ce := parse_expression(exp)? + t1 := parse(t1_str)? + t2 := parse(t2_str)? - t3 := ce.next(t1)! + t3 := ce.next(t1)? assert t2.year == t3.year assert t2.month == t3.month @@ -16,19 +16,19 @@ fn util_test_time(exp string, t1_str string, t2_str string) ! { assert t2.minute == t3.minute } -fn test_next_simple() ! { +fn test_next_simple() ? { // Very simple - util_test_time('0 3', '2002-01-01 00:00:00', '2002-01-01 03:00:00')! + util_test_time('0 3', '2002-01-01 00:00:00', '2002-01-01 03:00:00')? // Overlap to next day - util_test_time('0 3', '2002-01-01 03:00:00', '2002-01-02 03:00:00')! - util_test_time('0 3', '2002-01-01 04:00:00', '2002-01-02 03:00:00')! + util_test_time('0 3', '2002-01-01 03:00:00', '2002-01-02 03:00:00')? + util_test_time('0 3', '2002-01-01 04:00:00', '2002-01-02 03:00:00')? - util_test_time('0 3/4', '2002-01-01 04:00:00', '2002-01-01 07:00:00')! + util_test_time('0 3/4', '2002-01-01 04:00:00', '2002-01-01 07:00:00')? // Overlap to next month - util_test_time('0 3', '2002-11-31 04:00:00', '2002-12-01 03:00:00')! + util_test_time('0 3', '2002-11-31 04:00:00', '2002-12-01 03:00:00')? // Overlap to next year - util_test_time('0 3', '2002-12-31 04:00:00', '2003-01-01 03:00:00')! + util_test_time('0 3', '2002-12-31 04:00:00', '2003-01-01 03:00:00')? } diff --git a/src/db/db.v b/src/db/db.v index b8b861a..9459c05 100644 --- a/src/db/db.v +++ b/src/db/db.v @@ -26,8 +26,8 @@ const ( ) // init initializes a database & adds the correct tables. -pub fn init(db_path string) !VieterDb { - conn := sqlite.connect(db_path)! +pub fn init(db_path string) ?VieterDb { + conn := sqlite.connect(db_path)? sql conn { create table MigrationVersion diff --git a/src/package/format.v b/src/package/format.v index a81d327..8ac432e 100644 --- a/src/package/format.v +++ b/src/package/format.v @@ -27,7 +27,7 @@ pub fn (pkg &Pkg) filename() string { } // to_desc returns a desc file valid string representation -pub fn (pkg &Pkg) to_desc() !string { +pub fn (pkg &Pkg) to_desc() ?string { p := pkg.info // filename @@ -48,7 +48,7 @@ pub fn (pkg &Pkg) to_desc() !string { desc += format_entry('CSIZE', p.csize.str()) desc += format_entry('ISIZE', p.size.str()) - sha256sum := pkg.checksum()! + sha256sum := pkg.checksum()? desc += format_entry('SHA256SUM', sha256sum) diff --git a/src/package/package.v b/src/package/package.v index 4518ffd..4f9eda6 100644 --- a/src/package/package.v +++ b/src/package/package.v @@ -43,12 +43,12 @@ pub mut: } // checksum calculates the sha256 hash of the package -pub fn (p &Pkg) checksum() !string { +pub fn (p &Pkg) checksum() ?string { return util.hash_file(p.path) } // parse_pkg_info_string parses a PkgInfo object from a string -fn parse_pkg_info_string(pkg_info_str &string) !PkgInfo { +fn parse_pkg_info_string(pkg_info_str &string) ?PkgInfo { mut pkg_info := PkgInfo{} // Iterate over the entire string @@ -101,7 +101,7 @@ fn parse_pkg_info_string(pkg_info_str &string) !PkgInfo { // read_pkg_archive extracts the file list & .PKGINFO contents from an archive // 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) { return error("'$pkg_path' doesn't exist or isn't a file.") } @@ -159,7 +159,7 @@ pub fn read_pkg_archive(pkg_path string) !Pkg { pkg_text := unsafe { buf.vstring_with_len(size).clone() } - pkg_info = parse_pkg_info_string(pkg_text)! + pkg_info = parse_pkg_info_string(pkg_text)? } else { C.archive_read_data_skip(a) } diff --git a/src/repo/add.v b/src/repo/add.v index 8ab3ae1..608ca50 100644 --- a/src/repo/add.v +++ b/src/repo/add.v @@ -29,7 +29,7 @@ pub: } // 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) { os.mkdir_all(repos_dir) or { return error('Failed to create repos directory: $err.msg()') } } @@ -49,27 +49,27 @@ pub fn new(repos_dir string, pkg_dir string, default_arch string) !RepoGroupMana // pkg archive. It's a wrapper around add_pkg_in_repo that parses the archive // file, passes the result to add_pkg_in_repo, and hard links the archive to // 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 { 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)? // If the add was successful, we move the file to the packages directory for arch in archs { repo_pkg_path := os.real_path(os.join_path(r.pkg_dir, repo, arch)) dest_path := os.join_path_single(repo_pkg_path, pkg.filename()) - os.mkdir_all(repo_pkg_path)! + os.mkdir_all(repo_pkg_path)? // We create hard links so that "any" arch packages aren't stored // multiple times - os.link(pkg_path, dest_path)! + os.link(pkg_path, dest_path)? } // After linking, we can remove the original file - os.rm(pkg_path)! + os.rm(pkg_path)? return RepoAddResult{ name: pkg.info.name @@ -85,11 +85,11 @@ pub fn (r &RepoGroupManager) add_pkg_from_path(repo string, pkg_path string) !Re // r.default_arch. If this arch-repo doesn't exist yet, it is created. If the // architecture isn't 'any', the package is only added to the specific // architecture. -fn (r &RepoGroupManager) add_pkg_in_repo(repo string, pkg &package.Pkg) ![]string { +fn (r &RepoGroupManager) add_pkg_in_repo(repo string, pkg &package.Pkg) ?[]string { // A package not of arch 'any' can be handled easily by adding it to the // respective repo if pkg.info.arch != 'any' { - r.add_pkg_in_arch_repo(repo, pkg.info.arch, pkg)! + r.add_pkg_in_arch_repo(repo, pkg.info.arch, pkg)? return [pkg.info.arch] } @@ -104,7 +104,7 @@ fn (r &RepoGroupManager) add_pkg_in_repo(repo string, pkg &package.Pkg) ![]strin // If this is the first package that's added to the repo, the directory // won't exist yet if os.exists(repo_dir) { - arch_repos = os.ls(repo_dir)! + arch_repos = os.ls(repo_dir)? } // The default_arch should always be updated when a package with arch 'any' @@ -118,7 +118,7 @@ fn (r &RepoGroupManager) add_pkg_in_repo(repo string, pkg &package.Pkg) ![]strin // not know which arch-repositories did succeed in adding the package, if // any. for arch in arch_repos { - r.add_pkg_in_arch_repo(repo, arch, pkg)! + r.add_pkg_in_arch_repo(repo, arch, pkg)? } return arch_repos @@ -128,24 +128,24 @@ fn (r &RepoGroupManager) add_pkg_in_repo(repo string, pkg &package.Pkg) ![]strin // arch-repo. It records the package's data in the arch-repo's desc & files // files, and afterwards updates the db & files archives to reflect these // 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') // 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)? os.mkdir_all(pkg_dir) or { return error('Failed to create package directory.') } - os.write_file(os.join_path_single(pkg_dir, 'desc'), pkg.to_desc()!) or { - os.rmdir_all(pkg_dir)! + os.write_file(os.join_path_single(pkg_dir, 'desc'), pkg.to_desc()?) or { + os.rmdir_all(pkg_dir)? return error('Failed to write desc file.') } os.write_file(os.join_path_single(pkg_dir, 'files'), pkg.to_files()) or { - os.rmdir_all(pkg_dir)! + os.rmdir_all(pkg_dir)? return error('Failed to write files file.') } - r.sync(repo, arch)! + r.sync(repo, arch)? } diff --git a/src/repo/remove.v b/src/repo/remove.v index 63866a9..add921c 100644 --- a/src/repo/remove.v +++ b/src/repo/remove.v @@ -5,7 +5,7 @@ import os // 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 // 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, sync bool) ?bool { repo_dir := os.join_path(r.repos_dir, repo, arch) // If the repository doesn't exist yet, the result is automatically false @@ -15,7 +15,7 @@ pub fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, // We iterate over every directory in the repo dir // TODO filter so we only check directories - for d in os.ls(repo_dir)! { + for d in os.ls(repo_dir)? { // Because a repository only allows a single version of each package, // we need only compare whether the name of the package is the same, // not the version. @@ -25,22 +25,22 @@ pub fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, // We lock the mutex here to prevent other routines from creating a // new archive while we remove an entry lock r.mutex { - os.rmdir_all(os.join_path_single(repo_dir, d))! + os.rmdir_all(os.join_path_single(repo_dir, d))? } // Also remove the package archive repo_pkg_dir := os.join_path(r.pkg_dir, repo, arch) - archives := os.ls(repo_pkg_dir)!.filter(it.split('-')#[..-3].join('-') == name) + archives := os.ls(repo_pkg_dir)?.filter(it.split('-')#[..-3].join('-') == name) for archive_name in archives { full_path := os.join_path_single(repo_pkg_dir, archive_name) - os.rm(full_path)! + os.rm(full_path)? } // Sync the db archives if requested if sync { - r.sync(repo, arch)! + r.sync(repo, arch)? } return true @@ -51,7 +51,7 @@ pub fn (r &RepoGroupManager) remove_pkg_from_arch_repo(repo string, arch string, } // remove_arch_repo removes an arch-repo & its packages. -pub fn (r &RepoGroupManager) remove_arch_repo(repo string, arch string) !bool { +pub fn (r &RepoGroupManager) remove_arch_repo(repo string, arch string) ?bool { repo_dir := os.join_path(r.repos_dir, repo, arch) // If the repository doesn't exist yet, the result is automatically false @@ -59,16 +59,16 @@ pub fn (r &RepoGroupManager) remove_arch_repo(repo string, arch string) !bool { return false } - os.rmdir_all(repo_dir)! + os.rmdir_all(repo_dir)? pkg_dir := os.join_path(r.pkg_dir, repo, arch) - os.rmdir_all(pkg_dir)! + os.rmdir_all(pkg_dir)? return true } // remove_repo removes a repo & its packages. -pub fn (r &RepoGroupManager) remove_repo(repo string) !bool { +pub fn (r &RepoGroupManager) remove_repo(repo string) ?bool { repo_dir := os.join_path_single(r.repos_dir, repo) // If the repository doesn't exist yet, the result is automatically false @@ -76,10 +76,10 @@ pub fn (r &RepoGroupManager) remove_repo(repo string) !bool { return false } - os.rmdir_all(repo_dir)! + os.rmdir_all(repo_dir)? pkg_dir := os.join_path_single(r.pkg_dir, repo) - os.rmdir_all(pkg_dir)! + os.rmdir_all(pkg_dir)? return true } diff --git a/src/repo/sync.v b/src/repo/sync.v index 9554748..73d21c8 100644 --- a/src/repo/sync.v +++ b/src/repo/sync.v @@ -32,7 +32,7 @@ fn archive_add_entry(archive &C.archive, entry &C.archive_entry, file_path &stri } // sync regenerates the repository archive files. -fn (r &RepoGroupManager) sync(repo string, arch string) ! { +fn (r &RepoGroupManager) sync(repo string, arch string) ? { subrepo_path := os.join_path(r.repos_dir, repo, arch) lock r.mutex { @@ -54,7 +54,7 @@ fn (r &RepoGroupManager) sync(repo string, arch string) ! { C.archive_write_open_filename(a_files, &char(files_path.str)) // Iterate over each directory - for d in os.ls(subrepo_path)!.filter(os.is_dir(os.join_path_single(subrepo_path, + for d in os.ls(subrepo_path)?.filter(os.is_dir(os.join_path_single(subrepo_path, it))) { // desc mut inner_path := os.join_path_single(d, 'desc') diff --git a/src/server/api_logs.v b/src/server/api_logs.v index fcbf024..287755a 100644 --- a/src/server/api_logs.v +++ b/src/server/api_logs.v @@ -43,9 +43,9 @@ fn (mut app App) v1_get_log_content(id int) web.Result { // parse_query_time unescapes an HTTP query parameter & tries to parse it as a // time.Time struct. -fn parse_query_time(query string) !time.Time { - unescaped := urllib.query_unescape(query)! - t := time.parse(unescaped)! +fn parse_query_time(query string) ?time.Time { + unescaped := urllib.query_unescape(query)? + t := time.parse(unescaped)? return t } diff --git a/src/server/cli.v b/src/server/cli.v index a9644f3..6fd09c5 100644 --- a/src/server/cli.v +++ b/src/server/cli.v @@ -1,7 +1,7 @@ module server import cli -import conf as vconf +import vieter_v.conf as vconf struct Config { pub: @@ -18,11 +18,11 @@ pub fn cmd() cli.Command { return cli.Command{ name: 'server' description: 'Start the Vieter server.' - execute: fn (cmd cli.Command) ! { - config_file := cmd.flags.get_string('config-file')! - conf := vconf.load(prefix: 'VIETER_', default_path: config_file)! + execute: fn (cmd cli.Command) ? { + config_file := cmd.flags.get_string('config-file')? + conf := vconf.load(prefix: 'VIETER_', default_path: config_file)? - server(conf)! + server(conf)? } } } diff --git a/src/server/server.v b/src/server/server.v index d5f6135..9903cea 100644 --- a/src/server/server.v +++ b/src/server/server.v @@ -24,7 +24,7 @@ pub mut: } // server starts the web server & starts listening for requests -pub fn server(conf Config) ! { +pub fn server(conf Config) ? { // Prevent using 'any' as the default arch if conf.default_arch == 'any' { util.exit_with_message(1, "'any' is not allowed as the value for default_arch.") diff --git a/src/util/stream.v b/src/util/stream.v index 15cc618..06397aa 100644 --- a/src/util/stream.v +++ b/src/util/stream.v @@ -5,7 +5,7 @@ import io import os // reader_to_writer tries to consume the entire reader & write it to the writer. -pub fn reader_to_writer(mut reader io.Reader, mut writer io.Writer) ! { +pub fn reader_to_writer(mut reader io.Reader, mut writer io.Writer) ? { mut buf := []u8{len: 10 * 1024} for { @@ -21,8 +21,8 @@ pub fn reader_to_writer(mut reader io.Reader, mut writer io.Writer) ! { } // reader_to_file writes the contents of a BufferedReader to a file -pub fn reader_to_file(mut reader io.BufferedReader, length int, path string) ! { - mut file := os.create(path)! +pub fn reader_to_file(mut reader io.BufferedReader, length int, path string) ? { + mut file := os.create(path)? defer { file.close() } @@ -69,11 +69,11 @@ pub fn match_array_in_array(a1 []T, a2 []T) int { // read_until_separator consumes an io.Reader until it encounters some // separator array. The data read is stored inside the provided res array. -pub fn read_until_separator(mut reader io.Reader, mut res []u8, sep []u8) ! { +pub fn read_until_separator(mut reader io.Reader, mut res []u8, sep []u8) ? { mut buf := []u8{len: sep.len} for { - c := reader.read(mut buf)! + c := reader.read(mut buf)? res << buf[..c] match_len := match_array_in_array(buf[..c], sep) @@ -84,7 +84,7 @@ pub fn read_until_separator(mut reader io.Reader, mut res []u8, sep []u8) ! { if match_len > 0 { match_left := sep.len - match_len - c2 := reader.read(mut buf[..match_left])! + c2 := reader.read(mut buf[..match_left])? res << buf[..c2] if buf[..c2] == sep[match_len..] { diff --git a/src/util/util.v b/src/util/util.v index 213104c..4cd374e 100644 --- a/src/util/util.v +++ b/src/util/util.v @@ -23,7 +23,7 @@ pub fn exit_with_message(code int, msg string) { } // hash_file returns the sha256 hash of a given file -pub fn hash_file(path &string) !string { +pub fn hash_file(path &string) ?string { file := os.open(path) or { return error('Failed to open file.') } mut sha256sum := sha256.new() @@ -39,7 +39,7 @@ pub fn hash_file(path &string) !string { // This function never actually fails, but returns an option to follow // the Writer interface. - sha256sum.write(buf[..bytes_read])! + sha256sum.write(buf[..bytes_read])? } return sha256sum.checksum().hex() diff --git a/src/web/logging.v b/src/web/logging.v index 12b07d7..fc697ff 100644 --- a/src/web/logging.v +++ b/src/web/logging.v @@ -3,33 +3,33 @@ module web import log // log reate a log message with the given level -pub fn (mut ctx Context) log(msg string, level log.Level) { +pub fn (mut ctx Context) log(msg &string, level log.Level) { lock ctx.logger { ctx.logger.send_output(msg, level) } } // lfatal create a log message with the fatal level -pub fn (mut ctx Context) lfatal(msg string) { +pub fn (mut ctx Context) lfatal(msg &string) { ctx.log(msg, log.Level.fatal) } // lerror create a log message with the error level -pub fn (mut ctx Context) lerror(msg string) { +pub fn (mut ctx Context) lerror(msg &string) { ctx.log(msg, log.Level.error) } // lwarn create a log message with the warn level -pub fn (mut ctx Context) lwarn(msg string) { +pub fn (mut ctx Context) lwarn(msg &string) { ctx.log(msg, log.Level.warn) } // linfo create a log message with the info level -pub fn (mut ctx Context) linfo(msg string) { +pub fn (mut ctx Context) linfo(msg &string) { ctx.log(msg, log.Level.info) } // ldebug create a log message with the debug level -pub fn (mut ctx Context) ldebug(msg string) { +pub fn (mut ctx Context) ldebug(msg &string) { ctx.log(msg, log.Level.debug) } diff --git a/src/web/parse.v b/src/web/parse.v index 7af635f..ee7a72c 100644 --- a/src/web/parse.v +++ b/src/web/parse.v @@ -8,7 +8,7 @@ import net.http const attrs_to_ignore = ['auth'] // 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 { return [http.Method.get], '/$name' } @@ -61,7 +61,7 @@ fn parse_query_from_url(url urllib.URL) map[string]string { } // Extract form data from an HTTP request. -fn parse_form_from_request(request http.Request) !(map[string]string, map[string][]http.FileData) { +fn parse_form_from_request(request http.Request) ?(map[string]string, map[string][]http.FileData) { mut form := map[string]string{} mut files := map[string][]http.FileData{} if request.method in methods_with_form { diff --git a/src/web/web.v b/src/web/web.v index 1b40e7a..1d1480f 100644 --- a/src/web/web.v +++ b/src/web/web.v @@ -24,7 +24,7 @@ pub: pub mut: // TCP connection to client. // But beware, do not store it for further use, after request processing web will close connection. - conn &net.TcpConn = unsafe { nil } + conn &net.TcpConn // Gives access to a shared logger object logger shared log.Log // time.ticks() from start of web connection handle. @@ -67,20 +67,20 @@ struct Route { pub fn (ctx Context) before_request() {} // send_string writes the given string to the TCP connection socket. -fn (mut ctx Context) send_string(s string) ! { - ctx.conn.write(s.bytes())! +fn (mut ctx Context) send_string(s string) ? { + ctx.conn.write(s.bytes())? } // send_reader reads at most `size` bytes from the given reader & writes them // to the TCP connection socket. Internally, a 10KB buffer is used, to avoid // having to store all bytes in memory at once. -fn (mut ctx Context) send_reader(mut reader io.Reader, size u64) ! { +fn (mut ctx Context) send_reader(mut reader io.Reader, size u64) ? { mut buf := []u8{len: 10_000} mut bytes_left := size // Repeat as long as the stream still has data for bytes_left > 0 { - bytes_read := reader.read(mut buf)! + bytes_read := reader.read(mut buf)? bytes_left -= u64(bytes_read) mut to_write := bytes_read @@ -96,20 +96,20 @@ fn (mut ctx Context) send_reader(mut reader io.Reader, size u64) ! { // send_custom_response sends the given http.Response to the client. It can be // used to overwrite the Context object & send a completely custom // http.Response instead. -fn (mut ctx Context) send_custom_response(resp &http.Response) ! { - ctx.send_string(resp.bytestr())! +fn (mut ctx Context) send_custom_response(resp &http.Response) ? { + ctx.send_string(resp.bytestr())? } // send_response_header constructs a valid HTTP response with an empty body & // sends it to the client. -pub fn (mut ctx Context) send_response_header() ! { +pub fn (mut ctx Context) send_response_header() ? { mut resp := http.new_response( header: ctx.header.join(headers_close) ) resp.header.add(.content_type, ctx.content_type) resp.set_status(ctx.status) - ctx.send_custom_response(resp)! + ctx.send_custom_response(resp)? } // send is a convenience function for sending the HTTP response with an empty