diff options
-rw-r--r-- | flake.nix | 140 | ||||
-rw-r--r-- | include/evanix.h | 1 | ||||
-rw-r--r-- | include/jobs.h | 3 | ||||
-rw-r--r-- | meson.build | 9 | ||||
-rw-r--r-- | meson_options.txt | 1 | ||||
-rw-r--r-- | pyproject.toml | 10 | ||||
-rw-r--r-- | python-package.nix | 41 | ||||
-rw-r--r-- | src/build.c | 19 | ||||
-rw-r--r-- | src/evanix-py.c | 14 | ||||
-rw-r--r-- | src/evanix.c | 6 | ||||
-rw-r--r-- | src/jobs.c | 48 | ||||
-rw-r--r-- | src/queue.c | 1 |
12 files changed, 226 insertions, 67 deletions
@@ -3,75 +3,99 @@ inputs.nixpkgs.url = "github:NixOs/nixpkgs/nixos-unstable"; - outputs = { self, nixpkgs }: let - lib = nixpkgs.lib; + outputs = + { self, nixpkgs }: + let + lib = nixpkgs.lib; - forSystem = f: system: f { - inherit system; - pkgs = import nixpkgs { inherit system; }; - }; + forSystem = + f: system: + f { + inherit system; + pkgs = import nixpkgs { inherit system; }; + }; - supportedSystems = lib.platforms.unix; - forAllSystems = f: lib.genAttrs supportedSystems (forSystem f); - in { - devShells = forAllSystems ({ system, pkgs }: { - default = pkgs.mkShell { - name = "dev"; + supportedSystems = lib.systems.flakeExposed; + forAllSystems = f: lib.genAttrs supportedSystems (forSystem f); + in + { + devShells = forAllSystems ( + { system, pkgs }: + { + default = pkgs.mkShell { + name = "dev"; - buildInputs = with pkgs; [ - jq - cjson - nix-eval-jobs + buildInputs = with pkgs; [ + jq + cjson + nix-eval-jobs - pkg-config - meson - ninja + pkg-config + meson + ninja - gdb - ccls - valgrind - clang-tools # clang-format - ]; + gdb + ccls + valgrind + clang-tools # clang-format + ]; - shellHook = '' - export PS1="\033[0;34m[ ]\033[0m $PS1" - ''; - }; - }); + shellHook = '' + export PS1="\033[0;34m[ ]\033[0m $PS1" + ''; + }; + } + ); - packages = forAllSystems ({ system, pkgs }: { - evanix = pkgs.stdenv.mkDerivation (finalAttrs: { - name = "evanix"; + packages = forAllSystems ( + { system, pkgs }: + { + default = self.packages.${system}.evanix; + evanix = pkgs.stdenv.mkDerivation (finalAttrs: { + name = "evanix"; - src = ./.; - nativeBuildInputs = with pkgs; [ - meson - ninja - pkg-config - makeWrapper - ]; - buildInputs = with pkgs; [ - cjson - nix-eval-jobs - ]; + src = ./.; + nativeBuildInputs = with pkgs; [ + meson + ninja + pkg-config + makeWrapper + ]; + buildInputs = with pkgs; [ + cjson + nix-eval-jobs + ]; - postInstall = '' - wrapProgram $out/bin/evanix \ - --prefix PATH : ${lib.makeBinPath [ pkgs.nix-eval-jobs ]} - ''; + postInstall = '' + wrapProgram $out/bin/evanix \ + --prefix PATH : ${lib.makeBinPath [ pkgs.nix-eval-jobs ]} + ''; - meta = { - homepage = "https://git.sinanmohd.com/evanix"; + meta = { + homepage = "https://git.sinanmohd.com/evanix"; - license = lib.licenses.gpl3; - platforms = supportedSystems; - mainProgram = "evanix"; + license = lib.licenses.gpl3; + platforms = supportedSystems; + mainProgram = "evanix"; - maintainers = with lib.maintainers; [ sinanmohd ]; - }; - }); + maintainers = with lib.maintainers; [ sinanmohd ]; + }; + }); - default = self.packages.${system}.evanix; - }); - }; + evanix-py = pkgs.python3Packages.callPackage ./python-package.nix { }; + pythonWithEvanix = + let + wrapper = pkgs.python3.withPackages (ps: [ (ps.callPackage ./python-package.nix { }) ]); + in + wrapper.overrideAttrs (oldAttrs: { + makeWrapperArgs = oldAttrs.makeWrapperArgs or [ ] ++ [ + "--prefix" + "PATH" + ":" + "${lib.makeBinPath [ pkgs.nix-eval-jobs ]}" + ]; + }); + } + ); + }; } diff --git a/include/evanix.h b/include/evanix.h index aa53b9f..c4285fc 100644 --- a/include/evanix.h +++ b/include/evanix.h @@ -7,6 +7,7 @@ struct evanix_opts_t { bool isdryrun; bool ispipelined; bool close_stderr_exec; + char *system; }; extern struct evanix_opts_t evanix_opts; diff --git a/include/jobs.h b/include/jobs.h index 11f6b01..37445c1 100644 --- a/include/jobs.h +++ b/include/jobs.h @@ -9,7 +9,7 @@ struct output { }; struct job { - char *name, *drv_path; + char *name, *drv_path, *attr; bool transitive; bool insubstituters; @@ -32,6 +32,7 @@ typedef enum { JOB_READ_EVAL_ERR = 2, JOB_READ_JSON_INVAL = 3, JOB_READ_CACHED = 4, + JOB_READ_SYS_MISMATCH = 5, } job_read_state_t; int job_read(FILE *stream, struct job **jobs); diff --git a/meson.build b/meson.build index 38f78d7..e5290f8 100644 --- a/meson.build +++ b/meson.build @@ -21,4 +21,13 @@ add_project_arguments( cjson_dep = dependency('libcjson') evanix_inc = include_directories('include') +if get_option('build-python') + py = import('python').find_installation() + py.extension_module( + 'evanix', + 'src/evanix-py.c', + install: true, + ) +endif + subdir('src') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..e8baf64 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('build-python', type: 'boolean', value: 'false') diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b5a3375 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +build-backend = 'mesonpy' +requires = [ 'meson-python' ] + +[project] +name = 'evanix' +version = '0.0.1' + +[tool.meson-python.args] +setup = [ '-Dbuild-python=true' ] diff --git a/python-package.nix b/python-package.nix new file mode 100644 index 0000000..a422052 --- /dev/null +++ b/python-package.nix @@ -0,0 +1,41 @@ +{ + lib, + buildPythonPackage, + meson-python, + ninja, + pkg-config, + makeWrapper, + cjson, +}: + +buildPythonPackage { + pname = "evanix"; + version = "0.0.1"; + pyproject = true; + + src = + let + fs = lib.fileset; + in + fs.toSource { + root = ./.; + fileset = fs.unions [ + ./src + ./include + ./meson.build + ./meson_options.txt + ./pyproject.toml + ]; + }; + + build-system = [ meson-python ]; + nativeBuildInputs = [ + ninja + pkg-config + makeWrapper + ]; + buildInputs = [ + cjson + # nix-eval-jobs + ]; +} diff --git a/src/build.c b/src/build.c index 39750b5..87238e9 100644 --- a/src/build.c +++ b/src/build.c @@ -2,6 +2,7 @@ #include <pthread.h> #include <stdbool.h> #include <stdlib.h> +#include <limits.h> #include <string.h> #include "build.h" @@ -43,16 +44,29 @@ out: static int build(struct queue *queue) { struct job *job; - char *args[3]; + char *args[5]; size_t argindex; int ret; + char out_link[NAME_MAX] = "result"; + ret = queue_pop(queue, &job, queue->htab); if (ret < 0) return ret; + if (job->attr) { + ret = snprintf(out_link, sizeof(out_link), "result-%s", job->attr); + if (ret < 0 || (size_t)ret > sizeof(out_link)) { + ret = -ENAMETOOLONG; + print_err("%s", strerror(-ret)); + goto out_free_job; + } + } + argindex = 0; args[argindex++] = "nix-build"; + args[argindex++] = "--out-link"; + args[argindex++] = out_link; args[argindex++] = job->drv_path; args[argindex++] = NULL; @@ -64,9 +78,10 @@ static int build(struct queue *queue) run("nix-build", args); } +out_free_job: job_free(job); - return 0; + return ret; } int build_thread_new(struct build_thread **build_thread, struct queue *q) diff --git a/src/evanix-py.c b/src/evanix-py.c new file mode 100644 index 0000000..c010e27 --- /dev/null +++ b/src/evanix-py.c @@ -0,0 +1,14 @@ +#include <Python.h> + +static PyMethodDef methods[] = { + {NULL, NULL, 0, NULL}, +}; + +static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, "evanix", NULL, -1, methods, +}; + +PyMODINIT_FUNC PyInit_evanix(void) +{ + return PyModule_Create(&module); +} diff --git a/src/evanix.c b/src/evanix.c index 64bd763..01279d1 100644 --- a/src/evanix.c +++ b/src/evanix.c @@ -14,6 +14,7 @@ static const char usage[] = " -f, --flake Build a flake.\n" " -d, --dry-run Show what derivations would be " "built.\n" + " -s, --system System to build for." " -p, --pipelined <bool> Use evanix build pipeline.\n" " -c, --close-stderr-exec <bool> Close stderr on exec.\n" "\n"; @@ -23,6 +24,7 @@ struct evanix_opts_t evanix_opts = { .isflake = false, .ispipelined = true, .isdryrun = false, + .system = NULL, }; static int evanix(char *expr); @@ -99,6 +101,7 @@ int main(int argc, char *argv[]) {"help", no_argument, NULL, 'h'}, {"flake", no_argument, NULL, 'f'}, {"dry-run", no_argument, NULL, 'd'}, + {"system", required_argument, NULL, 's'}, {"pipelined", required_argument, NULL, 'p'}, {"close-stderr-exec", required_argument, NULL, 'c'}, {NULL, 0, NULL, 0}, @@ -117,6 +120,9 @@ int main(int argc, char *argv[]) case 'd': evanix_opts.isdryrun = true; break; + case 's': + evanix_opts.system = optarg; + break; case 'p': ret = atob(optarg); if (ret < 0) { @@ -11,7 +11,7 @@ #include "util.h" static void output_free(struct output *output); -static int job_new(struct job **j, char *name, char *drv_path, +static int job_new(struct job **j, char *name, char *drv_path, char *attr, struct job *parent); static int job_output_insert(struct job *j, char *name, char *store_path); static int job_read_inputdrvs(struct job *job, cJSON *input_drvs); @@ -167,7 +167,7 @@ static int job_read_inputdrvs(struct job *job, cJSON *input_drvs) int ret = 0; for (cJSON *array = input_drvs; array != NULL; array = array->next) { - ret = job_new(&dep_job, NULL, array->string, job); + ret = job_new(&dep_job, NULL, array->string, NULL, job); if (ret < 0) goto out_free_dep_job; @@ -238,6 +238,7 @@ int job_read(FILE *stream, struct job **job) char *drv_path = NULL; struct job *j = NULL; cJSON *root = NULL; + char *attr = NULL; char *name = NULL; int ret = 0; @@ -253,6 +254,17 @@ int job_read(FILE *stream, struct job **job) goto out_free; } + temp = cJSON_GetObjectItemCaseSensitive(root, "system"); + if (!cJSON_IsString(temp)) { + ret = JOB_READ_JSON_INVAL; + goto out_free; + } + if (evanix_opts.system != NULL && + strcmp(evanix_opts.system, temp->valuestring)) { + ret = JOB_READ_SYS_MISMATCH; + goto out_free; + } + temp = cJSON_GetObjectItemCaseSensitive(root, "name"); if (!cJSON_IsString(temp)) { ret = JOB_READ_JSON_INVAL; @@ -260,6 +272,14 @@ int job_read(FILE *stream, struct job **job) } name = temp->valuestring; + temp = cJSON_GetObjectItemCaseSensitive(root, "attr"); + if (!cJSON_IsString(temp)) { + ret = JOB_READ_JSON_INVAL; + goto out_free; + } + if (temp->valuestring[0] != '\0') + attr = temp->valuestring; + temp = cJSON_GetObjectItemCaseSensitive(root, "drvPath"); if (!cJSON_IsString(temp)) { free(name); @@ -268,7 +288,7 @@ int job_read(FILE *stream, struct job **job) } drv_path = temp->valuestring; - ret = job_new(&j, name, drv_path, NULL); + ret = job_new(&j, name, drv_path, attr, NULL); if (ret < 0) goto out_free; @@ -332,11 +352,12 @@ void job_free(struct job *job) free(job->drv_path); free(job->name); + free(job->attr); free(job); } static int job_new(struct job **j, char *name, char *drv_path, - struct job *parent) + char *attr, struct job *parent) { struct job *job; int ret = 0; @@ -360,12 +381,23 @@ static int job_new(struct job **j, char *name, char *drv_path, job->parents_filled = 0; job->parents = NULL; + if (attr != NULL) { + job->attr = strdup(attr); + if (job->attr == NULL) { + print_err("%s", strerror(errno)); + ret = -errno; + goto out_free_job; + } + } else { + job->attr = NULL; + } + if (name != NULL) { job->name = strdup(name); if (job->name == NULL) { print_err("%s", strerror(errno)); ret = -errno; - goto out_free_job; + goto out_free_attr; } } else { job->name = NULL; @@ -390,6 +422,9 @@ out_free_drv_path: out_free_name: if (ret < 0) free(job->name); +out_free_attr: + if (ret < 0) + free(job->attr); out_free_job: if (ret < 0) free(job); @@ -402,12 +437,13 @@ out_free_job: int jobs_init(FILE **stream, char *expr) { size_t argindex; - char *args[5]; + char *args[6]; int ret; argindex = 0; args[argindex++] = "nix-eval-jobs"; args[argindex++] = "--check-cache-status"; + args[argindex++] = "--force-recurse"; if (evanix_opts.isflake) args[argindex++] = "--flake"; args[argindex++] = expr; diff --git a/src/queue.c b/src/queue.c index a5b4d6a..09eebb6 100644 --- a/src/queue.c +++ b/src/queue.c @@ -67,6 +67,7 @@ void *queue_thread_entry(void *queue_thread) break; } else if (ret == JOB_READ_EVAL_ERR || ret == JOB_READ_JSON_INVAL || + ret == JOB_READ_SYS_MISMATCH || ret == JOB_READ_CACHED) { continue; } else if (ret == JOB_READ_SUCCESS) { |