diff scictl/scictl.c @ 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 de4bf839b565
children 2cb228f23f53
line wrap: on
line diff
--- 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]);
 }