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

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-05-01 20:59+0300\n" "POT-Creation-Date: 2024-05-01 23:04+0300\n"
"PO-Revision-Date: 2024-05-01 13:34+0300\n" "PO-Revision-Date: 2024-05-01 13:34+0300\n"
"Last-Translator: <ngn@ngn.tf>\n" "Last-Translator: <ngn@ngn.tf>\n"
"Language-Team: Turkish <gnome-turk@gnome.org>\n" "Language-Team: Turkish <gnome-turk@gnome.org>\n"
@ -23,76 +23,100 @@ msgstr ""
#: src/config.c:18 #: src/config.c:18
#, c-format #, c-format
msgid "Configuration target %s does not have \"dst\" field" msgid "Configuration target \"%s\" does not have \"dst\" field"
msgstr "" msgstr ""
#: src/config.c:23 #: src/config.c:23
#, c-format #, c-format
msgid "Configuration target %s does not have \"src\" field" msgid "Configuration target \"%s\" does not have \"src\" field"
msgstr "" msgstr ""
#: src/config.c:53 #: src/config.c:32
msgid "Configuration does not have a name field" msgid "Configuration does not have a name field"
msgstr "" msgstr ""
#: src/config.c:58 #: src/config.c:37
msgid "Configuration does not have an author field" msgid "Configuration does not have an author field"
msgstr "" msgstr ""
#: src/config.c:63 #: src/config.c:42
msgid "Configuration does not have any targets" msgid "Configuration does not have any targets"
msgstr "" msgstr ""
#: src/config.c:117 #: src/config.c:120
#, c-format #, c-format
msgid "Key %s is unknown" msgid "Key %s is unknown"
msgstr "" msgstr ""
#: src/config.c:160 #: src/config.c:156
msgid "Configuration file not found"
msgstr ""
#: src/config.c:170
msgid "Failed to parse configuration file" msgid "Failed to parse configuration file"
msgstr "" msgstr ""
#: src/main.c:66 #: src/log.c:150
msgid "y"
msgstr ""
#: src/log.c:150
msgid "Y"
msgstr ""
#: src/log.c:152
msgid "n"
msgstr ""
#: src/log.c:152
msgid "N"
msgstr ""
#: src/log.c:155
msgid "Please answer with y/n"
msgstr ""
#: src/main.c:74
#, c-format #, c-format
msgid "Failed to access paths (%s)" msgid "Failed to access paths (%s)"
msgstr "" msgstr ""
#: src/main.c:74 #: src/main.c:82
msgid "Failed to lock, mc is already running" msgid "Failed to lock, mc is already running"
msgstr "" msgstr ""
#: src/main.c:77 #: src/main.c:85
msgid "Failed to lock, did you mess up your directory permissions?" msgid "Failed to lock, did you mess up your directory permissions?"
msgstr "" msgstr ""
#: src/main.c:86
#, c-format
msgid "%s: command failed"
msgstr ""
#: src/main.c:90
#, c-format
msgid "%s: command successful"
msgstr ""
#: src/main.c:94 #: src/main.c:94
#, c-format #, c-format
msgid "MatterLinux Configuration Manager (%s)" msgid "%s: command failed"
msgstr ""
#: src/main.c:95
msgid "Different operations are done using different commands\n"
msgstr "" msgstr ""
#: src/main.c:98 #: src/main.c:98
msgid "pull down a configuration" #, c-format
msgid "%s: command successful"
msgstr "" msgstr ""
#: src/main.c:101 #: src/main.c:102
msgid "build the configuration in the current directory" #, c-format
msgid "MatterLinux Configuration Manager (%s)"
msgstr "" msgstr ""
#: src/main.c:103 #: src/main.c:103
msgid "Different operations are done using different commands\n"
msgstr ""
#: src/main.c:106
msgid "pull down a configuration"
msgstr ""
#: src/main.c:109
msgid "build the configuration in the current directory"
msgstr ""
#: src/main.c:111
msgid "" msgid ""
"Licensed under GPLv3, see <https://www.gnu.org/licenses/> for more " "Licensed under GPLv3, see <https://www.gnu.org/licenses/> for more "
"information" "information"
@ -102,21 +126,58 @@ msgstr ""
msgid "Please specify a config name or a URL" msgid "Please specify a config name or a URL"
msgstr "" msgstr ""
#: src/pull.c:55 #: src/pull.c:56
#, c-format #, c-format
msgid "Cloning %s" msgid "Cloning %s"
msgstr "" msgstr ""
#: src/pull.c:60 #: src/pull.c:61
#, c-format #, c-format
msgid "Failed to clone the %s: %s" msgid "Failed to clone the %s:"
msgstr "" msgstr ""
#: src/pull.c:70 #: src/pull.c:72
#, c-format #, c-format
msgid "Failed to chdir to %s" msgid "Failed to chdir to %s"
msgstr "" msgstr ""
#: src/pull.c:76 #: src/pull.c:77
msgid "Failed to load the configuration file (mc.cfg):" msgid "Failed to load the configuration file (mc.cfg):"
msgstr "" msgstr ""
#: src/pull.c:82
msgid "Loaded repository configuration"
msgstr ""
#: src/pull.c:83
msgid "Configuration details:\n"
msgstr ""
#: src/pull.c:84
msgid "Name"
msgstr ""
#: src/pull.c:85
msgid "Author"
msgstr ""
#: src/pull.c:87
msgid "Keywords"
msgstr ""
#: src/pull.c:92
msgid "Do you want to continue?"
msgstr ""
#: src/pull.c:95
msgid "Checking all the targets"
msgstr ""
#: src/pull.c:99
#, c-format
msgid "Failed to access the source for the target \"%s\""
msgstr ""
#: src/pull.c:105
msgid "All the targets are OK"
msgstr ""

