Mercurial > sci
view scictl/scictl.c @ 85:cf49ab595e2e default tip @
sciworkerd: avoid spawning several tasks
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 09 Mar 2023 10:43:48 +0100 |
parents | 71cd8447e3a4 |
children |
line wrap: on
line source
/* * scictl.c -- main scictl(8) utility file * * Copyright (c) 2021-2023 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. */ #include <errno.h> #include <limits.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <utlist.h> #include "apic.h" #include "util.h" static void usage(void) { fprintf(stderr, "usage: scictl [-k key] [-u baseurl] command [args...]\n"); exit(1); } static void help(void) { fprintf(stderr, "usage: scictl job-add project tag\n"); fprintf(stderr, " scictl job-todo worker\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); } 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 = NULL; size_t nr, consolesz = 0; if (strcmp(path, "-") == 0) fp = stdin; else if (!(fp = fopen(path, "r"))) util_die("abort: %s: %s\n", path, strerror(errno)); str = util_open_memstream(&console, &consolesz); while ((nr = fread(buf, 1, sizeof (buf), fp)) > 0) fwrite(buf, 1, nr, str); if ((ferror(fp) && !feof(fp)) || (ferror(str) && !feof(str))) util_die("abort: %s\n", strerror(errno)); fclose(str); fclose(fp); return console; } static inline intmax_t get_int(json_t *obj, const char *key) { json_t *val; if ((val = json_object_get(obj, key)) && json_is_integer(val)) return json_integer_value(val); return 0; } static inline const char * get_string(json_t *obj, const char *key) { json_t *val; if ((val = json_object_get(obj, key)) && json_is_string(val)) return json_string_value(val); return ""; } static void cmd_job_add(int argc, char **argv) { struct apic req; json_t *obj; if (argc < 3) usage(); obj = json_pack("{ss ss}", "project_name", argv[1], "tag", argv[2] ); if (apic_job_add(&req, obj) < 0) util_die("abort: %s\n", req.error); json_decref(obj); } static void cmd_job_todo(int argc, char **argv) { struct apic req; json_t *array, *obj; size_t i; if (argc < 2) usage(); if ((array = apic_job_todo(&req, argv[1]))) util_die("abort: %s\n", req.error); json_array_foreach(array, i, obj) { printf("%-16s%jd\n", "id:", get_int(obj, "id")); printf("%-16s%s\n", "tag:", get_string(obj, "tag")); printf("%-16s%s\n", "project:", get_string(obj, "project_name")); if (i + 1 < json_array_size(array)) printf("\n"); } json_decref(array); } static void cmd_project_add(int argc, char **argv) { struct apic req; char *script; json_t *obj; if (argc < 5) usage(); script = readfile(argv[4]); obj = json_pack("{ss ss ss ss}", "name", argv[1], "desc", argv[2], "url", argv[3], "script", script ); if (apic_project_save(&req, obj) < 0) util_die("abort: unable to create project: %s\n", req.error); json_decref(obj); } static void cmd_project_update(int argc, char **argv) { struct apic req; json_t *obj; if (argc < 4) usage(); if (!(obj = apic_project_find(&req, argv[1]))) util_die("abort: unable to find project: %s\n", req.error); /* Those fields are treated from argument. */ if (strcmp(argv[2], "name") == 0 || strcmp(argv[2], "desc") == 0 || strcmp(argv[2], "url") == 0) json_object_set_new(obj, argv[2], json_string(argv[3])); /* The script, however, is read from the file. */ else if (strcmp(argv[2], "script") == 0) json_object_set_new(obj, "script", json_string(readfile(argv[3]))); if (apic_project_save(&req, obj) < 0) util_die("abort: unable to save project: %s\n", req.error); json_decref(obj); } static void cmd_project_info(int argc, char **argv) { struct apic req; json_t *obj; if (argc < 2) usage(); if (!(obj = apic_project_find(&req, argv[1]))) util_die("abort: unable to find project: %s\n", req.error); printf("%-16s%s\n", "name:", get_string(obj, "name")); printf("%-16s%s\n", "desc:", get_string(obj, "desc")); printf("%-16s%s\n", "url:", get_string(obj, "url")); printf("\n"); printf("%s", get_string(obj, "script")); json_decref(obj); } static void cmd_project_list(int argc, char **argv) { (void)argc; (void)argv; struct apic req; json_t *array, *obj; size_t i; if (!(array = apic_project_list(&req))) util_die("abort: unable to list projects: %s\n", req.error); json_array_foreach(array, i, obj) { printf("%-16s%s\n", "name:", get_string(obj, "name")); printf("%-16s%s\n", "desc:", get_string(obj, "desc")); printf("%-16s%s\n", "url:", get_string(obj, "url")); if (i + 1 < json_array_size(array)) printf("\n"); } json_decref(array); } static void cmd_worker_add(int argc, char **argv) { struct apic req; json_t *obj; if (argc < 3) usage(); obj = json_pack("{ss ss}", "name", argv[1], "desc", argv[2] ); if (apic_worker_save(&req, obj) < 0) util_die("abort: unable to save worker: %s\n", req.error); json_decref(obj); } static void cmd_worker_list(int argc, char **argv) { (void)argc; (void)argv; struct apic req; json_t *array, *obj; size_t i; if (!(array = apic_worker_list(&req))) util_die("abort: unable to list worker: %s\n", req.error); json_array_foreach(array, i, obj) { printf("%-16s%s\n", "name:", get_string(obj, "name")); printf("%-16s%s\n", "desc:", get_string(obj, "desc")); if (i + 1 < json_array_size(array)) printf("\n"); } json_decref(array); } static struct { const char *name; void (*exec)(int, char **); } commands[] = { { "job-add", cmd_job_add }, { "job-todo", cmd_job_todo }, { "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; const char *env; opterr = 0; setenv("POSIXLY_CORRECT", "1", 1); /* Environment first, options after. */ if ((env = getenv("SCI_API_URL"))) util_strlcpy(apiconf.baseurl, env, sizeof (apiconf.baseurl)); if ((env = getenv("SCI_API_KEY"))) util_strlcpy(apiconf.key, env, sizeof (apiconf.key)); while ((ch = util_getopt(argc, argv, "k:u:")) != -1) { switch (ch) { case 'k': util_strlcpy(apiconf.key, optarg, sizeof (apiconf.key)); break; case 'u': util_strlcpy(apiconf.baseurl, optarg, sizeof (apiconf.baseurl)); break; default: break; } } argc -= optind; argv += optind; optind = 1; if (argc < 1) usage(); if (strcmp(argv[0], "help") == 0) help(); /* At this step, every command requires an API key. */ if (strlen(apiconf.key) == 0) util_die("abort: no API key defined\n"); for (size_t i = 0; commands[i].name; ++i) { if (strcmp(commands[i].name, argv[0]) == 0) { commands[i].exec(argc, argv); return 0; } } util_die("abort: invalid command: %s\n", argv[0]); }