2023-11-22 20:43:34 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <glob.h>
|
|
|
|
#include <signal.h>
|
2023-11-22 21:39:27 +00:00
|
|
|
#include <stdio.h>
|
2023-11-22 20:43:34 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2023-11-22 21:39:27 +00:00
|
|
|
#include "config.h"
|
2023-11-22 20:43:34 +00:00
|
|
|
#include "dyn_array.h"
|
|
|
|
|
2023-11-22 21:39:27 +00:00
|
|
|
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) {
|
2023-11-22 20:43:34 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-11-22 18:15:12 +00:00
|
|
|
int main(int argc, char **argv) {
|
2023-11-22 20:43:34 +00:00
|
|
|
int num = 0;
|
|
|
|
|
|
|
|
if (argc != 2) {
|
|
|
|
fprintf(stderr, "Usage: gen-flake <spec>\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2023-11-22 21:39:27 +00:00
|
|
|
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;
|
|
|
|
}
|
2023-11-22 18:15:12 +00:00
|
|
|
|
2023-11-22 21:39:27 +00:00
|
|
|
free_config(&config);
|
|
|
|
return EXIT_SUCCESS;
|
2023-11-22 18:15:12 +00:00
|
|
|
}
|