From 0de5ffb45d2734b95c3c11dd25d2bfdf6dd2bf0e Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Mon, 16 May 2022 17:34:51 +0200 Subject: [PATCH 1/6] chore: bumped versions --- CHANGELOG.md | 2 ++ PKGBUILD | 2 +- src/main.v | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c20393..7dc0a00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://git.rustybever.be/vieter/vieter/src/branch/dev) +## [0.3.0-alpha.2](https://git.rustybever.be/vieter/vieter/src/tag/0.3.0-alpha.2) + ### Added * Web API for adding & querying build logs diff --git a/PKGBUILD b/PKGBUILD index 83ab896..49fcf54 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -3,7 +3,7 @@ pkgbase='vieter' pkgname='vieter' -pkgver='0.3.0_alpha.1' +pkgver='0.3.0_alpha.2' pkgrel=1 depends=('glibc' 'openssl' 'libarchive' 'sqlite') makedepends=('git' 'vieter-v') diff --git a/src/main.v b/src/main.v index dbfac09..6df45dc 100644 --- a/src/main.v +++ b/src/main.v @@ -11,7 +11,7 @@ fn main() { mut app := cli.Command{ name: 'vieter' description: 'Vieter is a lightweight implementation of an Arch repository server.' - version: '0.3.0-alpha.1' + version: '0.3.0-alpha.2' flags: [ cli.Flag{ flag: cli.FlagType.string From e0561a876a74fd91f8044181d8ab16464dbf4410 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Tue, 17 May 2022 13:50:46 +0200 Subject: [PATCH 2/6] feat(server): added better query params to GitRepo API --- src/db/filter.v | 25 +++++++++++++++++++++++++ src/db/git.v | 14 ++++++++++++-- src/server/git.v | 5 ++++- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/db/filter.v diff --git a/src/db/filter.v b/src/db/filter.v new file mode 100644 index 0000000..79e281b --- /dev/null +++ b/src/db/filter.v @@ -0,0 +1,25 @@ +module db + +pub struct GitRepoFilter { +pub mut: + limit u64 = 25 + offset u64 + repo string +} + +pub fn filter_from_params(params map[string]string) ?T { + mut o := GitRepoFilter{} + + $for field in T.fields { + if field.name in params { + val := params[field.name] + + $if field.typ is string { + o.$(field.name) = val + } $else $if field.typ is u64 { + o.$(field.name) = val.u64() + } + } + } + return o +} diff --git a/src/db/git.v b/src/db/git.v index 9a475a5..cb31bf0 100644 --- a/src/db/git.v +++ b/src/db/git.v @@ -77,9 +77,19 @@ pub fn git_repo_from_params(params map[string]string) ?GitRepo { } // get_git_repos returns all GitRepo's in the database. -pub fn (db &VieterDb) get_git_repos() []GitRepo { +pub fn (db &VieterDb) get_git_repos(filter GitRepoFilter) []GitRepo { + // This seems to currently be blocked by a bug in the ORM, I'll have to ask + // around. + if filter.repo != '' { + res := sql db.conn { + select from GitRepo where repo == filter.repo order by id limit filter.limit offset filter.offset + } + + return res + } + res := sql db.conn { - select from GitRepo order by id + select from GitRepo order by id limit filter.limit offset filter.offset } return res diff --git a/src/server/git.v b/src/server/git.v index c5cbc0a..921251f 100644 --- a/src/server/git.v +++ b/src/server/git.v @@ -12,7 +12,10 @@ fn (mut app App) get_repos() web.Result { return app.json(http.Status.unauthorized, new_response('Unauthorized.')) } - repos := app.db.get_git_repos() + filter := db.filter_from_params(app.query) or { + return app.json(http.Status.bad_request, new_response('Invalid query parameters.')) + } + repos := app.db.get_git_repos(filter) return app.json(http.Status.ok, new_data_response(repos)) } From 706f3efad893b2121f65160a20a03a73a8f8a8de Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Wed, 18 May 2022 08:22:13 +0200 Subject: [PATCH 3/6] WIP: add filters to GitRepo CLI --- src/client/git.v | 8 +++++--- src/console/git/git.v | 46 ++++++++++++++++++++++++++++++++++++++++--- src/db/filter.v | 1 + src/db/git.v | 1 + src/util/util.v | 10 ++++++++++ 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/client/git.v b/src/client/git.v index 280caab..c21565a 100644 --- a/src/client/git.v +++ b/src/client/git.v @@ -1,12 +1,14 @@ module client -import db { GitRepo } +import db { GitRepo, GitRepoFilter } import net.http { Method } import response { Response } +import util // get_git_repos returns the current list of repos. -pub fn (c &Client) get_git_repos() ?[]GitRepo { - data := c.send_request<[]GitRepo>(Method.get, '/api/repos', {})? +pub fn (c &Client) get_git_repos(filter GitRepoFilter) ?[]GitRepo { + params := util.struct_to_map(filter) + data := c.send_request<[]GitRepo>(Method.get, '/api/repos', params)? return data.data } diff --git a/src/console/git/git.v b/src/console/git/git.v index 06d5f80..861bfb3 100644 --- a/src/console/git/git.v +++ b/src/console/git/git.v @@ -5,6 +5,7 @@ import env import cron.expression { parse_expression } import client import console +import db { GitRepoFilter } struct Config { address string [required] @@ -21,11 +22,50 @@ pub fn cmd() cli.Command { cli.Command{ name: 'list' description: 'List the current repos.' + flags: [ + cli.Flag{ + name: 'limit' + description: 'How many results to return.' + flag: cli.FlagType.int + }, + cli.Flag{ + name: 'offset' + description: 'Minimum index to return.' + flag: cli.FlagType.int + }, + cli.Flag{ + name: 'repo' + description: 'Only return Git repos that publish to this repo.' + flag: cli.FlagType.string + }, + cli.Flag{ + name: 'arch' + description: 'Only return repos enabled for this architecture.' + flag: cli.FlagType.string + }, + ] execute: fn (cmd cli.Command) ? { config_file := cmd.flags.get_string('config-file')? conf := env.load(config_file)? - list(conf)? + mut filter := GitRepoFilter{} + + if limit := cmd.flags.get_int('limit') { + println('limit = $limit') + filter.limit = u64(limit) + } + + if offset := cmd.flags.get_int('offset') { + filter.limit = u64(offset) + } + + if repo := cmd.flags.get_string('repo') { + filter.repo = repo + } + + dump(filter) + + list(conf, filter)? } }, cli.Command{ @@ -133,9 +173,9 @@ 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) ? { +fn list(conf Config, filter GitRepoFilter) ? { c := client.new(conf.address, conf.api_key) - repos := c.get_git_repos()? + repos := c.get_git_repos(filter)? data := repos.map([it.id.str(), it.url, it.branch, it.repo]) println(console.pretty_table(['id', 'url', 'branch', 'repo'], data)?) diff --git a/src/db/filter.v b/src/db/filter.v index 79e281b..07c890a 100644 --- a/src/db/filter.v +++ b/src/db/filter.v @@ -1,5 +1,6 @@ module db +[params] pub struct GitRepoFilter { pub mut: limit u64 = 25 diff --git a/src/db/git.v b/src/db/git.v index cb31bf0..7308346 100644 --- a/src/db/git.v +++ b/src/db/git.v @@ -78,6 +78,7 @@ pub fn git_repo_from_params(params map[string]string) ?GitRepo { // get_git_repos returns all GitRepo's in the database. pub fn (db &VieterDb) get_git_repos(filter GitRepoFilter) []GitRepo { + println(filter) // This seems to currently be blocked by a bug in the ORM, I'll have to ask // around. if filter.repo != '' { diff --git a/src/util/util.v b/src/util/util.v index 266bcb5..cbb4072 100644 --- a/src/util/util.v +++ b/src/util/util.v @@ -64,3 +64,13 @@ pub fn pretty_bytes(bytes int) string { return '${n:.2}${util.prefixes[i]}' } + +pub fn struct_to_map(o T) map[string]string { + mut m := map[string]string{} + + $for field in T.fields { + m[field.name] = o.$(field.name).str() + } + + return m +} From 1e079143cd29673ff2a20e8513dfc741493f0e9b Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Tue, 17 May 2022 13:50:46 +0200 Subject: [PATCH 4/6] feat(server): added better query params to GitRepo API --- src/db/filter.v | 25 +++++++++++++++++++++++++ src/db/git.v | 14 ++++++++++++-- src/server/git.v | 5 ++++- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/db/filter.v diff --git a/src/db/filter.v b/src/db/filter.v new file mode 100644 index 0000000..79e281b --- /dev/null +++ b/src/db/filter.v @@ -0,0 +1,25 @@ +module db + +pub struct GitRepoFilter { +pub mut: + limit u64 = 25 + offset u64 + repo string +} + +pub fn filter_from_params(params map[string]string) ?T { + mut o := GitRepoFilter{} + + $for field in T.fields { + if field.name in params { + val := params[field.name] + + $if field.typ is string { + o.$(field.name) = val + } $else $if field.typ is u64 { + o.$(field.name) = val.u64() + } + } + } + return o +} diff --git a/src/db/git.v b/src/db/git.v index 9a475a5..cb31bf0 100644 --- a/src/db/git.v +++ b/src/db/git.v @@ -77,9 +77,19 @@ pub fn git_repo_from_params(params map[string]string) ?GitRepo { } // get_git_repos returns all GitRepo's in the database. -pub fn (db &VieterDb) get_git_repos() []GitRepo { +pub fn (db &VieterDb) get_git_repos(filter GitRepoFilter) []GitRepo { + // This seems to currently be blocked by a bug in the ORM, I'll have to ask + // around. + if filter.repo != '' { + res := sql db.conn { + select from GitRepo where repo == filter.repo order by id limit filter.limit offset filter.offset + } + + return res + } + res := sql db.conn { - select from GitRepo order by id + select from GitRepo order by id limit filter.limit offset filter.offset } return res diff --git a/src/server/git.v b/src/server/git.v index c5cbc0a..921251f 100644 --- a/src/server/git.v +++ b/src/server/git.v @@ -12,7 +12,10 @@ fn (mut app App) get_repos() web.Result { return app.json(http.Status.unauthorized, new_response('Unauthorized.')) } - repos := app.db.get_git_repos() + filter := db.filter_from_params(app.query) or { + return app.json(http.Status.bad_request, new_response('Invalid query parameters.')) + } + repos := app.db.get_git_repos(filter) return app.json(http.Status.ok, new_data_response(repos)) } From 6e6249396a88843f6cb5df8845912c1b9b95c2c3 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Wed, 18 May 2022 08:22:13 +0200 Subject: [PATCH 5/6] WIP: add filters to GitRepo CLI --- src/client/git.v | 8 +++++--- src/console/git/git.v | 46 ++++++++++++++++++++++++++++++++++++++++--- src/db/filter.v | 1 + src/db/git.v | 1 + src/util/util.v | 10 ++++++++++ 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/client/git.v b/src/client/git.v index 280caab..c21565a 100644 --- a/src/client/git.v +++ b/src/client/git.v @@ -1,12 +1,14 @@ module client -import db { GitRepo } +import db { GitRepo, GitRepoFilter } import net.http { Method } import response { Response } +import util // get_git_repos returns the current list of repos. -pub fn (c &Client) get_git_repos() ?[]GitRepo { - data := c.send_request<[]GitRepo>(Method.get, '/api/repos', {})? +pub fn (c &Client) get_git_repos(filter GitRepoFilter) ?[]GitRepo { + params := util.struct_to_map(filter) + data := c.send_request<[]GitRepo>(Method.get, '/api/repos', params)? return data.data } diff --git a/src/console/git/git.v b/src/console/git/git.v index 06d5f80..861bfb3 100644 --- a/src/console/git/git.v +++ b/src/console/git/git.v @@ -5,6 +5,7 @@ import env import cron.expression { parse_expression } import client import console +import db { GitRepoFilter } struct Config { address string [required] @@ -21,11 +22,50 @@ pub fn cmd() cli.Command { cli.Command{ name: 'list' description: 'List the current repos.' + flags: [ + cli.Flag{ + name: 'limit' + description: 'How many results to return.' + flag: cli.FlagType.int + }, + cli.Flag{ + name: 'offset' + description: 'Minimum index to return.' + flag: cli.FlagType.int + }, + cli.Flag{ + name: 'repo' + description: 'Only return Git repos that publish to this repo.' + flag: cli.FlagType.string + }, + cli.Flag{ + name: 'arch' + description: 'Only return repos enabled for this architecture.' + flag: cli.FlagType.string + }, + ] execute: fn (cmd cli.Command) ? { config_file := cmd.flags.get_string('config-file')? conf := env.load(config_file)? - list(conf)? + mut filter := GitRepoFilter{} + + if limit := cmd.flags.get_int('limit') { + println('limit = $limit') + filter.limit = u64(limit) + } + + if offset := cmd.flags.get_int('offset') { + filter.limit = u64(offset) + } + + if repo := cmd.flags.get_string('repo') { + filter.repo = repo + } + + dump(filter) + + list(conf, filter)? } }, cli.Command{ @@ -133,9 +173,9 @@ 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) ? { +fn list(conf Config, filter GitRepoFilter) ? { c := client.new(conf.address, conf.api_key) - repos := c.get_git_repos()? + repos := c.get_git_repos(filter)? data := repos.map([it.id.str(), it.url, it.branch, it.repo]) println(console.pretty_table(['id', 'url', 'branch', 'repo'], data)?) diff --git a/src/db/filter.v b/src/db/filter.v index 79e281b..07c890a 100644 --- a/src/db/filter.v +++ b/src/db/filter.v @@ -1,5 +1,6 @@ module db +[params] pub struct GitRepoFilter { pub mut: limit u64 = 25 diff --git a/src/db/git.v b/src/db/git.v index cb31bf0..7308346 100644 --- a/src/db/git.v +++ b/src/db/git.v @@ -78,6 +78,7 @@ pub fn git_repo_from_params(params map[string]string) ?GitRepo { // get_git_repos returns all GitRepo's in the database. pub fn (db &VieterDb) get_git_repos(filter GitRepoFilter) []GitRepo { + println(filter) // This seems to currently be blocked by a bug in the ORM, I'll have to ask // around. if filter.repo != '' { diff --git a/src/util/util.v b/src/util/util.v index 266bcb5..cbb4072 100644 --- a/src/util/util.v +++ b/src/util/util.v @@ -64,3 +64,13 @@ pub fn pretty_bytes(bytes int) string { return '${n:.2}${util.prefixes[i]}' } + +pub fn struct_to_map(o T) map[string]string { + mut m := map[string]string{} + + $for field in T.fields { + m[field.name] = o.$(field.name).str() + } + + return m +} From 611ae175b8f55aa28621957a458ddb29fa359ce5 Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Wed, 18 May 2022 22:27:02 +0200 Subject: [PATCH 6/6] WIP: trying to refactor to models module [CI SKIP] --- src/build/build.v | 3 +- src/client/client.v | 5 ++- src/client/git.v | 5 ++- src/console/git/git.v | 16 ++++----- src/cron/daemon/daemon.v | 7 ++-- src/db/db.v | 3 +- src/db/filter.v | 26 -------------- src/db/git.v | 77 +--------------------------------------- src/models/git.v | 52 +++++++++++++++++++++++++++ src/models/models.v | 37 +++++++++++++++++++ src/server/git.v | 8 +++-- src/util/util.v | 1 - 12 files changed, 117 insertions(+), 123 deletions(-) delete mode 100644 src/db/filter.v create mode 100644 src/models/git.v create mode 100644 src/models/models.v diff --git a/src/build/build.v b/src/build/build.v index fab6c35..1f26d03 100644 --- a/src/build/build.v +++ b/src/build/build.v @@ -7,6 +7,7 @@ import os import db import strings import util +import models { GitRepo } const ( container_build_dir = '/build' @@ -93,7 +94,7 @@ pub: // build_repo builds, packages & publishes a given Arch package based on the // provided GitRepo. 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_repo(address string, api_key string, base_image_id string, repo &db.GitRepo) ?BuildResult { +pub fn build_repo(address string, api_key string, base_image_id string, repo &GitRepo) ?BuildResult { mut dd := docker.new_conn()? defer { diff --git a/src/client/client.v b/src/client/client.v index 3b28073..7cb6be5 100644 --- a/src/client/client.v +++ b/src/client/client.v @@ -29,7 +29,10 @@ fn (c &Client) send_request_raw(method Method, url string, params map[string]str // Escape each query param for k, v in params { - params_escaped[k] = urllib.query_escape(v) + // An empty parameter should be the same as not providing it at all + if v != '' { + params_escaped[k] = urllib.query_escape(v) + } } params_str := params_escaped.keys().map('$it=${params[it]}').join('&') diff --git a/src/client/git.v b/src/client/git.v index c21565a..fd14718 100644 --- a/src/client/git.v +++ b/src/client/git.v @@ -1,13 +1,12 @@ module client -import db { GitRepo, GitRepoFilter } +import models { GitRepo, GitRepoFilter } import net.http { Method } import response { Response } -import util // get_git_repos returns the current list of repos. pub fn (c &Client) get_git_repos(filter GitRepoFilter) ?[]GitRepo { - params := util.struct_to_map(filter) + params := models.params_from(filter) data := c.send_request<[]GitRepo>(Method.get, '/api/repos', params)? return data.data diff --git a/src/console/git/git.v b/src/console/git/git.v index 861bfb3..e5dd3d2 100644 --- a/src/console/git/git.v +++ b/src/console/git/git.v @@ -5,7 +5,7 @@ import env import cron.expression { parse_expression } import client import console -import db { GitRepoFilter } +import models { GitRepoFilter } struct Config { address string [required] @@ -50,21 +50,21 @@ pub fn cmd() cli.Command { mut filter := GitRepoFilter{} - if limit := cmd.flags.get_int('limit') { - println('limit = $limit') + limit := cmd.flags.get_int('limit') ? + if limit != 0 { filter.limit = u64(limit) } - if offset := cmd.flags.get_int('offset') { - filter.limit = u64(offset) + offset := cmd.flags.get_int('offset') ? + if offset != 0 { + filter.offset = u64(offset) } - if repo := cmd.flags.get_string('repo') { + repo := cmd.flags.get_string('repo') ? + if repo != '' { filter.repo = repo } - dump(filter) - list(conf, filter)? } }, diff --git a/src/cron/daemon/daemon.v b/src/cron/daemon/daemon.v index da3b46e..e92dd68 100644 --- a/src/cron/daemon/daemon.v +++ b/src/cron/daemon/daemon.v @@ -10,6 +10,7 @@ import docker import db import os import client +import models { GitRepo } const ( // How many seconds to wait before retrying to update API if failed @@ -20,7 +21,7 @@ const ( struct ScheduledBuild { pub: - repo db.GitRepo + repo GitRepo timestamp time.Time } @@ -38,7 +39,7 @@ mut: api_update_frequency int image_rebuild_frequency int // Repos currently loaded from API. - repos []db.GitRepo + repos []GitRepo // At what point to update the list of repositories. api_update_timestamp time.Time image_build_timestamp time.Time @@ -149,7 +150,7 @@ pub fn (mut d Daemon) run() { } // schedule_build adds the next occurence of the given repo build to the queue. -fn (mut d Daemon) schedule_build(repo db.GitRepo) { +fn (mut d Daemon) schedule_build(repo GitRepo) { ce := if repo.schedule != '' { parse_expression(repo.schedule) or { // TODO This shouldn't return an error if the expression is empty. diff --git a/src/db/db.v b/src/db/db.v index 7c1acf1..9192530 100644 --- a/src/db/db.v +++ b/src/db/db.v @@ -1,6 +1,7 @@ module db import sqlite +import models struct VieterDb { conn sqlite.DB @@ -11,7 +12,7 @@ pub fn init(db_path string) ?VieterDb { conn := sqlite.connect(db_path)? sql conn { - create table GitRepo + create table models.GitRepo create table BuildLog } diff --git a/src/db/filter.v b/src/db/filter.v deleted file mode 100644 index 07c890a..0000000 --- a/src/db/filter.v +++ /dev/null @@ -1,26 +0,0 @@ -module db - -[params] -pub struct GitRepoFilter { -pub mut: - limit u64 = 25 - offset u64 - repo string -} - -pub fn filter_from_params(params map[string]string) ?T { - mut o := GitRepoFilter{} - - $for field in T.fields { - if field.name in params { - val := params[field.name] - - $if field.typ is string { - o.$(field.name) = val - } $else $if field.typ is u64 { - o.$(field.name) = val.u64() - } - } - } - return o -} diff --git a/src/db/git.v b/src/db/git.v index 7308346..d8887ff 100644 --- a/src/db/git.v +++ b/src/db/git.v @@ -1,84 +1,9 @@ module db -pub struct GitRepoArch { -pub: - id int [primary; sql: serial] - repo_id int [nonull] - value string [nonull] -} - -// str returns a string representation. -pub fn (gra &GitRepoArch) str() string { - return gra.value -} - -pub struct GitRepo { -pub mut: - id int [optional; primary; sql: serial] - // URL of the Git repository - url string [nonull] - // Branch of the Git repository to use - branch string [nonull] - // Which repo the builder should publish packages to - repo string [nonull] - // Cron schedule describing how frequently to build the repo. - schedule string [optional] - // On which architectures the package is allowed to be built. In reality, - // this controls which builders will periodically build the image. - arch []GitRepoArch [fkey: 'repo_id'] -} - -// str returns a string representation. -pub fn (gr &GitRepo) str() string { - mut parts := [ - 'id: $gr.id', - 'url: $gr.url', - 'branch: $gr.branch', - 'repo: $gr.repo', - 'schedule: $gr.schedule', - 'arch: ${gr.arch.map(it.value).join(', ')}', - ] - str := parts.join('\n') - - return str -} - -// patch_from_params patches a GitRepo from a map[string]string, usually -// provided from a web.App's params -pub fn (mut r GitRepo) patch_from_params(params map[string]string) { - $for field in GitRepo.fields { - if field.name in params { - $if field.typ is string { - r.$(field.name) = params[field.name] - // This specific type check is needed for the compiler to ensure - // our types are correct - } $else $if field.typ is []GitRepoArch { - r.$(field.name) = params[field.name].split(',').map(GitRepoArch{ value: it }) - } - } - } -} - -// git_repo_from_params creates a GitRepo from a map[string]string, usually -// provided from a web.App's params -pub fn git_repo_from_params(params map[string]string) ?GitRepo { - mut repo := GitRepo{} - - // If we're creating a new GitRepo, we want all fields to be present before - // "patching". - $for field in GitRepo.fields { - if field.name !in params && !field.attrs.contains('optional') { - return error('Missing parameter: ${field.name}.') - } - } - repo.patch_from_params(params) - - return repo -} +import models { GitRepo, GitRepoArch, GitRepoFilter } // get_git_repos returns all GitRepo's in the database. pub fn (db &VieterDb) get_git_repos(filter GitRepoFilter) []GitRepo { - println(filter) // This seems to currently be blocked by a bug in the ORM, I'll have to ask // around. if filter.repo != '' { diff --git a/src/models/git.v b/src/models/git.v new file mode 100644 index 0000000..5dcc13a --- /dev/null +++ b/src/models/git.v @@ -0,0 +1,52 @@ +module models + +pub struct GitRepoArch { +pub: + id int [primary; sql: serial] + repo_id int [nonull] + value string [nonull] +} + +// str returns a string representation. +pub fn (gra &GitRepoArch) str() string { + return gra.value +} + +pub struct GitRepo { +pub mut: + id int [primary; sql: serial] + // URL of the Git repository + url string [nonull] + // Branch of the Git repository to use + branch string [nonull] + // Which repo the builder should publish packages to + repo string [nonull] + // Cron schedule describing how frequently to build the repo. + schedule string + // On which architectures the package is allowed to be built. In reality, + // this controls which builders will periodically build the image. + arch []GitRepoArch [fkey: 'repo_id'] +} + +// str returns a string representation. +pub fn (gr &GitRepo) str() string { + mut parts := [ + 'id: $gr.id', + 'url: $gr.url', + 'branch: $gr.branch', + 'repo: $gr.repo', + 'schedule: $gr.schedule', + 'arch: ${gr.arch.map(it.value).join(', ')}', + ] + str := parts.join('\n') + + return str +} + +[params] +pub struct GitRepoFilter { +pub mut: + limit u64 = 25 + offset u64 + repo string +} diff --git a/src/models/models.v b/src/models/models.v new file mode 100644 index 0000000..2acc584 --- /dev/null +++ b/src/models/models.v @@ -0,0 +1,37 @@ +module models + +pub fn from_params(params map[string]string) ?A { + mut o := A{} + + patch_from_params(mut o, params) ? + + return o +} + +pub fn patch_from_params(mut o B, params map[string]string) ? { + $for field in B.fields { + if field.name in params { + $if field.typ is string { + o.$(field.name) = params[field.name] + } $else $if field.typ is int { + o.$(field.name) = params[field.name].int() + } $else $if field.typ is u64 { + o.$(field.name) = params[field.name].u64() + } $else $if field.typ is []GitRepoArch { + o.$(field.name) = params[field.name].split(',').map(GitRepoArch{ value: it }) + } + } else if field.attrs.contains('nonull') { + return error('Missing parameter: ${field.name}.') + } + } +} + +pub fn params_from(o &D) map[string]string { + mut out := map[string]string{} + + $for field in D.fields { + out[field.name] = o.$(field.name).str() + } + + return out +} diff --git a/src/server/git.v b/src/server/git.v index 921251f..0885d59 100644 --- a/src/server/git.v +++ b/src/server/git.v @@ -4,6 +4,7 @@ import web import net.http import response { new_data_response, new_response } import db +import models { GitRepo, GitRepoArch, GitRepoFilter } // get_repos returns the current list of repos. ['/api/repos'; get] @@ -12,7 +13,8 @@ fn (mut app App) get_repos() web.Result { return app.json(http.Status.unauthorized, new_response('Unauthorized.')) } - filter := db.filter_from_params(app.query) or { + filter := models.from_params(app.query) or { + println(err.msg()) return app.json(http.Status.bad_request, new_response('Invalid query parameters.')) } repos := app.db.get_git_repos(filter) @@ -47,7 +49,7 @@ fn (mut app App) post_repo() web.Result { params['arch'] = app.conf.default_arch } - new_repo := db.git_repo_from_params(params) or { + new_repo := models.from_params(params) or { return app.json(http.Status.bad_request, new_response(err.msg())) } @@ -78,7 +80,7 @@ fn (mut app App) patch_repo(id int) web.Result { app.db.update_git_repo(id, app.query) if 'arch' in app.query { - arch_objs := app.query['arch'].split(',').map(db.GitRepoArch{ value: it }) + arch_objs := app.query['arch'].split(',').map(GitRepoArch{ value: it }) app.db.update_git_repo_archs(id, arch_objs) } diff --git a/src/util/util.v b/src/util/util.v index cbb4072..f9d47a8 100644 --- a/src/util/util.v +++ b/src/util/util.v @@ -71,6 +71,5 @@ pub fn struct_to_map(o T) map[string]string { $for field in T.fields { m[field.name] = o.$(field.name).str() } - return m }