view scictl.c @ 13:67348ec46425

man: add manual pages
author David Demelier <markand@malikania.fr>
date Wed, 30 Jun 2021 11:33:54 +0200
parents be3ec0e6bb8f
children 3051ef92173a
line wrap: on
line source

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdnoreturn.h>
#include <unistd.h>

#include "config.h"
#include "req.h"
#include "types.h"
#include "util.h"

noreturn static void
usage(void)
{
	fprintf(stderr, "usage: %s [-s sock] command [args...]\n", getprogname());
	exit(1);
}

noreturn 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());
	exit(0);
}

static char *
readfile(const char *path)
{
	FILE *fp, *str;
	char buf[BUFSIZ], *console;
	size_t nr;

	if (strcmp(path, "-") == 0)
		fp = stdin;
	else if (!(fp = fopen(path, "r")))
		err(1, "%s", path);

	console = util_calloc(1, SCI_MSG_MAX);

	if (!(str = fmemopen(console, SCI_MSG_MAX, "w")))
		err(1, "fmemopen");

	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;
	}

	fclose(str);
	fclose(fp);

	return console;
}

static struct req
cmd_job_add(int argc, char **argv)
{
	struct job job = {0};
	struct project project = {0};
	struct req rp, rj;

	if (argc < 2)
		usage();

	if ((rp = req_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;
	}

	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%s\n", "tag:", jobs[i].tag);
		printf("%-16s%s\n", "project:", project);

		if (i + 1 < jobsz)
			printf("\n");
	}

	req_finish(&rp);
	
	return rj;
}

static struct req
cmd_jobresult_add(int argc, char **argv)
{
	struct jobresult res = {0};
	struct worker wk = {0};
	struct req rw, rj;
	char *log;

	if (argc < 5)
		usage();

	/* Find worker id. */
	if ((rw = req_worker_find(&wk, argv[1])).status)
		return rw;

	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);

	free(log);
	req_finish(&rw);

	return rj;
}

static struct req
cmd_project_add(int argc, char **argv)
{
	struct project pc = {0};
	struct req res;
	char *script;

	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);

	free(script);

	return res;
}

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
cmd_project_info(int argc, char **argv)
{
	struct project project = {0};
	struct req req;

	if (argc < 1)
		usage();
	if ((req = req_project_find(&project, argv[0])).status)
		return req;

	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;
}

static struct req
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);

	if ((req = req_project_list(projects, &projectsz)).status)
		return req;

	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");
	}

	return req;
}

static struct req
cmd_worker_add(int argc, char **argv)
{
	struct worker wk = {0};

	if (argc < 2)
		usage();

	wk.name = argv[0];
	wk.desc = argv[1];

	return req_worker_add(&wk);
}

static struct req
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);

	if ((req = req_worker_list(wk, &wksz)).status)
		return req;

	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");
	}

	return req;
}

static struct {
	const char *name;
	struct req (*exec)(int, char **);
} commands[] = {
	{ "job-add",            cmd_job_add             },
	{ "job-todo",           cmd_job_todo            },
	{ "jobresult-add",      cmd_jobresult_add       },
	{ "project-add",        cmd_project_add         },
	{ "project-info",       cmd_project_info        },
	{ "project-list",       cmd_project_list        },
	{ "project-update",     cmd_project_update      },
	{ "worker-add",         cmd_worker_add          },
	{ "worker-list",        cmd_worker_list         },
	{ NULL,                 NULL                    }
};

int
main(int argc, char **argv)
{
	int ch, cmdfound = 0;

	setprogname("scictl");

	while ((ch = getopt(argc, argv, "s:")) != -1) {
		switch (ch) {
		case 's':
			req_set_path(optarg);
			break;
		default:
			break;
		}
	}

	argc -= optind;
	argv += optind;

	if (argc <= 0)
		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;
		}
	}

	if (!cmdfound)
		errx(1, "abort: command %s not found", argv[0]);
}