fix: better way to validate the config, add options to git clone

This commit is contained in:
ngn
2024-05-01 23:07:02 +03:00
parent 5691727d64
commit bdd1ee23d8
7 changed files with 230 additions and 83 deletions

View File

@ -15,18 +15,44 @@ bool target_is_valid(target_t *target) {
}
if (NULL == target->dst) {
error_set(_("Configuration target %s does not have \"dst\" field"), target->name);
error_set(_("Configuration target \"%s\" does not have \"dst\" field"), target->name);
return false;
}
if (NULL == target->src) {
error_set(_("Configuration target %s does not have \"src\" field"), target->name);
error_set(_("Configuration target \"%s\" does not have \"src\" field"), target->name);
return false;
}
return true;
}
bool config_is_valid(config_t *config) {
if (NULL == config->name) {
error_set(_("Configuration does not have a name field"));
return false;
}
if (NULL == config->author) {
error_set(_("Configuration does not have an author field"));
return false;
}
if (NULL == config->t_last) {
error_set(_("Configuration does not have any targets"));
return false;
}
target_t *cur = config->t_first;
while(cur){
if(!target_is_valid(cur))
return false;
cur = cur->next;
}
return true;
}
bool config_add_target(config_t *config, char *name) {
target_t *new = malloc(sizeof(target_t));
clist_init(&new->requires);
@ -48,25 +74,6 @@ bool config_add_target(config_t *config, char *name) {
return true;
}
bool config_is_valid(config_t *config) {
if (NULL == config->name) {
error_set(_("Configuration does not have a name field"));
return false;
}
if (NULL == config->author) {
error_set(_("Configuration does not have an author field"));
return false;
}
if (NULL == config->t_last) {
error_set(_("Configuration does not have any targets"));
return false;
}
return true;
}
int config_handler(void *data, const char *section, const char *key, const char *value) {
#define MATCH(s, k) eq((char *)section, s) && eq((char *)key, k)
#define MATCHKEY(k) eq((char *)key, k)
@ -85,17 +92,12 @@ int config_handler(void *data, const char *section, const char *key, const char
} else if (MATCH("details", "keywords")) {
clist_from_str(&config->keywords, (char *)value);
return 1;
}else if(eq((char*)section, "details")) {
goto UNKNOWN;
return 1;
}
if (NULL == config->t_last || (NULL != config->t_last->name && !eq(config->t_last->name, (char *)section))) {
if (NULL != config->t_last) {
if (!target_is_valid(config->t_last)) {
errno = ConfigInvalid;
debug("invalid %s %s", config->t_last->name, section);
return 0;
}
}
if(NULL == config->t_last || (NULL != config->t_last->name && !eq(config->t_last->name, (char*)section))){
debug("adding new target => %s", section);
config_add_target(config, strdup(section));
}
@ -107,13 +109,14 @@ int config_handler(void *data, const char *section, const char *key, const char
config->t_last->dst = strdup(value);
return 1;
} else if (MATCHKEY("src")) {
config->t_last->dst = strdup(value);
config->t_last->src = strdup(value);
return 1;
} else if (MATCHKEY("requires")) {
clist_from_str(&config->t_last->requires, strdup(value));
return 1;
}
UNKNOWN:
error_set(_("Key %s is unknown"), key);
errno = ConfigUnknown;
return 0;
@ -140,10 +143,17 @@ void config_free(config_t *config) {
}
clist_free(&config->keywords);
config->name = NULL;
config->author = NULL;
config->t_first = NULL;
config->t_last = NULL;
clist_init(&config->keywords);
}
bool config_load(config_t *config, char *path) {
if (!exists(path) || is_dir(path)) {
error_set(_("Configuration file not found"));
errno = ConfigNotFound;
return false;
}
@ -156,7 +166,7 @@ bool config_load(config_t *config, char *path) {
if (ini_parse(path, config_handler, config) < 0) {
config_free(config);
if (errno != ConfigUnknown && errno != ConfigInvalid) {
if (errno != ConfigUnknown) {
error_set(_("Failed to parse configuration file"));
errno = ConfigParseFail;
}

View File

@ -23,3 +23,4 @@ typedef struct config {
} config_t;
bool config_load(config_t *, char *);
void config_free(config_t *);

View File

@ -1,5 +1,8 @@
#include "log.h"
#include "env.h"
#include "intl.h"
#include "util.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
@ -88,6 +91,17 @@ void error(const char *msg, ...) {
va_end(args);
}
void details(const char *msg, ...) {
va_list args;
va_start(args, msg);
printf(" "COLOR_RESET);
vprintf(msg, args);
printf(COLOR_RESET "\n");
va_end(args);
}
void success(const char *msg, ...) {
va_list args;
va_start(args, msg);
@ -112,3 +126,32 @@ void debug(const char *msg, ...) {
va_end(args);
}
void input(const char *msg, ...) {
va_list args;
va_start(args, msg);
printf(COLOR_BOLD COLOR_CYAN ">>> " COLOR_RESET COLOR_BOLD);
vprintf(msg, args);
printf(COLOR_RESET);
va_end(args);
}
bool yesno(const char *msg){
char question[strlen(msg)+12], inp[2] = {'n','\0'}, c;
sprintf(question, "%s [y/n]? ", msg);
while(true){
input(question);
scanf("%c", &c);
inp[0] = c;
if(eq(inp, _("y")) || eq(inp, _("Y")))
return true;
else if(eq(inp, _("n")) || eq(inp, _("N")))
return false;
error(_("Please answer with y/n"));
}
}

View File

@ -4,15 +4,20 @@
#define COLOR_RED "\x1b[31m"
#define COLOR_BOLD "\x1b[1m"
#define COLOR_BLUE "\x1b[34m"
#define COLOR_CYAN "\x1b[36m"
#define COLOR_GREEN "\x1b[32m"
#define COLOR_MAGENTA "\x1b[35m"
#define COLOR_RESET "\x1b[0m"
#define COLOR_MAGENTA "\x1b[35m"
#define COLOR_UNDERLINE "\x1b[4m"
#define COLOR_RESET "\x1b[0m"
void bar_init();
bool bar(float, float);
void bar_free();
void info(const char *msg, ...);
void error(const char *msg, ...);
void success(const char *msg, ...);
void info(const char *, ...);
void error(const char *, ...);
void details(const char *, ...);
void success(const char *, ...);
void debug(const char *, ...);
void input(const char *, ...);
bool yesno(const char *);

View File

@ -24,6 +24,7 @@
#include <libintl.h>
#include <locale.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -51,7 +52,14 @@ struct CmdMap cmdmap[] = {
{.name = "mc-gen", .lock = false, .func = gen_cmd },
};
void handler(int sig){
unlock();
printf("\e[?25h");
exit(1);
}
int main(int argc, char *argv[]) {
signal(SIGINT, handler);
setbuf(stdout, NULL);
setlocale(LC_ALL, "");
textdomain("mc");

View File

@ -17,7 +17,7 @@
#define _(x) gettext(x)
int fetch_progress(const git_indexer_progress *stats, void *data) {
int pull_progress(const git_indexer_progress *stats, void *data){
bar(stats->indexed_objects, stats->total_objects);
return 0;
}
@ -29,6 +29,7 @@ bool pull_cmd() {
}
char *repo_url = NULL, *repo_root = NULL;
config_t repo_cfg = {.name = NULL};
bool ret = false;
if (url_is_local(args.list[1])) {
@ -49,15 +50,16 @@ bool pull_cmd() {
git_repository *repo = NULL;
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
opts.fetch_opts.callbacks.transfer_progress = fetch_progress;
opts.fetch_opts.callbacks.payload = NULL;
opts.fetch_opts.callbacks.transfer_progress = pull_progress;
opts.fetch_opts.callbacks.payload = NULL;
info(_("Cloning %s"), repo_url);
bar_init();
if (git_clone(&repo, repo_url, repo_root, NULL) < 0) {
if (git_clone(&repo, repo_url, repo_root, &opts) < 0) {
const git_error *e = git_error_last();
error(_("Failed to clone the %s: %s"), repo_url, e->message);
error(_("Failed to clone the %s:"), repo_url);
details(e->message);
bar_free();
goto END;
}
@ -71,23 +73,40 @@ COPY:
goto END;
}
config_t repo_cfg;
if (!config_load(&repo_cfg, "mc.cfg")) {
error(_("Failed to load the configuration file (mc.cfg):"));
printf(" %s\n", errch);
details(errch);
goto END;
}
info("Configuration details:");
printf(COLOR_BOLD " Name" COLOR_RESET ": %s\n", repo_cfg.name);
printf(COLOR_BOLD " Author" COLOR_RESET ": %s\n", repo_cfg.author);
success(_("Loaded repository configuration"));
info(_("Configuration details:\n"));
printf(COLOR_BOLD " %s " COLOR_RESET "=> %s\n", _("Name"), repo_cfg.name);
printf(COLOR_BOLD " %s " COLOR_RESET "=> %s\n", _("Author"), repo_cfg.author);
printf(COLOR_BOLD " Keywords" COLOR_RESET ":");
printf(COLOR_BOLD " %s " COLOR_RESET "=> ", _("Keywords"));
for (int i = 0; i < repo_cfg.keywords.s; i++)
printf("%s ", repo_cfg.keywords.c[i]);
printf("\n");
printf("\n\n");
if(!yesno(_("Do you want to continue?")))
goto END;
info(_("Checking all the targets"));
target_t *cur = repo_cfg.t_first;
while(NULL != cur){
if(!exists(cur->src)){
error(_("Failed to access the source for the target \"%s\""), cur->name);
goto END;
}
cur = cur->next;
}
success(_("All the targets are OK"));
END:
if(repo_cfg.name != NULL)
config_free(&repo_cfg);
free(repo_url);
return ret;
}