aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsinanmohd <sinan@sinanmohd.com>2024-06-07 22:05:55 +0530
committersinanmohd <sinan@sinanmohd.com>2024-06-09 22:43:48 +0530
commit8dfff0655a2f93cc540bbaf7b88fb820431ecd02 (patch)
treebbf2621277e920aa4bd9013b1fa9f8e1eb0b8e2c
parentf6a06d2fe7bd8519219f243536e77fcee46cb583 (diff)
src/jobs: init
implement data structures and json unmarshalling
-rw-r--r--flake.nix2
-rw-r--r--include/jobs.h22
-rw-r--r--include/util.h9
-rw-r--r--meson.build1
-rw-r--r--src/jobs.c178
-rw-r--r--src/meson.build6
-rw-r--r--src/util.c77
7 files changed, 294 insertions, 1 deletions
diff --git a/flake.nix b/flake.nix
index 7d5416c..33f3798 100644
--- a/flake.nix
+++ b/flake.nix
@@ -19,6 +19,7 @@
name = "dev";
buildInputs = with pkgs; [
+ jq
cjson
nix-eval-jobs
@@ -51,6 +52,7 @@
];
buildInputs = with pkgs; [
cjson
+ nix-eval-jobs
];
postInstall = ''
diff --git a/include/jobs.h b/include/jobs.h
new file mode 100644
index 0000000..571be0d
--- /dev/null
+++ b/include/jobs.h
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <sys/queue.h>
+
+LIST_HEAD(output_dlist, output);
+struct output {
+ char *name, *store_path;
+ LIST_ENTRY(output) dlist;
+};
+
+LIST_HEAD(job_dlist, job);
+struct job {
+ char *drv_path, *name;
+ struct output_dlist outputs;
+ struct job_dlist deps;
+
+ LIST_ENTRY(job) dlist;
+};
+
+int jobs_init(FILE **stream);
+int job_new(struct job **j, char *name, char *drv_path);
+void job_free(struct job *j);
+int jobs_read(FILE *stream, struct job *jobs);
diff --git a/include/util.h b/include/util.h
index e69de29..c5aa0ab 100644
--- a/include/util.h
+++ b/include/util.h
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#include <cjson/cJSON.h>
+
+#define print_err(fmt, ...) \
+ fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+
+int json_streaming_read(FILE *stream, cJSON **json);
+int vpopen(FILE **stream, const char *file, char *const argv[]);
diff --git a/meson.build b/meson.build
index d5f4f82..cac287a 100644
--- a/meson.build
+++ b/meson.build
@@ -11,6 +11,7 @@ project(
add_project_arguments(
[
+ '-D_POSIX_C_SOURCE=200809L',
'-Wvla',
],
language: 'c',
diff --git a/src/jobs.c b/src/jobs.c
new file mode 100644
index 0000000..7893632
--- /dev/null
+++ b/src/jobs.c
@@ -0,0 +1,178 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cjson/cJSON.h>
+
+#include "jobs.h"
+#include "util.h"
+
+static int job_output_insert(struct job *j, char *name, char *store_path);
+
+int job_read(FILE *stream, struct job **job)
+{
+ int ret;
+ cJSON *root, *temp, *input_drvs, *array;
+ struct job *dep_job;
+ char *name = NULL;
+ char *out_name = NULL;
+ char *drv_path = NULL;
+
+ ret = json_streaming_read(stream, &root);
+ if (ret < 0)
+ return ret;
+
+ temp = cJSON_GetObjectItemCaseSensitive(root, "name");
+ if (!cJSON_IsString(temp)) {
+ ret = -EPERM;
+ goto out_free;
+ }
+ name = strdup(temp->valuestring);
+ if (name == NULL) {
+ ret = -EPERM;
+ goto out_free;
+ }
+
+ temp = cJSON_GetObjectItemCaseSensitive(root, "drvPath");
+ if (!cJSON_IsString(temp)) {
+ ret = -EPERM;
+ goto out_free;
+ }
+ drv_path = strdup(temp->valuestring);
+ if (drv_path == NULL) {
+ ret = -EPERM;
+ goto out_free;
+ }
+
+ ret = job_new(job, name, drv_path);
+ if (ret < 0)
+ goto out_free;
+
+ input_drvs = cJSON_GetObjectItemCaseSensitive(root, "inputDrvs");
+ for (temp = input_drvs; temp != NULL; temp = temp->next) {
+ array = cJSON_GetObjectItemCaseSensitive(temp, temp->string);
+ if (!cJSON_IsArray(array)) {
+ ret = -EPERM;
+ job_free(*job);
+ goto out_free;
+ }
+
+ drv_path = strdup(temp->string);
+ if (drv_path == NULL) {
+ ret = -EPERM;
+ job_free(*job);
+ goto out_free;
+ }
+
+ ret = job_new(&dep_job, NULL, drv_path);
+ if (ret < 0) {
+ ret = -EPERM;
+ job_free(*job);
+ goto out_free;
+ }
+
+ for (; array != NULL; array = array->next) {
+ out_name = strdup(array->string);
+ ret = job_output_insert(dep_job, out_name, NULL);
+ if (ret < 0) {
+ job_free(*job);
+ job_free(dep_job);
+ goto out_free;
+ }
+ }
+
+ LIST_INSERT_HEAD(&(*job)->deps, dep_job, dlist);
+ drv_path = NULL;
+ }
+
+out_free:
+ cJSON_Delete(root);
+
+ if (ret < 0) {
+ print_err("%s", "Invalid JSON");
+ free(name);
+ free(drv_path);
+ }
+ return ret;
+}
+
+void output_free(struct output *output)
+{
+ if (output == NULL)
+ return;
+
+ free(output->name);
+ free(output->store_path);
+
+ free(output);
+}
+
+void job_free(struct job *job)
+{
+ struct job *j;
+ struct output *o;
+
+ if (job == NULL)
+ return;
+
+ free(job->name);
+ free(job->drv_path);
+ free(job);
+ LIST_FOREACH (o, &job->outputs, dlist)
+ output_free(o);
+
+ LIST_FOREACH (j, &job->deps, dlist)
+ job_free(j);
+}
+
+static int job_output_insert(struct job *j, char *name, char *store_path)
+{
+ struct output *o;
+
+ o = malloc(sizeof(*o));
+ if (o == NULL) {
+ print_err("%s", strerror(errno));
+ return -errno;
+ }
+
+ o->name = name;
+ o->store_path = store_path;
+ LIST_INSERT_HEAD(&j->outputs, o, dlist);
+
+ return 0;
+}
+
+int job_new(struct job **j, char *name, char *drv_path)
+{
+ struct job *job;
+
+ job = malloc(sizeof(*job));
+ if (*j == NULL) {
+ print_err("%s", strerror(errno));
+ return -errno;
+ }
+
+ job->name = name;
+ job->drv_path = drv_path;
+ LIST_INIT(&job->deps);
+ LIST_INIT(&job->outputs);
+
+ *j = job;
+ return 0;
+}
+
+int jobs_init(FILE **stream)
+{
+ int ret;
+
+ /* TODO: proproperly handle args */
+ char *const args[] = {
+ "--flake",
+ "github:sinanmohd/evanix#packages.x86_64-linux.evanix",
+ };
+
+ /* the package is wrapProgram-ed with nix-eval-jobs */
+ ret = vpopen(stream, "nix-eval-jobs", args);
+ return ret;
+}
diff --git a/src/meson.build b/src/meson.build
index d34718a..5fe292f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,6 +1,10 @@
e = executable(
'evanix',
- 'evanix.c',
+ [
+ 'evanix.c',
+ 'jobs.c',
+ 'util.c',
+ ],
include_directories: evanix_inc,
dependencies: cjson_dep,
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..001180e
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,77 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cjson/cJSON.h>
+
+#include "util.h"
+
+int json_streaming_read(FILE *stream, cJSON **json)
+{
+ int ret;
+ size_t n;
+ char *line = NULL;
+
+ ret = getline(&line, &n, stream);
+ if (ret < 0) {
+ if (errno != 0) {
+ print_err("%s", strerror(errno));
+ return -errno;
+ }
+
+ return -EOF;
+ }
+
+ *json = cJSON_Parse(line);
+ free(line);
+ if (cJSON_IsInvalid(*json)) {
+ print_err("%s", "Invalid JSON");
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+int vpopen(FILE **stream, const char *file, char *const argv[])
+{
+ int fd[2];
+ int ret;
+
+ ret = pipe(fd);
+ if (ret < 0) {
+ print_err("%s", strerror(errno));
+ return -errno;
+ }
+
+ ret = fork();
+ if (ret < 0) {
+ print_err("%s", strerror(errno));
+
+ close(fd[0]);
+ close(fd[1]);
+ return -errno;
+ } else if (ret > 0) {
+ close(fd[1]);
+ *stream = fdopen(fd[0], "r");
+ if (*stream == NULL) {
+ print_err("%s", strerror(errno));
+ return -errno;
+ }
+
+ return 0;
+ }
+
+ close(fd[0]);
+ ret = dup2(fd[1], STDOUT_FILENO);
+ if (ret < 0)
+ goto out_err;
+
+ execvp(file, argv);
+
+out_err:
+ close(fd[1]);
+ print_err("%s", strerror(errno));
+ exit(EXIT_FAILURE);
+}