Allow reading in STRING prompts.
parent
537226c651
commit
16e971af0b
|
@ -1,9 +1,7 @@
|
|||
# bootstrap
|
||||
|
||||
TODO:
|
||||
- [ ] Make free-ing data consistent with null pointers.
|
||||
- [ ] Add documentation throughout (ownership, docstrings, etc.).
|
||||
- [ ] Organize variables in each function to the top?
|
||||
|
||||
CLI utility for initializing projects in reproducible ways.
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
int evaluate_run_sh(
|
||||
const struct Config *const config,
|
||||
const struct DynArray *const prompts,
|
||||
const struct DynArray *const fields,
|
||||
struct Error **error
|
||||
);
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@ enum FieldType {
|
|||
|
||||
struct Field {
|
||||
enum FieldType type;
|
||||
// OWNERSHIP: Does not take ownership.
|
||||
const char *key;
|
||||
// OWNERSHIP: Does not take ownership.
|
||||
const char *prompt;
|
||||
};
|
||||
|
||||
|
|
8
main.c
8
main.c
|
@ -46,14 +46,10 @@ static int run(const char *root_dir, const char *target) {
|
|||
}
|
||||
|
||||
cleanup_prompts:
|
||||
if (prompts) {
|
||||
dyn_array_free(prompts);
|
||||
}
|
||||
dyn_array_free(prompts);
|
||||
|
||||
cleanup_parsed:
|
||||
if (parsed) {
|
||||
cJSON_Delete(parsed);
|
||||
}
|
||||
cJSON_Delete(parsed);
|
||||
|
||||
cleanup_config:
|
||||
config_free(config);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"display": {
|
||||
"type": "STRING",
|
||||
"prompt": "This is a prompt"
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@ struct Error *config_load(
|
|||
const char *target,
|
||||
struct Config **config
|
||||
) {
|
||||
assert(target);
|
||||
|
||||
if (cwd == 0) {
|
||||
return ERROR_NEW(ERROR_CONFIG_ENV_CWD_INVALID, "Could not retrieve $CWD.");
|
||||
}
|
||||
|
@ -22,11 +24,9 @@ struct Error *config_load(
|
|||
ERROR_CONFIG_ENV_ROOT_DIR_INVALID, "No specified root directory."
|
||||
);
|
||||
}
|
||||
assert(target);
|
||||
|
||||
// Check if the specified directory exists.
|
||||
const char *segments[] = {root_dir, target};
|
||||
char *filepath =
|
||||
const char *filepath =
|
||||
join_path_segments(sizeof(segments) / sizeof(char *), segments);
|
||||
|
||||
struct stat sb;
|
||||
|
@ -58,7 +58,7 @@ struct Error *config_load(
|
|||
(*config)->target = target;
|
||||
|
||||
cleanup:
|
||||
free(filepath);
|
||||
free((void *)filepath);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
#include "evaluator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "path.h"
|
||||
#include "string_buf.h"
|
||||
#include "validator.h"
|
||||
|
||||
static struct Error *find_run_sh(const struct Config *const config) {
|
||||
assert(config);
|
||||
|
||||
struct stat sb;
|
||||
const char *segments[] = {config->root_dir, config->target, "run.sh"};
|
||||
char *filepath =
|
||||
|
@ -35,9 +41,41 @@ static struct Error *find_run_sh(const struct Config *const config) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *prompt_field(struct Field *field) {
|
||||
assert(field);
|
||||
|
||||
switch (field->type) {
|
||||
case FT_STRING:
|
||||
printf("%s> ", field->prompt);
|
||||
char *input = calloc(1, 256);
|
||||
if (fgets(input, 256, stdin)) {
|
||||
size_t len = strlen(input);
|
||||
if (len > 0 && input[len - 1] == '\n') {
|
||||
input[len - 1] = '\0';
|
||||
}
|
||||
return input;
|
||||
} else {
|
||||
free(input);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void push_env(
|
||||
struct StringBuf *env, const char *key, const char *value
|
||||
) {
|
||||
assert(env);
|
||||
for (const char *c = key; *c; ++c) {
|
||||
string_buf_cappend(env, toupper(*c));
|
||||
}
|
||||
string_buf_sappend(env, "='");
|
||||
string_buf_sappend(env, value);
|
||||
string_buf_sappend(env, "' ");
|
||||
}
|
||||
|
||||
int evaluate_run_sh(
|
||||
const struct Config *const config,
|
||||
const struct DynArray *const prompts,
|
||||
const struct DynArray *const fields,
|
||||
struct Error **error
|
||||
) {
|
||||
*error = find_run_sh(config);
|
||||
|
@ -45,15 +83,28 @@ int evaluate_run_sh(
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (prompts) {
|
||||
for (int i = 0; i < prompts->size; ++i) {
|
||||
struct StringBuf *env_buf = string_buf_new(512);
|
||||
push_env(env_buf, "OUT", config->cwd);
|
||||
|
||||
if (fields) {
|
||||
for (int i = 0; i < fields->size; ++i) {
|
||||
struct Field *field = fields->buf[i];
|
||||
const char *response = prompt_field(field);
|
||||
if (!response) {
|
||||
*error = ERROR_NEW(
|
||||
ERROR_EVALUATOR_RESPONSE_INVALID, "Could not read in response."
|
||||
);
|
||||
string_buf_free(env_buf);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
push_env(env_buf, field->key, response);
|
||||
}
|
||||
// TODO: Display prompts and collect answers.
|
||||
}
|
||||
|
||||
const char *segments[] = {config->root_dir, config->target, "run.sh"};
|
||||
char *filepath =
|
||||
const char *filepath =
|
||||
join_path_segments(sizeof(segments) / sizeof(char *), segments);
|
||||
const char *env = string_buf_convert(env_buf);
|
||||
|
||||
struct StringBuf *command_buf = string_buf_new(1024);
|
||||
string_buf_sappend(command_buf, "cd ");
|
||||
|
@ -61,13 +112,12 @@ int evaluate_run_sh(
|
|||
string_buf_cappend(command_buf, '/');
|
||||
string_buf_sappend(command_buf, config->target);
|
||||
string_buf_sappend(command_buf, " && ");
|
||||
string_buf_sappend(command_buf, "OUT=");
|
||||
string_buf_sappend(command_buf, config->cwd);
|
||||
string_buf_cappend(command_buf, ' ');
|
||||
string_buf_sappend(command_buf, env);
|
||||
string_buf_sappend(command_buf, filepath);
|
||||
const char *command = string_buf_convert(command_buf);
|
||||
|
||||
free(filepath);
|
||||
free((void *)env);
|
||||
free((void *)filepath);
|
||||
|
||||
int exit_code = system(command);
|
||||
free((void *)command);
|
||||
|
|
|
@ -15,7 +15,6 @@ struct StringBuf *string_buf_new(size_t capacity) {
|
|||
|
||||
size_t string_buf_size(struct StringBuf *sb) {
|
||||
assert(sb);
|
||||
|
||||
return sb->size;
|
||||
}
|
||||
|
||||
|
@ -55,15 +54,15 @@ void string_buf_sappend(struct StringBuf *sb, const char s[static 1]) {
|
|||
|
||||
const char *string_buf_convert(struct StringBuf *sb) {
|
||||
assert(sb);
|
||||
|
||||
const char *buf = sb->buf;
|
||||
free(sb);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void string_buf_free(struct StringBuf *sb) {
|
||||
assert(sb);
|
||||
|
||||
if (!sb) {
|
||||
return;
|
||||
}
|
||||
free((void *)sb->buf);
|
||||
free(sb);
|
||||
sb = 0;
|
||||
|
|
|
@ -14,6 +14,7 @@ static struct Error *read_field(const cJSON *const field, struct Field **out) {
|
|||
|
||||
struct Error *error = 0;
|
||||
*out = malloc(sizeof(struct Field));
|
||||
(*out)->key = field->string;
|
||||
|
||||
const cJSON *type = cJSON_GetObjectItemCaseSensitive(field, "type");
|
||||
if (!cJSON_IsString(type)) {
|
||||
|
@ -94,9 +95,7 @@ struct Error *validate_spec_json(
|
|||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (*fields) {
|
||||
dyn_array_free(*fields);
|
||||
*fields = 0;
|
||||
}
|
||||
dyn_array_free(*fields);
|
||||
*fields = 0;
|
||||
return error;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue