Better naming throughout to match `spec`.
parent
508d738f9b
commit
4a8f8db0a5
21
README.md
21
README.md
|
@ -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
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
ncurses
|
||||
];
|
||||
shellHook = ''
|
||||
export GEN_FLAKE_SPEC_PATH="${./specs}"
|
||||
export SPEC_ROOT_DIR="${./specs}"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
74
main.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
14
src/config.c
14
src/config.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue