diff --git a/src/db/git.v b/src/db/git.v index f4a66f0..ac35ff4 100644 --- a/src/db/git.v +++ b/src/db/git.v @@ -29,12 +29,12 @@ pub mut: 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(', ')}', + "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') @@ -121,12 +121,18 @@ pub fn (db &VieterDb) update_git_repo(repo_id int, params map[string]string) { // Any fields that are array types require their own update method $if field.typ is string { values << "$field.name = '${params[field.name]}'" + // 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 }) + //} } } values_str := values.join(', ') query := 'update GitRepo set $values_str where id == $repo_id' - + println(query) db.conn.exec_none(query) } diff --git a/src/git/cli.v b/src/git/cli.v index 634b778..1839492 100644 --- a/src/git/cli.v +++ b/src/git/cli.v @@ -3,6 +3,7 @@ module git import cli import env import cron.expression { parse_expression } +import db { GitRepo, GitRepoArch } struct Config { address string [required] @@ -122,7 +123,7 @@ fn list(conf Config) ? { repos := get_repos(conf.address, conf.api_key) ? for repo in repos { - println('$repo.id\t$repo.url\t$repo.branch\t$repo.repo') + println('${repo.id}\t$repo.url\t$repo.branch\t$repo.repo') } } diff --git a/src/git/client.v b/src/git/client.v index f34d2ff..d4c5282 100644 --- a/src/git/client.v +++ b/src/git/client.v @@ -28,8 +28,8 @@ fn send_request(method http.Method, address string, url string, api_key strin // get_repos returns the current list of repos. pub fn get_repos(address string, api_key string) ?[]db.GitRepo { - data := send_request<[]db.GitRepo>(http.Method.get, address, '/api/repos', api_key, - {}) ? + data := send_request<[]db.GitRepo>(http.Method.get, address, '/api/repos', + api_key, {}) ? return data.data } diff --git a/src/git/git.v b/src/git/git.v new file mode 100644 index 0000000..7c1c83c --- /dev/null +++ b/src/git/git.v @@ -0,0 +1,84 @@ +module git + +/* import os */ +/* import json */ + +/* pub struct GitRepo { */ +/* pub mut: */ +/* // URL of the Git repository */ +/* url string */ +/* // Branch of the Git repository to use */ +/* branch string */ +/* // On which architectures the package is allowed to be built. In reality, */ +/* // this controls which builders will periodically build the image. */ +/* arch []string */ +/* // Which repo the builder should publish packages to */ +/* repo string */ +/* // Cron schedule describing how frequently to build the repo. */ +/* schedule string [optional] */ +/* } */ + +/* // 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 []string { */ +/* r.$(field.name) = params[field.name].split(',') */ +/* } */ +/* } */ +/* } */ +/* } */ + +/* // read_repos reads the provided path & parses it into a map of GitRepo's. */ +/* pub fn read_repos(path string) ?map[string]GitRepo { */ +/* if !os.exists(path) { */ +/* mut f := os.create(path) ? */ + +/* defer { */ +/* f.close() */ +/* } */ + +/* f.write_string('{}') ? */ + +/* return {} */ +/* } */ + +/* content := os.read_file(path) ? */ +/* res := json.decode(map[string]GitRepo, content) ? */ + +/* return res */ +/* } */ + +/* // write_repos writes a map of GitRepo's back to disk given the provided path. */ +/* pub fn write_repos(path string, repos &map[string]GitRepo) ? { */ +/* mut f := os.create(path) ? */ + +/* defer { */ +/* f.close() */ +/* } */ + +/* value := json.encode(repos) */ +/* f.write_string(value) ? */ +/* } */ + +/* // repo_from_params creates a GitRepo from a map[string]string, usually */ +/* // provided from a web.App's params */ +/* pub fn 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 */ +/* } */ diff --git a/src/server/cli.v b/src/server/cli.v index 4d39666..bea223d 100644 --- a/src/server/cli.v +++ b/src/server/cli.v @@ -6,9 +6,12 @@ import env struct Config { pub: log_level string = 'WARN' + log_file string = 'vieter.log' pkg_dir string - data_dir string + download_dir string api_key string + repos_dir string + repos_file string default_arch string } diff --git a/src/server/git.v b/src/server/git.v index 8bfc528..0389d5f 100644 --- a/src/server/git.v +++ b/src/server/git.v @@ -1,7 +1,9 @@ module server import web +import git import net.http +import rand import response { new_data_response, new_response } import db @@ -15,6 +17,13 @@ fn (mut app App) get_repos() web.Result { } repos := app.db.get_git_repos() + // repos := rlock app.git_mutex { + // git.read_repos(app.conf.repos_file) or { + // app.lerror('Failed to read repos file: $err.msg()') + + // return app.status(http.Status.internal_server_error) + // } + //} return app.json(http.Status.ok, new_data_response(repos)) } @@ -26,6 +35,19 @@ fn (mut app App) get_single_repo(id int) web.Result { return app.json(http.Status.unauthorized, new_response('Unauthorized.')) } + // repos := rlock app.git_mutex { + // git.read_repos(app.conf.repos_file) or { + // app.lerror('Failed to read repos file.') + + // return app.status(http.Status.internal_server_error) + // } + //} + + // if id !in repos { + // return app.not_found() + //} + + // repo := repos[id] repo := app.db.get_git_repo(id) or { return app.not_found() } return app.json(http.Status.ok, new_data_response(repo)) @@ -52,6 +74,32 @@ fn (mut app App) post_repo() web.Result { app.db.add_git_repo(new_repo) + // id := rand.uuid_v4() + + // mut repos := rlock app.git_mutex { + // git.read_repos(app.conf.repos_file) or { + // app.lerror('Failed to read repos file.') + + // return app.status(http.Status.internal_server_error) + // } + //} + // repos := app.db.get_git_repos() + + //// We need to check for duplicates + // for _, repo in repos { + // if repo == new_repo { + // return app.json(http.Status.bad_request, new_response('Duplicate repository.')) + // } + //} + + // repos[id] = new_repo + + // lock app.git_mutex { + // git.write_repos(app.conf.repos_file, &repos) or { + // return app.status(http.Status.internal_server_error) + // } + //} + return app.json(http.Status.ok, new_response('Repo added successfully.')) } @@ -62,9 +110,25 @@ fn (mut app App) delete_repo(id int) web.Result { return app.json(http.Status.unauthorized, new_response('Unauthorized.')) } + // mut repos := rlock app.git_mutex { + // git.read_repos(app.conf.repos_file) or { + // app.lerror('Failed to read repos file.') + + // return app.status(http.Status.internal_server_error) + // } + //} + + // if id !in repos { + // return app.not_found() + //} + // repos.delete(id) app.db.delete_git_repo(id) + // lock app.git_mutex { + // git.write_repos(app.conf.repos_file, &repos) or { return app.server_error(500) } + // } + return app.json(http.Status.ok, new_response('Repo removed successfully.')) } @@ -83,5 +147,23 @@ fn (mut app App) patch_repo(id int) web.Result { app.db.update_git_repo_archs(id, arch_objs) } + // mut repos := rlock app.git_mutex { + // git.read_repos(app.conf.repos_file) or { + // app.lerror('Failed to read repos file.') + + // return app.status(http.Status.internal_server_error) + // } + // } + + // if id !in repos { + // return app.not_found() + // } + + // repos[id].patch_from_params(app.query) + + // lock app.git_mutex { + // git.write_repos(app.conf.repos_file, &repos) or { return app.server_error(500) } + // } + return app.json(http.Status.ok, new_response('Repo updated successfully.')) } diff --git a/src/server/routes.v b/src/server/routes.v index fbf37df..f27afb4 100644 --- a/src/server/routes.v +++ b/src/server/routes.v @@ -68,7 +68,7 @@ fn (mut app App) put_package(repo string) web.Result { if length := app.req.header.get(.content_length) { // 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.conf.download_dir, rand.uuid_v4()) app.ldebug("Uploading $length bytes (${util.pretty_bytes(length.int())}) to '$pkg_path'.") diff --git a/src/server/server.v b/src/server/server.v index 2883942..751ea9c 100644 --- a/src/server/server.v +++ b/src/server/server.v @@ -7,12 +7,7 @@ import repo import util import db -const ( - port = 8000 - log_file_name = 'vieter.log' - repo_dir_name = 'repos' - db_file_name = 'vieter.sqlite' -) +const port = 8000 struct App { web.Context @@ -37,14 +32,11 @@ pub fn server(conf Config) ? { util.exit_with_message(1, 'Invalid log level. The allowed values are FATAL, ERROR, WARN, INFO & DEBUG.') } - os.mkdir_all(conf.data_dir) or { util.exit_with_message(1, 'Failed to create data directory.') } - mut logger := log.Log{ level: log_level } - log_file := os.join_path_single(conf.data_dir, server.log_file_name) - logger.set_full_logpath(log_file) + logger.set_full_logpath(conf.log_file) logger.log_to_console_too() defer { @@ -53,15 +45,17 @@ pub fn server(conf Config) ? { logger.close() } - repo_dir := os.join_path_single(conf.data_dir, server.repo_dir_name) // This also creates the directories if needed - repo := repo.new(repo_dir, conf.pkg_dir, conf.default_arch) or { + repo := repo.new(conf.repos_dir, conf.pkg_dir, conf.default_arch) or { logger.error(err.msg()) exit(1) } - db_file := os.join_path_single(conf.data_dir, server.db_file_name) - db := db.init(db_file) or { util.exit_with_message(1, 'Failed to initialize database.') } + os.mkdir_all(conf.download_dir) or { + util.exit_with_message(1, 'Failed to create download directory.') + } + + db := db.init('test.db') or { util.exit_with_message(1, 'Failed to initialize database.') } web.run(&App{ logger: logger diff --git a/vieter.toml b/vieter.toml index d3922a4..fc86d77 100644 --- a/vieter.toml +++ b/vieter.toml @@ -1,8 +1,10 @@ # This file contains settings used during development api_key = "test" -data_dir = "data" +download_dir = "data/downloads" +repos_dir = "data/repos" pkg_dir = "data/pkgs" log_level = "DEBUG" +repos_file = "data/repos.json" default_arch = "x86_64" address = "http://localhost:8000"