Mercurial > sci
changeset 22:dd078aea5d02
misc: use project/worker name as primary key
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 21 Jul 2022 20:23:22 +0200 |
parents | ec30e1b078a9 |
children | 2cb228f23f53 |
files | .hgignore Makefile lib/apic.c lib/apic.h lib/db.c lib/db.h lib/strlcpy.c lib/strtonum.c lib/types.c lib/types.h lib/util.h man/scid.8.in scictl/scictl.c scid/page-api-projects.c scid/page-api-todo.c scid/page-api-workers.c sql/init.sql sql/job-add.sql sql/job-todo.sql sql/jobresult-add.sql sql/project-add.sql sql/project-find-id.sql sql/project-find.sql sql/project-list.sql sql/project-save.sql sql/project-update.sql sql/worker-add.sql sql/worker-find-id.sql sql/worker-find.sql sql/worker-list.sql sql/worker-save.sql |
diffstat | 31 files changed, 584 insertions(+), 675 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Tue Jul 19 22:45:44 2022 +0200 +++ b/.hgignore Thu Jul 21 20:23:22 2022 +0200 @@ -21,6 +21,7 @@ # executables. ^bcc$ +^scictl/scictl$ ^scid/scid$ ^sciworkerd/sciworkerd$
--- a/Makefile Tue Jul 19 22:45:44 2022 +0200 +++ b/Makefile Thu Jul 21 20:23:22 2022 +0200 @@ -26,6 +26,7 @@ lib/db.c \ lib/log.c \ lib/strlcpy.c \ + lib/strtonum.c \ lib/types.c \ lib/util.c LIBSCI_OBJS= ${LIBSCI_SRCS:.c=.o} @@ -35,15 +36,12 @@ sql/job-add.sql \ sql/job-todo.sql \ sql/jobresult-add.sql \ - sql/project-add.sql \ - sql/project-find-id.sql \ sql/project-find.sql \ sql/project-list.sql \ - sql/project-update.sql \ - sql/worker-add.sql \ + sql/project-save.sql \ sql/worker-find.sql \ - sql/worker-find-id.sql \ - sql/worker-list.sql + sql/worker-list.sql \ + sql/worker-save.sql SQL_OBJS= ${SQL_SRCS:.sql=.h} SCICTL= scictl/scictl
--- a/lib/apic.c Tue Jul 19 22:45:44 2022 +0200 +++ b/lib/apic.c Thu Jul 21 20:23:22 2022 +0200 @@ -19,7 +19,7 @@ struct converter { void *data; size_t datasz; - int (*unpack)(void *, size_t, json_t *); + ssize_t (*unpack)(void *, size_t, json_t *); json_t *(*pack)(const void *, size_t); }; @@ -133,6 +133,101 @@ return ret; } +static ssize_t +get(struct apic *req, const struct converter *cv, const char *fmt, ...) +{ + va_list ap; + ssize_t ret; + + va_start(ap, fmt); + ret = perform(req, NULL, fmt, ap); + va_end(ap); + + if (ret < 0) + return -1; + if (!req->doc || (!json_is_object(req->doc) && !json_is_array(req->doc))) + return snprintf(req->error, sizeof (req->error), "invalid JSON document received"), -1; + if ((ret = cv->unpack(cv->data, cv->datasz, req->doc)) < 0) + return snprintf(req->error, sizeof (req->error), "%s", strerror(errno)); + + return ret; +} + +static int +create(struct apic *req, const struct converter *cv, const char *fmt, ...) +{ + va_list ap; + int ret; + json_t *doc; + char *body; + + memset(req, 0, sizeof (*req)); + + if (!(doc = cv->pack(cv->data, cv->datasz))) + return snprintf(req->error, sizeof (req->error), "%s", strerror(errno)); + if (!(body = json_dumps(doc, JSON_COMPACT))) { + json_decref(doc); + return snprintf(req->error, sizeof (req->error), "%s", strerror(errno)); + } + + va_start(ap, fmt); + ret = perform(req, body, fmt, ap); + va_end(ap); + + json_decref(doc); + free(body); + + return 0; +} + +static json_t * +wrap_job_to(const void *data, size_t datasz) +{ + return job_to(data, datasz); +} + +static ssize_t +wrap_job_from(void *data, size_t datasz, json_t *doc) +{ + return job_from(data, datasz, doc); +} + +static json_t * +wrap_jobresult_to(const void *data, size_t datasz) +{ + return jobresult_to(data, datasz); +} + +static ssize_t +wrap_project_from(void *data, size_t datasz, json_t *doc) +{ + return project_from(data, datasz, doc); +} + +static json_t * +wrap_project_to(const void *data, size_t datasz) +{ + return project_to(data, datasz); +} + +static ssize_t +wrap_worker_from(void *data, size_t datasz, json_t *doc) +{ + return worker_from(data, datasz, doc); +} + +static json_t * +wrap_worker_to(const void *data, size_t datasz) +{ + return worker_to(data, datasz); +} + +static ssize_t +wrap_jobresult_from(void *data, size_t datasz, json_t *doc) +{ + return jobresult_from(data, datasz, doc); +} + int apic_get(struct apic *req, const char *fmt, ...) { @@ -171,105 +266,6 @@ return ret; } -static int -get(struct apic *req, const struct converter *cv, const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = perform(req, NULL, fmt, ap); - va_end(ap); - - memset(req, 0, sizeof (*req)); - - if (ret < 0) - return -1; - if (!req->doc || !json_is_object(req->doc)) - return snprintf(req->error, sizeof (req->error), "invalid JSON object received"), -1; - if (cv->unpack(cv->data, cv->datasz, req->doc) < 0) - return snprintf(req->error, sizeof (req->error), "%s", strerror(errno)); - - return 0; -} - -static int -create(struct apic *req, const struct converter *cv, const char *fmt, ...) -{ - va_list ap; - int ret; - json_t *doc; - char *body; - - memset(req, 0, sizeof (*req)); - - if (!(doc = cv->pack(cv->data, cv->datasz))) - return snprintf(req->error, sizeof (req->error), "%s", strerror(errno)); - if (!(body = json_dumps(doc, JSON_COMPACT))) { - json_decref(doc); - return snprintf(req->error, sizeof (req->error), "%s", strerror(errno)); - } - - va_start(ap, fmt); - ret = perform(req, body, fmt, ap); - va_end(ap); - json_decref(doc); - free(body); - - if (cv->unpack(cv->data, cv->datasz, req->doc) < 0) - return snprintf(req->error, sizeof (req->error), "%s", strerror(errno)); - - return 0; -} - -static json_t * -wrap_job_to(const void *data, size_t datasz) -{ - return job_to(data, datasz); -} - -static int -wrap_job_from(void *data, size_t datasz, json_t *doc) -{ - return job_from(data, datasz, doc); -} - -static json_t * -wrap_jobresult_to(const void *data, size_t datasz) -{ - return jobresult_to(data, datasz); -} - -static int -wrap_project_from(void *data, size_t datasz, json_t *doc) -{ - return project_from(data, datasz, doc); -} - -static json_t * -wrap_project_to(const void *data, size_t datasz) -{ - return project_to(data, datasz); -} - -static int -wrap_worker_from(void *data, size_t datasz, json_t *doc) -{ - return worker_from(data, datasz, doc); -} - -static json_t * -wrap_worker_to(const void *data, size_t datasz) -{ - return worker_to(data, datasz); -} - -static int -wrap_jobresult_from(void *data, size_t datasz, json_t *doc) -{ - return jobresult_from(data, datasz, doc); -} - int apic_job_add(struct apic *req, struct job *job) { @@ -287,7 +283,7 @@ } ssize_t -apic_job_todo(struct apic *req, struct job *jobs, size_t jobsz, int worker_id) +apic_job_todo(struct apic *req, struct job *jobs, size_t jobsz, intmax_t worker_id) { assert(req); assert(jobs); @@ -298,7 +294,7 @@ .unpack = wrap_job_from }; - return get(req, &cv, "api/v1/jobs/%d", worker_id); + return get(req, &cv, "api/v1/jobs/%jd", worker_id); } int @@ -318,7 +314,7 @@ } int -apic_project_add(struct apic *req, struct project *project) +apic_project_save(struct apic *req, struct project *project) { assert(req); assert(project); @@ -365,7 +361,7 @@ } int -apic_project_find(struct apic *req, struct project *project) +apic_project_find(struct apic *req, struct project *project, const char *name) { assert(req); assert(project); @@ -376,26 +372,11 @@ .unpack = wrap_project_from }; - return get(req, &cv, "api/v1/projects/%s", project->name); + return get(req, &cv, "api/v1/projects/%s", name); } int -apic_project_find_id(struct apic *req, struct project *project) -{ - assert(req); - assert(project); - - struct converter cv = { - .data = project, - .datasz = 1, - .unpack = wrap_project_from - }; - - return get(req, &cv, "api/v1/projects/%jd", project->id); -} - -int -apic_worker_add(struct apic *req, struct worker *wk) +apic_worker_save(struct apic *req, struct worker *wk) { assert(req); assert(wk); @@ -426,7 +407,7 @@ } int -apic_worker_find(struct apic *req, struct worker *wk) +apic_worker_find(struct apic *req, struct worker *wk, const char *name) { assert(req); assert(wk); @@ -437,20 +418,16 @@ .unpack = wrap_worker_from }; - return get(req, &cv, "api/v1/workers/%s", wk->name); + return get(req, &cv, "api/v1/workers/%s", name); } -int -apic_worker_find_id(struct apic *req, struct worker *wk) +void +apic_finish(struct apic *req) { assert(req); - assert(wk); - struct converter cv = { - .data = wk, - .datasz = 1, - .unpack = wrap_worker_from - }; + if (req->doc) + json_decref(req->doc); - return get(req, &cv, "api/v1/workers/%jd", wk->id); + memset(req, 0, sizeof (*req)); }
--- a/lib/apic.h Tue Jul 19 22:45:44 2022 +0200 +++ b/lib/apic.h Thu Jul 21 20:23:22 2022 +0200 @@ -1,6 +1,9 @@ #ifndef SCI_APIC_H #define SCI_APIC_H +#include <sys/types.h> +#include <stdint.h> + #include <jansson.h> #include "config.h" @@ -44,37 +47,28 @@ apic_job_add(struct apic *, struct job *); ssize_t -apic_job_todo(struct apic *, struct job *, size_t, int); +apic_job_todo(struct apic *, struct job *, size_t, intmax_t); int apic_jobresult_add(struct apic *, struct jobresult *); int -apic_project_add(struct apic *, struct project *); - -int -apic_project_update(struct apic *, struct project *); +apic_project_save(struct apic *, struct project *); ssize_t apic_project_list(struct apic *, struct project *, size_t); int -apic_project_find(struct apic *, struct project *); +apic_project_find(struct apic *, struct project *, const char *); int -apic_project_find_id(struct apic *, struct project *); - -int -apic_worker_add(struct apic *, struct worker *); +apic_worker_save(struct apic *, struct worker *); ssize_t apic_worker_list(struct apic *, struct worker *, size_t); int -apic_worker_find(struct apic *, struct worker *); - -int -apic_worker_find_id(struct apic *, struct worker *); +apic_worker_find(struct apic *, struct worker *, const char *); void apic_finish(struct apic *);
--- a/lib/db.c Tue Jul 19 22:45:44 2022 +0200 +++ b/lib/db.c Thu Jul 21 20:23:22 2022 +0200 @@ -33,15 +33,12 @@ #include "sql/job-add.h" #include "sql/job-todo.h" #include "sql/jobresult-add.h" -#include "sql/project-add.h" -#include "sql/project-update.h" #include "sql/project-find.h" -#include "sql/project-find-id.h" #include "sql/project-list.h" -#include "sql/worker-add.h" +#include "sql/project-save.h" #include "sql/worker-find.h" -#include "sql/worker-find-id.h" #include "sql/worker-list.h" +#include "sql/worker-save.h" #define CHAR(v) (const char *)(v) @@ -59,11 +56,10 @@ { struct project *project = data; - project->id = sqlite3_column_int(stmt, 0); - project->name = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); - project->desc = util_strdup(CHAR(sqlite3_column_text(stmt, 2))); - project->url = util_strdup(CHAR(sqlite3_column_text(stmt, 3))); - project->script = util_strdup(CHAR(sqlite3_column_text(stmt, 4))); + project->name = util_strdup(CHAR(sqlite3_column_text(stmt, 0))); + project->desc = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); + project->url = util_strdup(CHAR(sqlite3_column_text(stmt, 2))); + project->script = util_strdup(CHAR(sqlite3_column_text(stmt, 3))); } static void @@ -71,9 +67,8 @@ { struct worker *w = data; - w->id = sqlite3_column_int(stmt, 0); - w->name = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); - w->desc = util_strdup(CHAR(sqlite3_column_text(stmt, 2))); + w->name = util_strdup(CHAR(sqlite3_column_text(stmt, 0))); + w->desc = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); } static void @@ -81,9 +76,9 @@ { struct job *job = data; - job->id = sqlite3_column_int(stmt, 0); + job->id = sqlite3_column_int64(stmt, 0); job->tag = util_strdup(CHAR(sqlite3_column_text(stmt, 1))); - job->project_id = sqlite3_column_int(stmt, 2); + job->project_name = util_strdup(CHAR(sqlite3_column_text(stmt, 2))); } static void @@ -211,19 +206,10 @@ } int -db_project_add(struct project *p) +db_project_save(struct project *p) { - return (p->id = insert(CHAR(sql_project_add), "ssss", p->name, p->desc, - p->url, p->script)) < 0 ? -1 : 0; -} - -int -db_project_update(const struct project *p) -{ - assert(p); - - return update(CHAR(sql_project_update), "ssssi", p->name, p->desc, - p->url, p->script, p->id); + return insert(CHAR(sql_project_save), "ssss", p->name, p->desc, + p->url, p->script) < 0 ? -1 : 0; } ssize_t @@ -253,24 +239,11 @@ } int -db_project_find_id(struct project *project, intmax_t id) -{ - struct list sel = { - .unpack = project_unpacker, - .data = project, - .datasz = 1, - .elemwidth = sizeof (*project), - }; - - return list(&sel, CHAR(sql_project_find_id), "i", id) == 1 ? 0 : -1; -} - -int -db_worker_add(struct worker *wk) +db_worker_save(struct worker *wk) { assert(wk); - return (wk->id = insert(CHAR(sql_worker_add), "ss", wk->name, wk->desc)) < 0 ? -1 : 0; + return insert(CHAR(sql_worker_save), "ss", wk->name, wk->desc) < 0 ? -1 : 0; } ssize_t @@ -302,29 +275,16 @@ } int -db_worker_find_id(struct worker *wk, intmax_t id) -{ - struct list sel = { - .unpack = worker_unpacker, - .data = wk, - .datasz = 1, - .elemwidth = sizeof (*wk), - }; - - return list(&sel, CHAR(sql_worker_find_id), "i", id) == 1 ? 0 : -1; -} - -int db_job_add(struct job *job) { assert(job); return (job->id = insert(CHAR(sql_job_add), - "si", job->tag, job->project_id)) < 0 ? -1 : 0; + "ss", job->tag, job->project_name)) < 0 ? -1 : 0; } ssize_t -db_job_todo(struct job *jobs, size_t jobsz, int worker_id) +db_job_todo(struct job *jobs, size_t jobsz, const char *worker) { assert(jobs); @@ -335,7 +295,7 @@ .elemwidth = sizeof (*jobs), }; - return list(&sel, CHAR(sql_job_todo), "iiz", worker_id, worker_id, jobsz); + return list(&sel, CHAR(sql_job_todo), "ssz", worker, worker, jobsz); } int @@ -343,8 +303,8 @@ { assert(r); - return (r->id = insert(CHAR(sql_jobresult_add), "iiis", r->job_id, - r->worker_id, r->exitcode, r->log)) < 0 ? -1 : 0; + return (r->id = insert(CHAR(sql_jobresult_add), "jsis", r->job_id, + r->worker_name, r->exitcode, r->log)) < 0 ? -1 : 0; } void
--- a/lib/db.h Tue Jul 19 22:45:44 2022 +0200 +++ b/lib/db.h Thu Jul 21 20:23:22 2022 +0200 @@ -35,16 +35,13 @@ db_job_add(struct job *); ssize_t -db_job_todo(struct job *, size_t, int); +db_job_todo(struct job *, size_t, const char *); int db_jobresult_add(struct jobresult *); int -db_project_add(struct project *); - -int -db_project_update(const struct project *); +db_project_save(struct project *); ssize_t db_project_list(struct project *, size_t); @@ -53,10 +50,7 @@ db_project_find(struct project *, const char *); int -db_project_find_id(struct project *, intmax_t); - -int -db_worker_add(struct worker *); +db_worker_save(struct worker *); ssize_t db_worker_list(struct worker *, size_t); @@ -64,9 +58,6 @@ int db_worker_find(struct worker *, const char *); -int -db_worker_find_id(struct worker *, intmax_t); - void db_finish(void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/strlcpy.c Thu Jul 21 20:23:22 2022 +0200 @@ -0,0 +1,49 @@ +/* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns strlen(src); if retval >= dsize, truncation occurred. + */ +size_t +util_strlcpy(char *dst, const char *src, size_t dsize) +{ + const char *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = '\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/strtonum.c Thu Jul 21 20:23:22 2022 +0200 @@ -0,0 +1,65 @@ +/* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */ + +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +util_strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +}
--- a/lib/types.c Tue Jul 19 22:45:44 2022 +0200 +++ b/lib/types.c Thu Jul 21 20:23:22 2022 +0200 @@ -28,9 +28,9 @@ static inline json_t * job_packer(const struct job *job) { - return json_pack("{si si ss}", + return json_pack("{si ss ss}", "id", job->id, - "project_id", job->project_id, + "project_name", job->project_name, "tag", job->tag ); } @@ -38,14 +38,16 @@ static inline int job_unpacker(struct job *job, json_t *doc) { - const int ret = json_unpack(doc, "{si si ss}", + const int ret = json_unpack(doc, "{si ss ss}", "id", &job->id, - "project_id", &job->project_id, + "project_name", &job->project_name, "tag", &job->tag ); - if (ret == 0) + if (ret == 0) { + job->project_name = util_strdup(job->project_name); job->tag = util_strdup(job->tag); + } return ret; } @@ -53,10 +55,10 @@ static inline json_t * jobresult_packer(const struct jobresult *res) { - return json_pack("{si si si si ss}", + return json_pack("{si si ss si ss}", "id", res->id, "job_id", res->job_id, - "worker_id", res->worker_id, + "worker_name", res->worker_name, "exitcode", res->exitcode, "log", res->log ); @@ -65,16 +67,18 @@ static inline int jobresult_unpacker(struct jobresult *res, json_t *doc) { - const int ret = json_unpack(doc, "{si si si si ss}", + const int ret = json_unpack(doc, "{si si ss si ss}", "id", &res->id, "job_id", &res->job_id, - "worker_id", &res->worker_id, + "worker_name", &res->worker_name, "exitcode", &res->exitcode, "log", &res->log ); - if (ret == 0) + if (ret == 0) { + res->worker_name = util_strdup(res->worker_name); res->log = util_strdup(res->log); + } return ret; } @@ -82,8 +86,7 @@ static inline json_t * worker_packer(const struct worker *w) { - return json_pack("{si ss ss}", - "id", w->id, + return json_pack("{ss ss}", "name", w->name, "desc", w->desc ); @@ -92,8 +95,7 @@ static inline int worker_unpacker(struct worker *w, json_t *doc) { - const int ret = json_unpack(doc, "{si ss ss}", - "id", &w->id, + const int ret = json_unpack(doc, "{ss ss}", "name", &w->name, "desc", &w->desc ); @@ -109,8 +111,7 @@ static inline json_t * project_packer(struct project *p) { - return json_pack("{si ss ss ss ss}", - "id", p->id, + return json_pack("{ss ss ss ss}", "name", p->name, "desc", p->desc, "url", p->url, @@ -121,8 +122,7 @@ static inline int project_unpacker(struct project *p, json_t *doc) { - const int ret = json_unpack(doc, "{si ss ss ss ss}", - "id", &p->id, + const int ret = json_unpack(doc, "{ss ss ss ss}", "name", &p->name, "desc", &p->desc, "url", &p->url, @@ -197,6 +197,14 @@ return from(jobs, jobsz, sizeof (*jobs), doc, (unpacker)job_unpacker); } +void +job_finish(struct job *job) +{ + assert(job); + + free(job->tag); +} + json_t * jobresult_to(const struct jobresult *res, size_t resz) { @@ -214,6 +222,14 @@ return from(res, resz, sizeof (*res), doc, (unpacker)jobresult_unpacker); } +void +jobresult_finish(struct jobresult *res) +{ + assert(res); + + free(res->log); +} + json_t * worker_to(const struct worker *w, size_t wsz) { @@ -231,6 +247,15 @@ return from(w, wsz, sizeof (*w), doc, (unpacker)worker_unpacker); } +void +worker_finish(struct worker *w) +{ + assert(w); + + free(w->name); + free(w->desc); +} + json_t * project_to(const struct project *proj, size_t projsz) { @@ -247,3 +272,14 @@ return from(proj, projsz, sizeof (*proj), doc, (unpacker)project_unpacker); } + +void +project_finish(struct project *proj) +{ + assert(proj); + + free(proj->name); + free(proj->desc); + free(proj->url); + free(proj->script); +}
--- a/lib/types.h Tue Jul 19 22:45:44 2022 +0200 +++ b/lib/types.h Thu Jul 21 20:23:22 2022 +0200 @@ -27,26 +27,24 @@ struct job { intmax_t id; - int project_id; + char *project_name; char *tag; }; struct jobresult { intmax_t id; int job_id; - int worker_id; + char *worker_name; int exitcode; char *log; }; struct worker { - intmax_t id; char *name; char *desc; }; struct project { - intmax_t id; char *name; char *desc; char *url;
--- a/lib/util.h Tue Jul 19 22:45:44 2022 +0200 +++ b/lib/util.h Thu Jul 21 20:23:22 2022 +0200 @@ -69,4 +69,7 @@ void util_die(const char *, ...); +long long +util_strtonum(const char *, long long, long long, const char **); + #endif /* !SCI_UTIL_H */
--- a/man/scid.8.in Tue Jul 19 22:45:44 2022 +0200 +++ b/man/scid.8.in Thu Jul 21 20:23:22 2022 +0200 @@ -23,37 +23,36 @@ .\" SYNOPSIS .Sh SYNOPSIS .Nm +.Op Fl f .Op Fl d Ar database-file -.Op Fl s Ar socket-file .\" DESCRIPTION .Sh DESCRIPTION The .Nm -program is the main controller daemon responsible of the database access. It -opens it, creates if does not exist and then update its content. +program is the main controller daemon responsible of the database access and +web content. It opens it, creates if does not exist and then update its +content. +.Pp +After that, it opens a CGI/FastCGI service to get HTTP requests either from a +web browser or through the dedicated +.Xr scictl 1 +utility. .Pp It is part of the .Xr sci 7 continuous integration framework. .Pp -It also opens a UNIX socket connection on -.Pa @VARDIR@/run/sci.sock -by default unless option -.Fl s -has been specified, it will opens it on -.Ar database-file -argument. -.Pp -Clients connect to -.Nm -and make requests to create, update or list projects, workers and jobs. This can -either be done using -.Nm scictl -utility or the HTTP interface using -.Nm sciwebd . +Available options: +.Bl -tag +.It Fl f +Runs as FastCGI process. +.It Fl d Ar database-file +Use path specified +.Pa database-file +as alternative database location. +.El .\" SEE ALSO .Sh SEE ALSO .Xr sci 7 , .Xr scictl 8 , -.Xr sciwebd 8 , .Xr sciworkerd 8
--- a/scictl/scictl.c Tue Jul 19 22:45:44 2022 +0200 +++ b/scictl/scictl.c Thu Jul 21 20:23:22 2022 +0200 @@ -16,64 +16,81 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <err.h> +#include <limits.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdnoreturn.h> #include <unistd.h> +#include "apic.h" #include "config.h" -#include "req.h" #include "types.h" #include "util.h" -noreturn static void +static void usage(void) { - fprintf(stderr, "usage: %s [-s sock] command [args...]\n", getprogname()); + fprintf(stderr, "usage: %s [-u baseurl] command [args...]\n", getprogname()); exit(1); } -noreturn static void +static void help(void) { - fprintf(stderr, "usage: %s job-add project tag\n", getprogname()); - fprintf(stderr, " %s job-todo worker\n", getprogname()); - fprintf(stderr, " %s jobresult-add id worker exitcode console\n", getprogname()); - fprintf(stderr, " %s project-add name desc url script\n", getprogname()); - fprintf(stderr, " %s project-info name\n", getprogname()); - fprintf(stderr, " %s project-list\n", getprogname()); - fprintf(stderr, " %s project-update name key value\n", getprogname()); - fprintf(stderr, " %s worker-add name desc\n", getprogname()); - fprintf(stderr, " %s worker-list\n", getprogname()); + fprintf(stderr, "usage: scictl job-add project tag\n"); + fprintf(stderr, " scictl job-todo worker\n"); + fprintf(stderr, " scictl jobresult-add id worker exitcode console\n"); + fprintf(stderr, " scictl project-add name desc url script\n"); + fprintf(stderr, " scictl project-info name\n"); + fprintf(stderr, " scictl project-list\n"); + fprintf(stderr, " scictl project-update name key value\n"); + fprintf(stderr, " scictl worker-add name desc\n"); + fprintf(stderr, " scictl worker-list\n"); exit(0); } +static inline void +replace(char **str, const char *new) +{ + free(*str); + *str = util_strdup(new); +} + +long long +toint(const char *s) +{ + long long v; + const char *err; + + v = util_strtonum(s, 0, LLONG_MAX, &err); + + if (err) + util_die("abort: %s\n", err); + + return v; +} + static char * readfile(const char *path) { FILE *fp, *str; - char buf[BUFSIZ], *console; - size_t nr; + char buf[BUFSIZ], *console = NULL; + size_t nr, consolesz = 0; if (strcmp(path, "-") == 0) fp = stdin; else if (!(fp = fopen(path, "r"))) - err(1, "%s", path); + util_die("abort: %s: %s\n", path, strerror(errno)); - console = util_calloc(1, SCI_MSG_MAX); - - if (!(str = fmemopen(console, SCI_MSG_MAX, "w"))) - err(1, "fmemopen"); + if (!(str = open_memstream(&console, &consolesz))) + util_die("abort: open_memstream: %s\n", strerror(errno)); while ((nr = fread(buf, 1, sizeof (buf), fp)) > 0) fwrite(buf, 1, nr, str); - if ((ferror(fp) && !feof(fp)) || (ferror(str) && !feof(str))) { - free(console); - console = NULL; - } + if ((ferror(fp) && !feof(fp)) || (ferror(str) && !feof(str))) + util_die("abort: %s\n", strerror(errno)); fclose(str); fclose(fp); @@ -87,285 +104,218 @@ return fwrite(s, w, n, data); } -static json_t * -parse(const char *data) -{ - json_t *doc; - json_error_t err; - - if (!(json_loads(doc, 0, &err))) - die("abort: unable to parse JSON: %s\n", err.text); - - return doc; -} - -static json_t * -get(const char *url) -{ - CURL *curl; - CURLcode code; - FILE *fp; - char buf[HTTP_BUF_MAX]; - long ret; - - if (!(fp = fmemopen(buf, sizeof (buf), "w"))) - die("abort: %s", strerror(errno)); - - curl = curl_easy_init(); - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, extract); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3L); - code = curl_easy_perform(curl); - - if (code != CURLE_OK) - die("abort: %s", curl_easy_strerror(code)); - - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret); - - if (ret != 200) - die("abort: HTTP %ld\n", ret); - - curl_easy_cleanup(curl); - fclose(fp); - - return parse(buf); -} - -static struct req +static void cmd_job_add(int argc, char **argv) { struct job job = {0}; - struct project project = {0}; + struct apic req; + + if (argc < 3) + usage(); + + job.project_name = util_strdup(argv[1]); + job.tag = util_strdup(argv[2]); + + if (apic_job_add(&req, &job) < 0) + util_die("abort: %s\n", req.error); + + apic_finish(&req); + job_finish(&job); +} + +static void +cmd_job_todo(int argc, char **argv) +{ + struct job jobs[SCI_JOB_LIST_MAX] = {0}; + size_t jobsz; + struct apic req; if (argc < 2) usage(); - project.name = argv[0]; - - if (_project_find(&project, argv[0])).status) - return rp; - - job.project_id = project.id; - job.tag = argv[1]; - - rj = req_job_add(&job); - req_finish(&rp); - - return rj; -} - -static struct req -cmd_job_todo(int argc, char **argv) -{ - struct project projects[SCI_PROJECT_MAX] = {0}; - struct job jobs[SCI_JOB_LIST_MAX] = {0}; - struct req rp, rj; - size_t projectsz = UTIL_SIZE(projects), jobsz = UTIL_SIZE(jobs); - - if (argc < 1) - usage(); - - /* First retrieve projects for a better listing. */ - if ((rp = req_project_list(projects, &projectsz)).status) - return rp; - - if ((rj = req_job_todo(jobs, &jobsz, argv[0])).status) { - req_finish(&rp); - return rj; - } + if ((jobsz = apic_job_todo(&req, jobs, UTIL_SIZE(jobs), toint(argv[1])))) + util_die("abort: %s\n", req.error); for (size_t i = 0; i < jobsz; ++i) { - const char *project = "unknown"; - - /* Find project if exists (it should). */ - for (size_t p = 0; p < projectsz; ++p) { - if (projects[p].id == jobs[i].project_id) { - project = projects[p].name; - break; - } - } - - printf("%-16s%d\n", "id:", jobs[i].id); + printf("%-16s%jd\n", "id:", jobs[i].id); printf("%-16s%s\n", "tag:", jobs[i].tag); - printf("%-16s%s\n", "project:", project); + printf("%-16s%s\n", "project:", jobs[i].project_name); if (i + 1 < jobsz) printf("\n"); + + job_finish(&jobs[i]); } - req_finish(&rp); - - return rj; + apic_finish(&req); } -static struct req +static void cmd_jobresult_add(int argc, char **argv) { struct jobresult res = {0}; - struct worker wk = {0}; - struct req rw, rj; - char *log; + struct apic req; + + if (argc < 5) + usage(); + + res.job_id = toint(argv[1]); + res.worker_name = util_strdup(argv[2]); + res.exitcode = toint(argv[3]); + res.log = readfile(argv[4]); + + if (apic_jobresult_add(&req, &res) < 0) + util_die("abort: unable to add job result: %s\n", req.error); + + apic_finish(&req); + jobresult_finish(&res); +} + +static void +cmd_project_add(int argc, char **argv) +{ + struct project pc = {0}; + struct apic req; if (argc < 5) usage(); - /* Find worker id. */ - if ((rw = req_worker_find(&wk, argv[1])).status) - return rw; + pc.name = util_strdup(argv[1]); + pc.desc = util_strdup(argv[2]); + pc.url = util_strdup(argv[3]); + pc.script = readfile(argv[4]); - res.job_id = strtoll(argv[0], NULL, 10); - res.exitcode = strtoll(argv[2], NULL, 10); - res.worker_id = wk.id; - res.log = log = readfile(argv[3]); - rj = req_jobresult_add(&res); + if (apic_project_save(&req, &pc) < 0) + util_die("abort: unable to create project: %s\n", req.error); - free(log); - req_finish(&rw); - - return rj; + apic_finish(&req); + project_finish(&pc); } -static struct req -cmd_project_add(int argc, char **argv) +static void +cmd_project_update(int argc, char **argv) { - struct project pc = {0}; - struct req res; - char *script; + struct project pc; + struct apic req; if (argc < 4) usage(); - pc.name = argv[0]; - pc.desc = argv[1]; - pc.url = argv[2]; - pc.script = script = readfile(argv[3]); - res = req_project_add(&pc); + if (apic_project_find(&req, &pc, argv[1]) < 0) + util_die("abort: unable to find project: %s\n", req.error); - free(script); + if (strcmp(argv[2], "name") == 0) + replace(&pc.name, argv[3]); + else if (strcmp(argv[2], "desc") == 0) + replace(&pc.desc, argv[3]); + else if (strcmp(argv[2], "url") == 0) + replace(&pc.url, argv[3]); + else if (strcmp(argv[2], "script") == 0) + replace(&pc.script, readfile(argv[3])); - return res; + if (apic_project_save(&req, &pc) < 0) + util_die("abort: unable to save project: %s\n", req.error); + + apic_finish(&req); + project_finish(&pc); } -static struct req -cmd_project_update(int argc, char **argv) -{ - struct project pc; - struct req rget, rsend; - char *script = NULL; - - if (argc < 3) - help(); - - if ((rget = req_project_find(&pc, argv[0])).status) - return rget; - - if (strcmp(argv[1], "name") == 0) - pc.name = argv[2]; - else if (strcmp(argv[1], "desc") == 0) - pc.desc = argv[2]; - else if (strcmp(argv[1], "url") == 0) - pc.url = argv[2]; - else if (strcmp(argv[1], "script") == 0) - pc.script = script = readfile(argv[2]); - - rsend = req_project_update(&pc); - - req_finish(&rget); - free(script); - - return rsend; -} - -static struct req +static void cmd_project_info(int argc, char **argv) { struct project project = {0}; - struct req req; + struct apic req; - if (argc < 1) + if (argc < 2) usage(); - if ((req = req_project_find(&project, argv[0])).status) - return req; + if (apic_project_find(&req, &project, argv[1]) < 0) + util_die("abort: unable to find project: %s\n", req.error); - printf("%-16s%d\n", "id:", project.id); printf("%-16s%s\n", "name:", project.name); printf("%-16s%s\n", "desc:", project.desc); printf("%-16s%s\n", "url:", project.url); printf("\n"); printf("%s", project.script); - return req; + apic_finish(&req); + project_finish(&project); } -static struct req +static void cmd_project_list(int argc, char **argv) { (void)argc; (void)argv; struct project projects[SCI_PROJECT_MAX] = {0}; - struct req req; - size_t projectsz = UTIL_SIZE(projects); + struct apic req; + ssize_t projectsz; - if ((req = req_project_list(projects, &projectsz)).status) - return req; + if ((projectsz = apic_project_list(&req, projects, UTIL_SIZE(projects))) < 0) + util_die("abort: unable to list projects: %s\n", req.error); for (size_t i = 0; i < projectsz; ++i) { - printf("%-16s%d\n", "id:", projects[i].id); printf("%-16s%s\n", "name:", projects[i].name); printf("%-16s%s\n", "desc:", projects[i].desc); printf("%-16s%s\n", "url:", projects[i].url); if (i + 1 < projectsz) printf("\n"); + + project_finish(&projects[i]); } - return req; + apic_finish(&req); } -static struct req +static void cmd_worker_add(int argc, char **argv) { struct worker wk = {0}; + struct apic req; - if (argc < 2) + if (argc < 3) usage(); - wk.name = argv[0]; - wk.desc = argv[1]; + wk.name = util_strdup(argv[1]); + wk.desc = util_strdup(argv[2]); - return req_worker_add(&wk); + if (apic_worker_save(&req, &wk) < 0) + util_die("abort: unable to save worker: %s\n", req.error); + + worker_finish(&wk); + apic_finish(&req); } -static struct req +static void cmd_worker_list(int argc, char **argv) { (void)argc; (void)argv; struct worker wk[SCI_WORKER_MAX]; - struct req req; - size_t wksz = UTIL_SIZE(wk); + struct apic req; + ssize_t wksz; - if ((req = req_worker_list(wk, &wksz)).status) - return req; + if ((wksz = apic_worker_list(&req, wk, UTIL_SIZE(wk))) < 0) + util_die("abort: unable to list worker: %s\n", req.error); for (size_t i = 0; i < wksz; ++i) { - printf("%-16s%d\n", "id:", wk[i].id); printf("%-16s%s\n", "name:", wk[i].name); printf("%-16s%s\n", "desc:", wk[i].desc); if (i + 1 < wksz) printf("\n"); + + worker_finish(&wk[i]); } - return req; + apic_finish(&req); } static struct { const char *name; - struct req (*exec)(int, char **); + void (*exec)(int, char **); } commands[] = { { "job-add", cmd_job_add }, { "job-todo", cmd_job_todo }, @@ -382,14 +332,21 @@ int main(int argc, char **argv) { - int ch, cmdfound = 0; + int ch; - setprogname("scictl"); + opterr = 0; + setenv("POSIXLY_CORRECT", "1", 1); - while ((ch = getopt(argc, argv, "s:")) != -1) { + while ((ch = getopt(argc, argv, "u:")) != -1) { switch (ch) { - case 's': - req_set_path(optarg); + case 'u': + util_strlcpy(apiconf.baseurl, optarg, sizeof (apiconf.baseurl)); + break; + case '?': + util_die("abort: invalid option: %c\n", ch); + break; + case ':': + util_die("abort: missing value for option %c\n", ch); break; default: break; @@ -399,26 +356,19 @@ argc -= optind; argv += optind; - if (argc <= 0) + optind = 1; + + if (argc < 1) usage(); if (strcmp(argv[0], "help") == 0) help(); for (size_t i = 0; commands[i].name; ++i) { - struct req res; - if (strcmp(commands[i].name, argv[0]) == 0) { - res = commands[i].exec(--argc, ++argv); - cmdfound = 1; - - if (res.status) - warnx("%s", json_string_value(json_object_get(res.msg, "error"))); - - req_finish(&res); - break; + commands[i].exec(argc, argv); + return 0; } } - if (!cmdfound) - errx(1, "abort: command %s not found", argv[0]); + util_die("abort: invalid command: %s\n", argv[0]); }
--- a/scid/page-api-projects.c Tue Jul 19 22:45:44 2022 +0200 +++ b/scid/page-api-projects.c Thu Jul 21 20:23:22 2022 +0200 @@ -53,7 +53,7 @@ log_warn("api/post: invalid JSON input: %s", err.text); else if (project_from(&res, 1, doc) < 0) log_warn("api/post: failed to decode parameters"); - else if (db_project_add(&res) < 0) + else if (db_project_save(&res) < 0) log_warn("api/post: database save error"); else ret = 0; @@ -96,19 +96,6 @@ } static void -get_one_id(struct kreq *r, intmax_t id) -{ - struct project project = {0}; - - if (db_project_find_id(&project, id) < 0) - page(r, NULL, KHTTP_500, KMIME_APP_JSON, NULL); - else { - push(r, &project); - project_finish(&project); - } -} - -static void get_all(struct kreq *r) { struct project projects[SCI_PROJECT_MAX] = {0}; @@ -129,21 +116,18 @@ } /* - * GET /api/v1/projects[/<name|id>] - * ------------------------------ + * GET /api/v1/projects[/<name>] + * ----------------------------- * * Retrieve one project or a list of projects depending on the presence of - * <name> or <id> parameter. + * <name> parameter. */ static void get(struct kreq *r) { - char name[128]; - intmax_t id; + char name[128] = {0}; - if (sscanf(r->path, "v1/projects/%jd", &id) == 1) - get_one_id(r, id); - else if (sscanf(r->path, "v1/projects/%127s", name) == 1) + if (sscanf(r->path, "v1/projects/%127s", name) == 1) get_one(r, name); else get_all(r);
--- a/scid/page-api-todo.c Tue Jul 19 22:45:44 2022 +0200 +++ b/scid/page-api-todo.c Thu Jul 21 20:23:22 2022 +0200 @@ -76,7 +76,7 @@ /* * GET /api/v1/todo/<worker-name> - * ---------------- + * ------------------------------ * * Retrieve a list of jobs to perform for this worker name. */ @@ -85,14 +85,8 @@ { struct job jobs[SCI_JOB_LIST_MAX]; ssize_t jobsz; - struct worker wk = {0}; - if (db_worker_find(&wk, util_basename(r->path)) < 0) { - page(r, NULL, KHTTP_404, KMIME_APP_JSON, NULL); - return; - } - - if ((jobsz = db_job_todo(jobs, UTIL_SIZE(jobs), wk.id)) < 0) + if ((jobsz = db_job_todo(jobs, UTIL_SIZE(jobs), util_basename(r->path))) < 0) page(r, NULL, KHTTP_500, KMIME_APP_JSON, NULL); else { khttp_head(r, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_APP_JSON]); @@ -107,7 +101,7 @@ } void -page_api_v1_jobs(struct kreq *r) +page_api_v1_todo(struct kreq *r) { assert(r);
--- a/scid/page-api-workers.c Tue Jul 19 22:45:44 2022 +0200 +++ b/scid/page-api-workers.c Thu Jul 21 20:23:22 2022 +0200 @@ -35,7 +35,7 @@ log_warn("api/post: invalid JSON input: %s", err.text); else if (worker_from(&res, 1, doc) < 0) log_warn("api/post: failed to decode parameters"); - else if (db_worker_add(&res) < 0) + else if (db_worker_save(&res) < 0) log_warn("api/post: database save error"); else ret = 0; @@ -78,19 +78,6 @@ } static void -get_one_id(struct kreq *r, intmax_t id) -{ - struct worker worker = {0}; - - if (db_worker_find_id(&worker, id) < 0) - page(r, NULL, KHTTP_500, KMIME_APP_JSON, NULL); - else { - push(r, &worker); - worker_finish(&worker); - } -} - -static void get_all(struct kreq *r) { struct worker workers[SCI_PROJECT_MAX] = {0}; @@ -111,21 +98,18 @@ } /* - * GET /api/v1/workers[/<name|id>] - * ------------------------------ + * GET /api/v1/workers[/<name>] + * ---------------------------- * * Retrieve one worker or a list of workers depending on the presence of - * <name> or <id> parameter. + * <name> parameter. */ static void get(struct kreq *r) { - char name[128]; - int id; + char name[128] = {0}; - if (sscanf(r->path, "v1/workers/%d", &id) == 1) - get_one_id(r, id); - else if (sscanf(r->path, "v1/workers/%127s", name) == 1) + if (sscanf(r->path, "v1/workers/%127s", name) == 1) get_one(r, name); else get_all(r);
--- a/sql/init.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/init.sql Thu Jul 21 20:23:22 2022 +0200 @@ -17,7 +17,7 @@ -- CREATE TABLE IF NOT EXISTS project( - `name` TEXT NOT NULL UNIQUE, + `name` TEXT NOT NULL PRIMARY KEY, `desc` TEXT NOT NULL, `url` TEXT NOT NULL, `script` TEXT NOT NULL, @@ -25,20 +25,20 @@ ); CREATE TABLE IF NOT EXISTS worker( - `name` TEXT NOT NULL UNIQUE, + `name` TEXT NOT NULL PRIMARY KEY, `desc` TEXT NOT NULL, `date` INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) ); CREATE TABLE IF NOT EXISTS job( `tag` TEXT NOT NULL UNIQUE, - `project_id` INTEGER NOT NULL REFERENCES project (id), + `project_name` INTEGER NOT NULL REFERENCES project (name), `date` INTEGER NOT NULL DEFAULT (strftime('%s', 'now')) ); CREATE TABLE IF NOT EXISTS jobresult( `job_id` INTEGER NOT NULL REFERENCES job (id), - `worker_id` INTEGER NOT NULL REFERENCES worker (id), + `worker_name` INTEGER NOT NULL REFERENCES worker (name), `exitcode` INTEGER DEFAULT 0, `console` TEXT DEFAULT NULL, `date` INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
--- a/sql/job-add.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/job-add.sql Thu Jul 21 20:23:22 2022 +0200 @@ -18,5 +18,5 @@ INSERT INTO job( `tag`, - `project_id` + `project_name` ) VALUES (?, ?)
--- a/sql/job-todo.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/job-todo.sql Thu Jul 21 20:23:22 2022 +0200 @@ -23,17 +23,17 @@ -- SELECT `job`.`rowid` , `job`.`tag` - , `job`.`project_id` + , `job`.`project_name` FROM `job` WHERE `job`.`rowid` NOT IN ( SELECT `jobresult`.`job_id` FROM `jobresult` - WHERE `jobresult`.`worker_id` = ? + WHERE `jobresult`.`worker_name` = ? ) AND `job`.`date` >= ( SELECT `worker`.`date` FROM `worker` - WHERE `worker`.`rowid` = ? + WHERE `worker`.`name` = ? ) LIMIT ?
--- a/sql/jobresult-add.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/jobresult-add.sql Thu Jul 21 20:23:22 2022 +0200 @@ -18,7 +18,7 @@ INSERT INTO jobresult( `job_id`, - `worker_id`, + `worker_name`, `exitcode`, `console` ) VALUES (?, ?, ?, ?)
--- a/sql/project-add.sql Tue Jul 19 22:45:44 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ --- --- project-add.sql -- create a new project --- --- Copyright (c) 2021 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -INSERT INTO project( - `name`, - `desc`, - `url`, - `script` -) VALUES (?, ?, ?, ?)
--- a/sql/project-find-id.sql Tue Jul 19 22:45:44 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ --- --- project-find-id.sql -- find project by id --- --- Copyright (c) 2021 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -SELECT rowid - , * - FROM `project` - WHERE `rowid` = ? - LIMIT 1
--- a/sql/project-find.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/project-find.sql Thu Jul 21 20:23:22 2022 +0200 @@ -16,8 +16,7 @@ -- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- -SELECT rowid - , * +SELECT * FROM `project` WHERE `name` = ? LIMIT 1
--- a/sql/project-list.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/project-list.sql Thu Jul 21 20:23:22 2022 +0200 @@ -16,7 +16,6 @@ -- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- -SELECT rowid - , * +SELECT * FROM `project` LIMIT ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sql/project-save.sql Thu Jul 21 20:23:22 2022 +0200 @@ -0,0 +1,24 @@ +-- +-- project-save.sql -- create a new project +-- +-- Copyright (c) 2021 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +REPLACE INTO project( + `name`, + `desc`, + `url`, + `script` +) VALUES (?, ?, ?, ?)
--- a/sql/project-update.sql Tue Jul 19 22:45:44 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ --- --- project-update.sql -- update existing project by id --- --- Copyright (c) 2021 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -UPDATE `project` - SET `name` = ? - , `desc` = ? - , `url` = ? - , `script` = ? - WHERE `rowid` = ?
--- a/sql/worker-add.sql Tue Jul 19 22:45:44 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ --- --- worker-add -- create a new worker --- --- Copyright (c) 2021 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -INSERT INTO worker( - `name`, - `desc` -) VALUES (?, ?)
--- a/sql/worker-find-id.sql Tue Jul 19 22:45:44 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ --- --- worker-find-id.sql -- find worker by id --- --- Copyright (c) 2021 David Demelier <markand@malikania.fr> --- --- Permission to use, copy, modify, and/or distribute this software for any --- purpose with or without fee is hereby granted, provided that the above --- copyright notice and this permission notice appear in all copies. --- --- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES --- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR --- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES --- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN --- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF --- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --- - -SELECT rowid - , * - FROM `worker` - WHERE `rowid` = ? - LIMIT 1
--- a/sql/worker-find.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/worker-find.sql Thu Jul 21 20:23:22 2022 +0200 @@ -16,8 +16,7 @@ -- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- -SELECT rowid - , * +SELECT * FROM `worker` WHERE `name` = ? LIMIT 1
--- a/sql/worker-list.sql Tue Jul 19 22:45:44 2022 +0200 +++ b/sql/worker-list.sql Thu Jul 21 20:23:22 2022 +0200 @@ -16,7 +16,6 @@ -- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -- -SELECT rowid - , * +SELECT * FROM `worker` LIMIT ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sql/worker-save.sql Thu Jul 21 20:23:22 2022 +0200 @@ -0,0 +1,22 @@ +-- +-- worker-save -- create a new worker +-- +-- Copyright (c) 2021 David Demelier <markand@malikania.fr> +-- +-- Permission to use, copy, modify, and/or distribute this software for any +-- purpose with or without fee is hereby granted, provided that the above +-- copyright notice and this permission notice appear in all copies. +-- +-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-- + +REPLACE INTO worker( + `name`, + `desc` +) VALUES (?, ?)