From f949647e1b33a52aeedef33bb9adce9d0556fdbf Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Wed, 22 Nov 2023 14:39:27 -0700 Subject: [PATCH] Add example of spec and explanation on how it works. --- .gitignore | 2 +- Makefile | 6 +++-- README.md | 41 +++++++++++++++++++++++++++++ gen-flake | Bin 20880 -> 24992 bytes include/config.h | 24 +++++++++++++++++ include/dyn_array.h | 8 +++++- main.c | 60 +++++++++++++++++++++++++++++++----------- specs/clang/spec.json | 5 ++++ src/config.c | 41 +++++++++++++++++++++++++++++ src/dyn_array.c | 8 ------ 10 files changed, 167 insertions(+), 28 deletions(-) create mode 100644 README.md create mode 100644 include/config.h create mode 100644 specs/clang/spec.json create mode 100644 src/config.c diff --git a/.gitignore b/.gitignore index c83ed64..b50d6c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .cache/ .direnv/ -a.out +gen-flake compile_commands.json diff --git a/Makefile b/Makefile index 85ac7e7..b980bd7 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ +COMMAND=clang -g -I include src/*.c main.c -o gen-flake + all: - @clang -g -lncurses -I include src/*.c main.c -o gen-flake + @${COMMAND} bear: - @bear -- clang -g -lncurses -I include src/*.c main.c -o gen-flake + @bear -- ${COMMAND} diff --git a/README.md b/README.md new file mode 100644 index 0000000..67e30e8 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# gen-flake + +CLI utility for initializing projects deterministically using flakes. + +## Problem + +Nix supports the concept of [templates](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake-init) +out of the box, but the usefulness of the implementation is dubious. In +particular, +```bash +> nix flake init +``` +simply copies the files specified in the template directory to the current +local directory, with no means of configuring the copied files. This is +especially useless when working with projects that typically generate files +on initialization (i.e. most projects). + +## How This Works + +Within the `specs` directory exists so-called *specs*. A spec is a directory +containing a `spec.json` file and a `run.sh` file. The former is configured like +so: + +```spec.json +{ + versions: [...], +} +``` + +The keys of this top-level JSON object correspond to the parameters that are +prompted by the `gen-flake` curses interface. The value is used to determine +what kind of prompt `gen-flake` provides for the given question. Possible value +types are: + +* `[...]` (list) + * This indicates a select option prompt. The user chooses amongst the values + specified in the JSON list. + +Once all prompts are evaluated, the keys of the object are converted into +uppercase environment variables and passed to the `run.sh` file relative to the +current directory. diff --git a/gen-flake b/gen-flake index 11e4692a1e295dc13b9b2e3ef148420fb0a7f63c..878528c06e5d6159aac7c3d1436dfff98887a86d 100755 GIT binary patch literal 24992 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 delta 5510 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 V4eVV^F -struct DynArray; +struct DynArray { + void **buf; + // The size of @buf excluding `NUL`. + size_t size; + // The allocated size of @buf including `NUL`. + size_t _capacity; +}; struct DynArray *dyn_array_new(size_t capacity); diff --git a/main.c b/main.c index 697e4e0..d82e9aa 100644 --- a/main.c +++ b/main.c @@ -1,15 +1,39 @@ #include -#include #include #include +#include #include #include #include #include +#include "config.h" #include "dyn_array.h" -static int glob_specs(char *name, struct DynArray *entries) { +static const char *glob_spec_pattern(const struct Config *const config) { + assert(config); + + int spec_path_length = strlen(config->spec_path); + int target_length = strlen(config->target); + // Support paths that have trailing forward slashes. + int sep_length = 0; + if (config->spec_path[spec_path_length - 1] == '/') { + sep_length = 1; + } + + char *pattern = calloc(1, spec_path_length + sep_length + target_length + 1); + memcpy(pattern, config->spec_path, spec_path_length); + if (sep_length) { + memcpy(pattern + spec_path_length, "/", sep_length); + } + memcpy(pattern + spec_path_length + sep_length, config->target, + target_length); + + return pattern; +} + +static int glob_specs(char *name, const char *spec_path, + struct DynArray *entries) { assert(name); assert(entries); @@ -41,12 +65,6 @@ cleanup: return retval; } -static void cleanup(int sig) { - endwin(); - - exit(EXIT_SUCCESS); -} - int main(int argc, char **argv) { int num = 0; @@ -55,13 +73,23 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } - // Allow interrupting the program cleanly. - // TODO: How does this cleanup spec correctly? - signal(SIGINT, cleanup); + struct Config config; + switch (load_config(argv[1], &config)) { + case ENV_SPEC_PATH_EMPTY: + fprintf(stderr, "Must specify GEN_FLAKE_SPEC_PATH environment variable."); + exit(EXIT_FAILURE); + case ENV_SPEC_PATH_MISSING: + fprintf(stderr, + "GEN_FLAKE_SPEC_PATH environment variable should not be empty."); + exit(EXIT_FAILURE); + case INVALID_TARGET: + fprintf(stderr, "Spec `%s` is invalid.", argv[1]); + exit(EXIT_FAILURE); + default: + // Return value of `0` indicates no issue. + break; + } - initscr(); - keypad(stdscr, TRUE); // Enable keyboard mapping. - nonl(); // Disables NL to CR/NL conversion on output. - - cleanup(0); + free_config(&config); + return EXIT_SUCCESS; } diff --git a/specs/clang/spec.json b/specs/clang/spec.json new file mode 100644 index 0000000..61b562d --- /dev/null +++ b/specs/clang/spec.json @@ -0,0 +1,5 @@ +{ + "versions": [ + "default" + ] +} diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..ed9a82a --- /dev/null +++ b/src/config.c @@ -0,0 +1,41 @@ +#include +#include + +#include "config.h" + +const char *ENV_SPEC_PATH = "GEN_FLAKE_SPEC_PATH"; + +enum ConfigError load_config(const char *target, struct Config *config) { + const char *spec_path = getenv(ENV_SPEC_PATH); + if (spec_path == 0) { + return ENV_SPEC_PATH_MISSING; + } + if (spec_path[0] == 0) { + return ENV_SPEC_PATH_EMPTY; + } + if (target == 0) { + return INVALID_TARGET; + } + + size_t target_len = strlen(target); + if (target_len == 0) { + return INVALID_TARGET; + } + + config = malloc(sizeof(struct Config)); + config->spec_path = spec_path; + + char *copy_target = calloc(1, target_len + 1); + strcpy(copy_target, target); + config->target=copy_target; + + return 0; +} + +void free_config(struct Config *config) { + if (!config) { + return; + } + free((void *)config->target); + free(config); +} diff --git a/src/dyn_array.c b/src/dyn_array.c index 38593ea..4866627 100644 --- a/src/dyn_array.c +++ b/src/dyn_array.c @@ -2,14 +2,6 @@ #include "dyn_array.h" -struct DynArray { - void **buf; - // The size of @buf excluding `NUL`. - size_t size; - // The allocated size of @buf including `NUL`. - size_t _capacity; -}; - struct DynArray *dyn_array_new(size_t capacity) { struct DynArray *a = malloc(sizeof(struct DynArray)); a->buf = calloc(capacity, sizeof(void *));