first commit
This commit is contained in:
8
src/args.c
Normal file
8
src/args.c
Normal file
@ -0,0 +1,8 @@
|
||||
#include "args.h"
|
||||
|
||||
args_t args;
|
||||
|
||||
void args_load(int argc, char *argv[]) {
|
||||
args.count = argc;
|
||||
args.list = argv;
|
||||
}
|
9
src/args.h
Normal file
9
src/args.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct Args {
|
||||
int count;
|
||||
char **list;
|
||||
} args_t;
|
||||
|
||||
extern args_t args;
|
||||
void args_load(int, char *[]);
|
173
src/config.c
Normal file
173
src/config.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include <ini.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "error.h"
|
||||
#include "intl.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
bool target_is_valid(target_t *target) {
|
||||
if (NULL == target->name) {
|
||||
error_set(_("Configuration target is missing a name"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NULL == target->dst) {
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool config_add_target(config_t *config, char *name) {
|
||||
target_t *new = malloc(sizeof(target_t));
|
||||
clist_init(&new->requires);
|
||||
|
||||
new->next = NULL;
|
||||
new->name = name;
|
||||
new->desc = NULL;
|
||||
new->dst = NULL;
|
||||
new->src = NULL;
|
||||
|
||||
if (NULL == config->t_first || NULL == config->t_last) {
|
||||
config->t_first = new;
|
||||
config->t_last = new;
|
||||
return true;
|
||||
}
|
||||
|
||||
config->t_last->next = new;
|
||||
config->t_last = new;
|
||||
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)
|
||||
|
||||
if (strlen(section) == 0)
|
||||
return 1;
|
||||
|
||||
config_t *config = data;
|
||||
|
||||
if (MATCH("details", "name")) {
|
||||
config->name = strdup(value);
|
||||
return 1;
|
||||
} else if (MATCH("details", "author")) {
|
||||
config->author = strdup(value);
|
||||
return 1;
|
||||
} else if (MATCH("details", "keywords")) {
|
||||
clist_from_str(&config->keywords, (char *)value);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
debug("adding new target => %s", section);
|
||||
config_add_target(config, strdup(section));
|
||||
}
|
||||
|
||||
if (MATCHKEY("desc")) {
|
||||
config->t_last->desc = strdup(value);
|
||||
return 1;
|
||||
} else if (MATCHKEY("dst")) {
|
||||
config->t_last->dst = strdup(value);
|
||||
return 1;
|
||||
} else if (MATCHKEY("src")) {
|
||||
config->t_last->dst = strdup(value);
|
||||
return 1;
|
||||
} else if (MATCHKEY("requires")) {
|
||||
clist_from_str(&config->t_last->requires, strdup(value));
|
||||
return 1;
|
||||
}
|
||||
|
||||
error_set(_("Key %s is unknown"), key);
|
||||
errno = ConfigUnknown;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void target_free(target_t *target) {
|
||||
free(target->name);
|
||||
free(target->desc);
|
||||
free(target->dst);
|
||||
free(target->src);
|
||||
clist_free(&target->requires);
|
||||
free(target);
|
||||
}
|
||||
|
||||
void config_free(config_t *config) {
|
||||
free(config->name);
|
||||
free(config->author);
|
||||
|
||||
target_t *cur = config->t_first, *prev = NULL;
|
||||
while (cur != NULL) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
target_free(prev);
|
||||
}
|
||||
|
||||
clist_free(&config->keywords);
|
||||
}
|
||||
|
||||
bool config_load(config_t *config, char *path) {
|
||||
if (!exists(path) || is_dir(path)) {
|
||||
errno = ConfigNotFound;
|
||||
return false;
|
||||
}
|
||||
|
||||
config->name = NULL;
|
||||
config->author = NULL;
|
||||
config->t_first = NULL;
|
||||
config->t_last = NULL;
|
||||
clist_init(&config->keywords);
|
||||
|
||||
if (ini_parse(path, config_handler, config) < 0) {
|
||||
config_free(config);
|
||||
if (errno != ConfigUnknown && errno != ConfigInvalid) {
|
||||
error_set(_("Failed to parse configuration file"));
|
||||
errno = ConfigParseFail;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!config_is_valid(config)) {
|
||||
errno = ConfigInvalid;
|
||||
config_free(config);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
25
src/config.h
Normal file
25
src/config.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "util.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct target {
|
||||
struct target *next;
|
||||
clist_t
|
||||
requires;
|
||||
char *name;
|
||||
char *desc;
|
||||
char *src;
|
||||
char *dst;
|
||||
} target_t;
|
||||
|
||||
typedef struct config {
|
||||
target_t *t_first;
|
||||
target_t *t_last;
|
||||
|
||||
char *name;
|
||||
char *author;
|
||||
clist_t keywords;
|
||||
} config_t;
|
||||
|
||||
bool config_load(config_t *, char *);
|
23
src/env.c
Normal file
23
src/env.c
Normal file
@ -0,0 +1,23 @@
|
||||
#include "env.h"
|
||||
#include <pwd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
char *env_mc_root() {
|
||||
char *env = getenv("MC_ROOT");
|
||||
if (env == NULL) {
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
return pw->pw_dir;
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
bool env_mc_yes() {
|
||||
return NULL != getenv("MC_YES");
|
||||
}
|
||||
|
||||
bool env_mc_debug() {
|
||||
return NULL != getenv("MC_DEBUG");
|
||||
}
|
6
src/env.h
Normal file
6
src/env.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
char *env_mc_root();
|
||||
bool env_mc_yes();
|
||||
bool env_mc_debug();
|
27
src/error.c
Normal file
27
src/error.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include "error.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
char *errch = NULL;
|
||||
int errno = 0;
|
||||
|
||||
char *error_set(char *text, ...) {
|
||||
if (NULL != errch)
|
||||
free(errch);
|
||||
|
||||
va_list args, argscp;
|
||||
va_start(args, text);
|
||||
va_copy(argscp, args);
|
||||
|
||||
int size = vsnprintf(NULL, 0, text, args);
|
||||
|
||||
errch = malloc(size + 1);
|
||||
bzero(errch, size + 1);
|
||||
vsprintf(errch, text, argscp);
|
||||
|
||||
va_end(argscp);
|
||||
va_end(args);
|
||||
return errch;
|
||||
}
|
13
src/error.h
Normal file
13
src/error.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
enum ErrorCodes {
|
||||
ConfigUnknown = 955,
|
||||
ConfigNotFound = 954,
|
||||
ConfigInvalid = 953,
|
||||
ConfigParseFail = 952,
|
||||
};
|
||||
|
||||
extern int errno;
|
||||
extern char *errch;
|
||||
|
||||
char *error_set(char *text, ...);
|
3
src/intl.h
Normal file
3
src/intl.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
#include <libintl.h>
|
||||
#define _(x) gettext(x)
|
17
src/lock.c
Normal file
17
src/lock.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include "lock.h"
|
||||
#include "paths.h"
|
||||
#include "util.h"
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
lock_st lock() {
|
||||
if (exists(mc_lock_path))
|
||||
return ALREADY_LOCKED;
|
||||
if (creat(mc_lock_path, 0600) == -1)
|
||||
return LOCK_ERROR;
|
||||
return LOCK_SUCCESS;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
unlink(mc_lock_path);
|
||||
}
|
9
src/lock.h
Normal file
9
src/lock.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
typedef enum lock_state {
|
||||
ALREADY_LOCKED = 1,
|
||||
LOCK_SUCCESS = 2,
|
||||
LOCK_ERROR = 3,
|
||||
} lock_st;
|
||||
|
||||
lock_st lock();
|
||||
void unlock();
|
114
src/log.c
Normal file
114
src/log.c
Normal file
@ -0,0 +1,114 @@
|
||||
#include "log.h"
|
||||
#include "env.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int lastprog = -1;
|
||||
struct winsize barwin = {0};
|
||||
|
||||
void bar_init() {
|
||||
lastprog = -1;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &barwin);
|
||||
printf("\e[?25l");
|
||||
bar(0, 1);
|
||||
}
|
||||
|
||||
void bar_free() {
|
||||
int size = barwin.ws_col;
|
||||
|
||||
printf("\r");
|
||||
for (int i = 0; i < size; i++)
|
||||
printf(" ");
|
||||
printf("\r");
|
||||
|
||||
printf("\e[?25h");
|
||||
}
|
||||
|
||||
bool bar(float cur, float max) {
|
||||
if (cur <= 0 || max <= 0 || cur > max)
|
||||
return false;
|
||||
|
||||
float per = 100 * (cur / max);
|
||||
if (per > 100) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char perc[20];
|
||||
sprintf(perc, " %%%.f", per);
|
||||
|
||||
int size = barwin.ws_col - (3 + strlen(perc));
|
||||
if (size <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int prog = size * (cur / max);
|
||||
if (prog == lastprog || prog > size)
|
||||
return true;
|
||||
lastprog = prog;
|
||||
|
||||
printf("\r" COLOR_BOLD "[");
|
||||
for (int i = 0; i < prog; i++) {
|
||||
printf("#");
|
||||
}
|
||||
printf(COLOR_BLUE "#" COLOR_RESET COLOR_BOLD);
|
||||
|
||||
for (int i = prog; i < size; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("]" COLOR_RESET);
|
||||
|
||||
printf(COLOR_BOLD COLOR_BLUE "%s" COLOR_RESET "\r", perc);
|
||||
return true;
|
||||
}
|
||||
|
||||
void info(const char *msg, ...) {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
printf(COLOR_BOLD COLOR_BLUE ">>> " COLOR_RESET COLOR_BOLD);
|
||||
vprintf(msg, args);
|
||||
printf(COLOR_RESET "\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void error(const char *msg, ...) {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
printf(COLOR_BOLD COLOR_RED ">>> " COLOR_RESET COLOR_BOLD);
|
||||
vprintf(msg, args);
|
||||
printf(COLOR_RESET "\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void success(const char *msg, ...) {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
printf(COLOR_BOLD COLOR_GREEN ">>> " COLOR_RESET COLOR_BOLD);
|
||||
vprintf(msg, args);
|
||||
printf(COLOR_RESET "\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void debug(const char *msg, ...) {
|
||||
if (!env_mc_debug())
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
printf(COLOR_BOLD COLOR_MAGENTA "DEBUG: " COLOR_RESET COLOR_BOLD);
|
||||
vprintf(msg, args);
|
||||
printf(COLOR_RESET "\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
18
src/log.h
Normal file
18
src/log.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
#define COLOR_RED "\x1b[31m"
|
||||
#define COLOR_BOLD "\x1b[1m"
|
||||
#define COLOR_BLUE "\x1b[34m"
|
||||
#define COLOR_GREEN "\x1b[32m"
|
||||
#define COLOR_MAGENTA "\x1b[35m"
|
||||
#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 debug(const char *, ...);
|
106
src/main.c
Normal file
106
src/main.c
Normal file
@ -0,0 +1,106 @@
|
||||
// clang-format off
|
||||
|
||||
/*
|
||||
|
||||
* mc | MatterLinux Configuration Manager
|
||||
* MatterLinux 2023-2024 (https://matterlinux.xyz)
|
||||
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
// clang-format on
|
||||
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "args.h"
|
||||
#include "gen.h"
|
||||
#include "lock.h"
|
||||
#include "log.h"
|
||||
#include "paths.h"
|
||||
#include "pull.h"
|
||||
#include "util.h"
|
||||
|
||||
#define _(x) gettext(x)
|
||||
|
||||
typedef bool (*cmd)();
|
||||
struct CmdMap {
|
||||
char *name;
|
||||
bool lock;
|
||||
cmd func;
|
||||
};
|
||||
|
||||
struct CmdMap cmdmap[] = {
|
||||
{.name = "mc-pull", .lock = true, .func = pull_cmd},
|
||||
{.name = "mc-gen", .lock = false, .func = gen_cmd },
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
setbuf(stdout, NULL);
|
||||
setlocale(LC_ALL, "");
|
||||
textdomain("mc");
|
||||
|
||||
for (int i = 0; i < sizeof(cmdmap) / sizeof(struct CmdMap); i++) {
|
||||
if (strcmp(argv[0], cmdmap[i].name) != 0)
|
||||
continue;
|
||||
|
||||
args_load(argc, argv);
|
||||
|
||||
if(!paths_load()){
|
||||
error(_("Failed to access paths (%s)"), mc_dir);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (cmdmap[i].lock) {
|
||||
int st = lock();
|
||||
switch (st) {
|
||||
case ALREADY_LOCKED:
|
||||
error(_("Failed to lock, mc is already running"));
|
||||
return EXIT_FAILURE;
|
||||
case LOCK_ERROR:
|
||||
error(_("Failed to lock, did you mess up your directory permissions?"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = cmdmap[i].func();
|
||||
unlock();
|
||||
|
||||
if (!ret) {
|
||||
error(_("%s: command failed"), cmdmap[i].name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
success(_("%s: command successful"), cmdmap[i].name);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
info(_("MatterLinux Configuration Manager (%s)"), VERSION);
|
||||
info(_("Different operations are done using different commands\n"));
|
||||
|
||||
printf(COLOR_BOLD " mc-pull" COLOR_RESET ": ");
|
||||
printf(" %s\n", _("pull down a configuration"));
|
||||
|
||||
printf(COLOR_BOLD " mc-gen" COLOR_RESET ": ");
|
||||
printf(" %s\n\n", _("build the configuration in the current directory"));
|
||||
|
||||
info(_("Licensed under GPLv3, see <https://www.gnu.org/licenses/> for more "
|
||||
"information"));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
31
src/paths.c
Normal file
31
src/paths.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "env.h"
|
||||
#include "paths.h"
|
||||
#include "util.h"
|
||||
|
||||
char *mc_lock_path;
|
||||
char *mc_tmp_path;
|
||||
char *mc_root;
|
||||
char *mc_dir;
|
||||
|
||||
char *append_root(char *pth) {
|
||||
char fp[strlen(mc_root) + strlen(pth) + 10];
|
||||
join(fp, mc_root, pth);
|
||||
return strdup(fp);
|
||||
}
|
||||
|
||||
bool paths_load() {
|
||||
mc_root = env_mc_root();
|
||||
if (!exists(mc_root) || !is_dir(mc_root))
|
||||
return false;
|
||||
|
||||
mc_dir = append_root(MC_DIR);
|
||||
mc_lock_path = append_root(LOCK_PATH);
|
||||
mc_tmp_path = append_root(TMP_PATH);
|
||||
|
||||
if (!mksubdirsp(mc_dir, 0700))
|
||||
return false;
|
||||
return true;
|
||||
}
|
11
src/paths.h
Normal file
11
src/paths.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#define MC_DIR ".local/share/mc"
|
||||
#define TMP_PATH MC_DIR "/tmp"
|
||||
#define LOCK_PATH MC_DIR "/lock"
|
||||
|
||||
bool paths_load();
|
||||
extern char *mc_lock_path;
|
||||
extern char *mc_tmp_path;
|
||||
extern char *mc_root;
|
||||
extern char *mc_dir;
|
93
src/pull.c
Normal file
93
src/pull.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include "pull.h"
|
||||
#include "args.h"
|
||||
#include "config.h"
|
||||
#include "error.h"
|
||||
#include "log.h"
|
||||
#include "paths.h"
|
||||
#include "url.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <git2.h>
|
||||
#include <git2/global.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define _(x) gettext(x)
|
||||
|
||||
int fetch_progress(const git_indexer_progress *stats, void *data) {
|
||||
bar(stats->indexed_objects, stats->total_objects);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool pull_cmd() {
|
||||
if (args.count != 2) {
|
||||
error(_("Please specify a config name or a URL"));
|
||||
return false;
|
||||
}
|
||||
|
||||
char *repo_url = NULL, *repo_root = NULL;
|
||||
bool ret = false;
|
||||
|
||||
if (url_is_local(args.list[1])) {
|
||||
repo_root = args.list[1];
|
||||
goto COPY;
|
||||
}
|
||||
|
||||
else if (url_is_name(args.list[1]))
|
||||
repo_url = url_complete(args.list[1]);
|
||||
|
||||
else
|
||||
repo_url = url_ensure_protocol(args.list[1]);
|
||||
|
||||
rmrf(mc_tmp_path);
|
||||
repo_root = mc_tmp_path;
|
||||
|
||||
git_libgit2_init();
|
||||
|
||||
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;
|
||||
|
||||
info(_("Cloning %s"), repo_url);
|
||||
bar_init();
|
||||
|
||||
if (git_clone(&repo, repo_url, repo_root, NULL) < 0) {
|
||||
const git_error *e = git_error_last();
|
||||
error(_("Failed to clone the %s: %s"), repo_url, e->message);
|
||||
bar_free();
|
||||
goto END;
|
||||
}
|
||||
|
||||
bar_free();
|
||||
git_libgit2_shutdown();
|
||||
|
||||
COPY:
|
||||
if (chdir(repo_root) < 0) {
|
||||
error(_("Failed to chdir to %s"), repo_root);
|
||||
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);
|
||||
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);
|
||||
|
||||
printf(COLOR_BOLD " Keywords" COLOR_RESET ":");
|
||||
for (int i = 0; i < repo_cfg.keywords.s; i++)
|
||||
printf("%s ", repo_cfg.keywords.c[i]);
|
||||
printf("\n");
|
||||
|
||||
END:
|
||||
free(repo_url);
|
||||
return ret;
|
||||
}
|
4
src/pull.h
Normal file
4
src/pull.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
|
||||
bool pull_cmd();
|
26
src/repo.c
Normal file
26
src/repo.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include <git2.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TMP_PATH "/tmp/confer"
|
||||
|
||||
char *repo_clone(char *url) {
|
||||
git_libgit2_init();
|
||||
git_repository *repo = NULL;
|
||||
|
||||
int random = randint(100, 999);
|
||||
char path[strlen(TMP_PATH) + 4];
|
||||
sprintf(path, "%s_%d", TMP_PATH, random);
|
||||
|
||||
if (git_clone(&repo, url, path, NULL) != 0) {
|
||||
error("Failed to clone the repository: " COLOR_RESET "%s", git_error_last()->message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
git_libgit2_shutdown();
|
||||
return strdup(path);
|
||||
}
|
1
src/repo.h
Normal file
1
src/repo.h
Normal file
@ -0,0 +1 @@
|
||||
char *repo_clone(char *);
|
46
src/url.c
Normal file
46
src/url.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include "util.h"
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define HUB_URL "https://configs.matterlinux.xyz"
|
||||
|
||||
bool url_is_name(char *name) {
|
||||
for (char *c = name; *c != '\0'; c++) {
|
||||
if (*c == '/' || *c == '.')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool url_is_local(char *url) {
|
||||
bool ret = false;
|
||||
if (startswith(url, "http://") || startswith(url, "https://"))
|
||||
return ret;
|
||||
|
||||
DIR *dir = NULL;
|
||||
if (access(url, F_OK) == 0 && (dir = opendir(url)) != NULL)
|
||||
ret = true;
|
||||
|
||||
closedir(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *url_complete(char *name) {
|
||||
char *url = malloc(strlen(name) + strlen(HUB_URL) + 1);
|
||||
|
||||
sprintf(url, "%s/%s", HUB_URL, name);
|
||||
return url;
|
||||
}
|
||||
|
||||
char *url_ensure_protocol(char *url) {
|
||||
if (startswith(url, "http://") || startswith(url, "https://"))
|
||||
return strdup(url);
|
||||
|
||||
char *full = malloc(strlen("https://") + strlen(url) + 1);
|
||||
join(full, "https://", url);
|
||||
return full;
|
||||
}
|
6
src/url.h
Normal file
6
src/url.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
bool url_is_name(char *);
|
||||
char *url_complete(char *);
|
||||
char *url_ensure_protocol(char *);
|
||||
bool url_is_local(char *);
|
189
src/util.c
Normal file
189
src/util.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
bool eq(char *s1, char *s2) {
|
||||
if (strlen(s1) != strlen(s2))
|
||||
return false;
|
||||
return strcmp(s1, s2) == 0;
|
||||
}
|
||||
|
||||
bool joinhome(char *res, char *path) {
|
||||
char *homedir = getenv("HOME");
|
||||
|
||||
if (NULL == homedir)
|
||||
return false;
|
||||
|
||||
snprintf(res, PATH_MAX, "%s/%s", homedir, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exists(char *path) {
|
||||
return access(path, F_OK) == 0;
|
||||
}
|
||||
|
||||
bool endswith(const char *str, const char *suf) {
|
||||
int strl = strlen(str);
|
||||
int sufl = strlen(suf);
|
||||
|
||||
if (sufl > strl)
|
||||
return false;
|
||||
|
||||
return strncmp(str + strl - sufl, suf, sufl) == 0;
|
||||
}
|
||||
|
||||
bool startswith(char *str, char *sub) {
|
||||
if (strlen(sub) > strlen(str))
|
||||
return false;
|
||||
return strncmp(str, sub, strlen(sub)) == 0;
|
||||
}
|
||||
|
||||
char *check_path(char *bin) {
|
||||
char *path = getenv("PATH");
|
||||
char *res = NULL;
|
||||
|
||||
if (NULL == path)
|
||||
return NULL;
|
||||
path = strdup(path);
|
||||
|
||||
char *p = strtok(path, ":");
|
||||
while (NULL != p) {
|
||||
char *fp = malloc(PATH_MAX);
|
||||
snprintf(fp, PATH_MAX, "%s/%s", p, bin);
|
||||
if (exists(fp)) {
|
||||
res = fp;
|
||||
break;
|
||||
}
|
||||
p = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
free(path);
|
||||
return res;
|
||||
}
|
||||
|
||||
int join(char *res, const char *base, const char *pth) {
|
||||
int blen = strlen(base);
|
||||
|
||||
if ((base[blen - 1] == '/' && pth[0] != '/') || (base[blen - 1] != '/' && pth[0] == '/')) {
|
||||
return sprintf(res, "%s%s", base, pth);
|
||||
} else if (base[blen - 1] != '/' && pth[0] != '/') {
|
||||
return sprintf(res, "%s/%s", base, pth);
|
||||
} else if (base[blen - 1] == '/' && pth[0] == '/') {
|
||||
char *basedup = strdup(base);
|
||||
basedup[blen - 1] = '\0';
|
||||
|
||||
return sprintf(res, "%s%s", basedup, pth);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int randint(int min, int max) {
|
||||
srand(time(NULL));
|
||||
return rand() % max + min;
|
||||
}
|
||||
|
||||
bool is_dir(char *path) {
|
||||
DIR *dir = opendir(path);
|
||||
if (dir) {
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mksubdirsp(char *path, int perms) {
|
||||
char cur[PATH_MAX];
|
||||
bzero(cur, PATH_MAX);
|
||||
int indx = 0;
|
||||
|
||||
for (char *c = path; *c != '\0'; c++) {
|
||||
if (*c == '/' && indx != 0) {
|
||||
cur[indx] = '\0';
|
||||
if (!exists(cur) && mkdir(cur, perms) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
cur[indx] = *c;
|
||||
indx++;
|
||||
}
|
||||
|
||||
if (!exists(cur) && mkdir(cur, perms) < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmrf(char *path) {
|
||||
if (!exists(path))
|
||||
return true;
|
||||
|
||||
if (!is_dir(path))
|
||||
return unlink(path) == 0;
|
||||
|
||||
DIR *dir = opendir(path);
|
||||
struct dirent *ent = NULL;
|
||||
char fp[PATH_MAX] = {};
|
||||
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
if (eq(ent->d_name, ".") || eq(ent->d_name, ".."))
|
||||
continue;
|
||||
|
||||
join(fp, path, ent->d_name);
|
||||
if (!rmrf(fp))
|
||||
return false;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
rmdir(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
void clist_init(clist_t *l) {
|
||||
l->c = NULL;
|
||||
l->s = 0;
|
||||
}
|
||||
|
||||
void clist_from_str(clist_t *l, char *str) {
|
||||
char *save = NULL, *el = NULL;
|
||||
char *strdp = strdup(str);
|
||||
el = strtok_r(strdp, ",", &save);
|
||||
|
||||
while (NULL != el) {
|
||||
clist_add(l, strdup(el));
|
||||
el = strtok_r(NULL, ",", &save);
|
||||
}
|
||||
|
||||
free(strdp);
|
||||
}
|
||||
|
||||
void clist_free(clist_t *l) {
|
||||
if (NULL == l->c || 0 == l->s)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < l->s; i++)
|
||||
free(l->c[i]);
|
||||
free(l->c);
|
||||
l->s = 0;
|
||||
}
|
||||
|
||||
void clist_add(clist_t *l, char *en) {
|
||||
if (NULL == l->c || 0 == l->s) {
|
||||
l->c = malloc(sizeof(char *));
|
||||
l->c[l->s] = en;
|
||||
l->s++;
|
||||
return;
|
||||
}
|
||||
|
||||
l->c = realloc(l->c, sizeof(char *) * (l->s + 1));
|
||||
l->c[l->s] = en;
|
||||
l->s++;
|
||||
}
|
25
src/util.h
Normal file
25
src/util.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct clist {
|
||||
char **c;
|
||||
size_t s;
|
||||
} clist_t;
|
||||
|
||||
bool eq(char *, char *);
|
||||
bool exists(char *);
|
||||
char *check_path(char *);
|
||||
bool joinhome(char *, char *);
|
||||
bool startswith(char *, char *);
|
||||
bool endswith(const char *, const char *);
|
||||
int join(char *, const char *, const char *);
|
||||
int randint(int, int);
|
||||
bool is_dir(char *);
|
||||
bool mksubdirsp(char *, int);
|
||||
bool rmrf(char *);
|
||||
|
||||
void clist_init(clist_t *);
|
||||
void clist_from_str(clist_t *, char *);
|
||||
void clist_add(clist_t *, char *);
|
||||
void clist_free(clist_t *);
|
Reference in New Issue
Block a user