Better naming throughout to match `spec`.

pull/9/head
Joshua Potter 2023-11-22 14:55:55 -07:00
parent 508d738f9b
commit 4a8f8db0a5
7 changed files with 30 additions and 108 deletions

View File

@ -2,20 +2,7 @@
CLI utility for initializing projects in reproducible ways.
## 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
## Overview
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
@ -28,9 +15,9 @@ so:
```
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:
prompted by the `spec init` curses interface. The value is used to determine
what kind of prompt `spec` provides for the given question. Possible value types
include:
* `[...]` (list)
* This indicates a select option prompt. The user chooses amongst the values

View File

@ -31,7 +31,7 @@
ncurses
];
shellHook = ''
export GEN_FLAKE_SPEC_PATH="${./specs}"
export SPEC_ROOT_DIR="${./specs}"
'';
};
}

View File

@ -1,18 +1,18 @@
#ifndef GEN_FLAKE_CONFIG_H
#define GEN_FLAKE_CONFIG_H
#ifndef _SPEC_CONFIG_H
#define _SPEC_CONFIG_H
struct Config {
// The root directory housing our specs. This string is nonempty.
const char *spec_path;
const char *root_dir;
// The name of the spec we want to load. This string is nonempty.
const char *target;
};
enum ConfigError {
// Indicates the `$GEN_FLAKE_SPEC_PATH` environment variable is not set.
ENV_SPEC_PATH_EMPTY = 1,
// Indicates the `$GEN_FLAKE_SPEC_PATH` environment variable is empty.
ENV_SPEC_PATH_MISSING,
// Indicates the `$SPEC_ROOT_DIR` environment variable is empty.
ENV_SPEC_ROOT_DIR_MISSING = 1,
// Indicates the `$SPEC_ROOT_DIR` environment variable is not set.
ENV_SPEC_ROOT_DIR_EMPTY,
// Indicates the target argument is invalid.
INVALID_TARGET,
};
@ -21,4 +21,4 @@ enum ConfigError load_config(const char *target, struct Config *config);
void free_config(struct Config *config);
#endif /* GEN_FLAKE_CONFIG_H */
#endif /* _SPEC_CONFIG_H */

View File

@ -1,5 +1,5 @@
#ifndef GEN_FLAKE_DYN_ARRAY_H
#define GEN_FLAKE_DYN_ARRAY_H
#ifndef _SPEC_DYN_ARRAY_H
#define _SPEC_DYN_ARRAY_H
#include <stdlib.h>
@ -19,4 +19,4 @@ void dyn_array_push(struct DynArray *a, void *item);
void dyn_array_free(struct DynArray *a);
#endif /* GEN_FLAKE_DYN_ARRAY_H */
#endif /* _SPEC_DYN_ARRAY_H */

74
main.c
View File

@ -1,70 +1,9 @@
#include <assert.h>
#include <glob.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "config.h"
#include "dyn_array.h"
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);
int name_length = strlen(name);
char *pattern = malloc(name_length + 3);
if (!pattern) {
goto cleanup;
}
memcpy(pattern, name, name_length);
memcpy(pattern + name_length + 1, "/*", 3);
glob_t *pglob = 0;
int retval = 0;
if ((retval = glob(pattern, GLOB_ONLYDIR | GLOB_MARK, 0, pglob))) {
goto cleanup;
}
// GLOB_ONLYDIR is just a hint. We still need to actually verify the only
// results we are reading in are directories.
// TODO:
globfree(pglob);
cleanup:
if (pattern) {
free(pattern);
}
return retval;
}
int main(int argc, char **argv) {
int num = 0;
@ -75,18 +14,17 @@ int main(int argc, char **argv) {
struct Config config;
switch (load_config(argv[1], &config)) {
case ENV_SPEC_PATH_EMPTY:
fprintf(stderr, "Must specify GEN_FLAKE_SPEC_PATH environment variable.");
case ENV_SPEC_ROOT_DIR_MISSING:
fprintf(stderr, "Must specify $SPEC_ROOT_DIR environment variable.");
exit(EXIT_FAILURE);
case ENV_SPEC_PATH_MISSING:
fprintf(stderr,
"GEN_FLAKE_SPEC_PATH environment variable should not be empty.");
case ENV_SPEC_ROOT_DIR_EMPTY:
fprintf(stderr, "$SPEC_ROOT_DIR environment variable should not be empty.");
exit(EXIT_FAILURE);
case INVALID_TARGET:
fprintf(stderr, "Spec `%s` is invalid.", argv[1]);
fprintf(stderr, "Target spec `%s` is invalid.", argv[1]);
exit(EXIT_FAILURE);
default:
// Return value of `0` indicates no issue.
// A return value of `0` indicates no issue.
break;
}

View File

@ -3,15 +3,15 @@
#include "config.h"
const char *ENV_SPEC_PATH = "GEN_FLAKE_SPEC_PATH";
const char *ENV_SPEC_ROOT_DIR = "SPEC_ROOT_DIR";
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;
const char *root_dir = getenv(ENV_SPEC_ROOT_DIR);
if (root_dir == 0) {
return ENV_SPEC_ROOT_DIR_MISSING;
}
if (spec_path[0] == 0) {
return ENV_SPEC_PATH_EMPTY;
if (root_dir[0] == 0) {
return ENV_SPEC_ROOT_DIR_EMPTY;
}
if (target == 0) {
return INVALID_TARGET;
@ -23,7 +23,7 @@ enum ConfigError load_config(const char *target, struct Config *config) {
}
config = malloc(sizeof(struct Config));
config->spec_path = spec_path;
config->root_dir = root_dir;
char *copy_target = calloc(1, target_len + 1);
strcpy(copy_target, target);

View File

@ -12,13 +12,11 @@ struct DynArray *dyn_array_new(size_t capacity) {
size_t dyn_array_size(struct DynArray *a) {
assert(a);
return a->size;
}
void dyn_array_push(struct DynArray *a, void *item) {
assert(a);
if (a->size == a->_capacity) {
// We assume reallocation will work.
a->_capacity *= 2;
@ -30,7 +28,6 @@ void dyn_array_push(struct DynArray *a, void *item) {
void dyn_array_free(struct DynArray *a) {
assert(a);
free(a->buf);
free(a);
}