View File

@ -15,18 +15,44 @@ bool target_is_valid(target_t *target) {
} }
if (NULL == target->dst) { 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; return false;
} }
if (NULL == target->src) { 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 false;
} }
return true; 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) { bool config_add_target(config_t *config, char *name) {
target_t *new = malloc(sizeof(target_t)); target_t *new = malloc(sizeof(target_t));
clist_init(&new->requires); clist_init(&new->requires);
@ -48,25 +74,6 @@ bool config_add_target(config_t *config, char *name) {
return true; 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) { 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 MATCH(s, k) eq((char *)section, s) && eq((char *)key, k)
#define MATCHKEY(k) 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")) { } else if (MATCH("details", "keywords")) {
clist_from_str(&config->keywords, (char *)value); clist_from_str(&config->keywords, (char *)value);
return 1; 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 || (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;
}
}
debug("adding new target => %s", section); debug("adding new target => %s", section);
config_add_target(config, strdup(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); config->t_last->dst = strdup(value);
return 1; return 1;
} else if (MATCHKEY("src")) { } else if (MATCHKEY("src")) {
config->t_last->dst = strdup(value); config->t_last->src = strdup(value);
return 1; return 1;
} else if (MATCHKEY("requires")) { } else if (MATCHKEY("requires")) {
clist_from_str(&config->t_last->requires, strdup(value)); clist_from_str(&config->t_last->requires, strdup(value));
return 1; return 1;
} }
UNKNOWN:
error_set(_("Key %s is unknown"), key); error_set(_("Key %s is unknown"), key);
errno = ConfigUnknown; errno = ConfigUnknown;
return 0; return 0;
@ -140,10 +143,17 @@ void config_free(config_t *config) {
} }
clist_free(&config->keywords); 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) { bool config_load(config_t *config, char *path) {
if (!exists(path) || is_dir(path)) { if (!exists(path) || is_dir(path)) {
error_set(_("Configuration file not found"));
errno = ConfigNotFound; errno = ConfigNotFound;
return false; return false;
} }
@ -156,7 +166,7 @@ bool config_load(config_t *config, char *path) {
if (ini_parse(path, config_handler, config) < 0) { if (ini_parse(path, config_handler, config) < 0) {
config_free(config); config_free(config);
if (errno != ConfigUnknown && errno != ConfigInvalid) { if (errno != ConfigUnknown) {
error_set(_("Failed to parse configuration file")); error_set(_("Failed to parse configuration file"));
errno = ConfigParseFail; errno = ConfigParseFail;
} }

View File

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

View File

@ -1,5 +1,8 @@
#include "log.h" #include "log.h"
#include "env.h" #include "env.h"
#include "intl.h"
#include "util.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
@ -88,6 +91,17 @@ void error(const char *msg, ...) {
va_end(args); 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, ...) { void success(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
@ -112,3 +126,32 @@ void debug(const char *msg, ...) {
va_end(args); 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_RED "\x1b[31m"
#define COLOR_BOLD "\x1b[1m" #define COLOR_BOLD "\x1b[1m"
#define COLOR_BLUE "\x1b[34m" #define COLOR_BLUE "\x1b[34m"
#define COLOR_CYAN "\x1b[36m"
#define COLOR_GREEN "\x1b[32m" #define COLOR_GREEN "\x1b[32m"
#define COLOR_MAGENTA "\x1b[35m" #define COLOR_MAGENTA "\x1b[35m"
#define COLOR_RESET "\x1b[0m" #define COLOR_UNDERLINE "\x1b[4m"
#define COLOR_RESET "\x1b[0m"
void bar_init(); void bar_init();
bool bar(float, float); bool bar(float, float);
void bar_free(); void bar_free();
void info(const char *msg, ...); void info(const char *, ...);
void error(const char *msg, ...); void error(const char *, ...);
void success(const char *msg, ...); void details(const char *, ...);
void success(const char *, ...);
void debug(const char *, ...); void debug(const char *, ...);
void input(const char *, ...);
bool yesno(const char *);

View File

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

View File

@ -17,7 +17,7 @@
#define _(x) gettext(x) #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); bar(stats->indexed_objects, stats->total_objects);
return 0; return 0;
} }
@ -29,6 +29,7 @@ bool pull_cmd() {
} }
char *repo_url = NULL, *repo_root = NULL; char *repo_url = NULL, *repo_root = NULL;
config_t repo_cfg = {.name = NULL};
bool ret = false; bool ret = false;
if (url_is_local(args.list[1])) { if (url_is_local(args.list[1])) {
@ -49,15 +50,16 @@ bool pull_cmd() {
git_repository *repo = NULL; git_repository *repo = NULL;
git_clone_options opts = GIT_CLONE_OPTIONS_INIT; git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
opts.fetch_opts.callbacks.transfer_progress = fetch_progress; opts.fetch_opts.callbacks.transfer_progress = pull_progress;
opts.fetch_opts.callbacks.payload = NULL; opts.fetch_opts.callbacks.payload = NULL;
info(_("Cloning %s"), repo_url); info(_("Cloning %s"), repo_url);
bar_init(); 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(); 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(); bar_free();
goto END; goto END;
} }
@ -71,23 +73,40 @@ COPY:
goto END; goto END;
} }
config_t repo_cfg;
if (!config_load(&repo_cfg, "mc.cfg")) { if (!config_load(&repo_cfg, "mc.cfg")) {
error(_("Failed to load the configuration file (mc.cfg):")); error(_("Failed to load the configuration file (mc.cfg):"));
printf(" %s\n", errch); details(errch);
goto END; goto END;
} }
info("Configuration details:"); success(_("Loaded repository configuration"));
printf(COLOR_BOLD " Name" COLOR_RESET ": %s\n", repo_cfg.name); info(_("Configuration details:\n"));
printf(COLOR_BOLD " Author" COLOR_RESET ": %s\n", repo_cfg.author); 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++) for (int i = 0; i < repo_cfg.keywords.s; i++)
printf("%s ", repo_cfg.keywords.c[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: END:
if(repo_cfg.name != NULL)
config_free(&repo_cfg);
free(repo_url); free(repo_url);
return ret; return ret;
} }