update: refactor and rename

This commit is contained in:
ngn 2024-08-01 04:48:11 +03:00
parent 48d177965e
commit 4354fb8b89
30 changed files with 642 additions and 626 deletions

View File

@ -1,22 +1,30 @@
HEADERS = $(wildcard src/*.h) $(wildcard src/*/*.h) SRCS = $(wildcard src/*.c) $(wildcard src/*/*.c)
CSRCS = $(wildcard src/*.c) $(wildcard src/*/*.c) OBJS = $(patsubst src/%.c,dist/%.o,$(SRCS))
CMDS = mc-pull mc-gen HDRS = $(wildcard src/*.h)
PO_SRCS = $(wildcard locale/*/*/*.po) PO_SRCS = $(wildcard locale/*/*/*.po)
PO_OUTS = $(patsubst locale/%.po,locale/%.mo,$(PO_SRCS)) PO_OUTS = $(patsubst locale/%.po,locale/%.mo,$(PO_SRCS))
PO_DIRS = $(wildcard locale/*/*) PO_DIRS = $(wildcard locale/*/*)
VERSION = 24.02 CFLAGS = -O3 -fstack-protector-strong -fcf-protection=full -fstack-clash-protection
prefix = /usr LIBS = -linih -lgit2 -lcurl -lcrypto
VERSION = 24.03
PREFIX = /usr
CC = gcc CC = gcc
all: dist/mc $(PO_OUTS) all: dist dist/confer $(PO_OUTS)
dist/mc: $(CSRCS) $(HEADERS) dist:
mkdir -p dist mkdir -pv dist/cmd
$(CC) $(CFLAGS) $(CSRCS) -o $@ -DVERSION=\"${VERSION}\" -linih -lgit2 -lcurl -lcrypto
locale/%.mo: locale/%.po dist/confer: $(OBJS)
$(CC) -o $@ $^ $(LIBS) $(CFLAGS)
dist/%.o: src/%.c
$(CC) -c -o $@ $^ $(LIBS) $(CFLAGS) -DVERSION=\"${VERSION}\"
locale/%.mo: locale/%.po
msgfmt $^ -o $@ msgfmt $^ -o $@
locale/%.po: locale/mc.pot locale/%.po: locale/mc.pot
@ -29,36 +37,30 @@ locale/%.po: locale/mc.pot
mv $@.old $@ ; \ mv $@.old $@ ; \
fi; \ fi; \
locale/mc.pot: $(CSRCS) locale/confer.pot: $(SRCS)
mkdir -p locale mkdir -p locale
xgettext -k_ -c $^ -o $@ xgettext -k_ -c $^ -o $@
install: install:
mkdir -pv $(DESTDIR)$(prefix)/bin mkdir -pv $(DESTDIR)/$(PREFIX)/bin
install -v -m755 dist/mc $(DESTDIR)$(prefix)/bin/mc install -v -m755 dist/confer $(DESTDIR)/$(PREFIX)/bin/confer
@for cmd in $(CMDS) ; do \
ln -sfv mc $(DESTDIR)$(prefix)/bin/$$cmd ; \
done
@for po in $(PO_DIRS) ; do \ @for po in $(PO_DIRS) ; do \
echo "installing locale: $$po/mc.mo" ; \ echo "installing locale: $$po/mc.mo" ; \
mkdir -pv $(DESTDIR)/usr/share/$$po ; \ mkdir -pv $(DESTDIR)/$(PREFIX)/share/$$po ; \
cp $$po/mc.mo $(DESTDIR)/usr/share/$$po ; \ cp $$po/mc.mo $(DESTDIR)/$(PREFIX)/share/$$po ; \
done done
uninstall: uninstall:
rm -v $(DESTDIR)$(prefix)/bin/mc rm -v $(DESTDIR)/$(PREFIX)/bin/confer
@for cmd in $(CMDS) ; do \
unlink $(DESTDIR)$(prefix)/bin/$$cmd ; \
done
clean: clean:
rm dist/mc rm dist/mc
rm locale/mc.pot rm locale/mc.pot
@for po in $(PO_DIRS) ; do \ @for po in $(PO_DIRS) ; do \
rm $$po/mc.mo ; \ rm $$po/confer.mo ; \
done done
format: format:
clang-format -i -style=file $(HEADERS) $(CSRCS) clang-format -i -style=file $(HDRS) $(SRCS)
.PHONY: install defcfg uninstall clean .PHONY: install uninstall clean format

View File

@ -1,10 +1,10 @@
# mc | MatterLinux configuration manager # confer | MatterLinux configuration manager
`mc` is a simple tool for managing desktop/window manager configurations, `coner` is a simple tool for managing desktop/window manager configurations,
it allows you to easily create configurations from your dot files and it allows you to easily create configurations from your dot files and
allows you to easily install them allows you to easily install them
### Installation ### Installation
To compile `mc` and to use it, you will need the following: To compile `coner` and to use it, you will need the following:
- gcc - gcc
- libgit2 - libgit2
- make - make
@ -18,10 +18,10 @@ release for a stable build**. Clone the repository only for development.
After downloading the source code, you can compile `mc` using the After downloading the source code, you can compile `mc` using the
`make` tool: `make` tool:
``` ```bash
make make
``` ```
After compiling it, you can install the binary, locales and the symbolic links: After compiling it, you can install the binary, locales and the symbolic links:
``` ```bash
make install make install
``` ```

View File

@ -0,0 +1,223 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-01 04:31+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/config.c:30
msgid "Configuration does not have a name field"
msgstr "Configuration does not have a name field"
#: src/config.c:35
msgid "Configuration does not have an author field"
msgstr "Configuration does not have an author field"
#: src/config.c:40
msgid "Configuration does not have any targets"
msgstr "Configuration does not have any targets"
#: src/config.c:102
msgid "Configuration contains multiple targets with the same name"
msgstr "Configuration contains multiple targets with the same name"
#: src/config.c:129
#, c-format
msgid "Key %s is unknown"
msgstr "Key %s is unknown"
#: src/config.c:161
msgid "Configuration file not found"
msgstr "Configuration file not found"
#: src/config.c:177
msgid "Failed to parse configuration file"
msgstr "Failed to parse configuration file"
#: src/config.c:193
msgid "Configuration details:\n"
msgstr "Configuration details:\n"
#: src/config.c:194 src/target.c:122
msgid "Name"
msgstr "Name"
#: src/config.c:196
msgid "Desc"
msgstr "Desc"
#: src/config.c:197
msgid "Author"
msgstr "Author"
#: src/config.c:199
msgid "Keywords"
msgstr "Keywords"
#: src/log.c:127
msgid "y"
msgstr "y"
#: src/log.c:127
msgid "Y"
msgstr "Y"
#: src/log.c:128
msgid "n"
msgstr "n"
#: src/log.c:128
msgid "N"
msgstr "N"
#: src/log.c:131
#, c-format
msgid "%s [y/N] "
msgstr "%s [y/N] "
#: src/log.c:151
msgid "Please answer with y/n"
msgstr "Please answer with y/n"
#: src/main.c:48
msgid "Program received a segfault"
msgstr "Program received a segfault"
#: src/main.c:61
msgid "pull down a configuration"
msgstr "pull down a configuration"
#: src/main.c:62
msgid "build the configuration in the current directory"
msgstr "build the configuration in the current directory"
#: src/main.c:73
msgid "Please specify the homedir with "
msgstr "Please specify the homedir with "
#: src/main.c:84
msgid "Failed to lock, confer is already running"
msgstr "Failed to lock, confer is already running"
#: src/main.c:88
msgid "Failed to lock, are you root?"
msgstr "Failed to lock, are you root?"
#: src/main.c:100
msgid "Command not found: "
msgstr "Command not found: "
#: src/main.c:102
#, c-format
msgid "MatterLinux configuration manager (version %s)"
msgstr "MatterLinux configuration manager (version %s)"
#: src/main.c:103
msgid "Usage: "
msgstr "Usage: "
#: src/main.c:105
msgid "Here is a list of available commands:"
msgstr "Here is a list of available commands:"
#: src/main.c:111
msgid "Here is a list of available options:"
msgstr "Here is a list of available options:"
#: src/main.c:114 src/main.c:115
#, c-format
msgid " "
msgstr " "
#: src/main.c:117
msgid ""
"Licensed under GPLv3, see https://www.gnu.org/licenses/ for more information"
msgstr ""
"Licensed under GPLv3, see https://www.gnu.org/licenses/ for more information"
#: src/target.c:15
msgid "Configuration target is missing a name"
msgstr "Configuration target is missing a name"
#: src/target.c:20
#, c-format
msgid "Configuration target \"%s\" does not have \"dst\" field"
msgstr "Configuration target \"%s\" does not have \"dst\" field"
#: src/target.c:25
#, c-format
msgid "Configuration target \"%s\" does not have \"src\" field"
msgstr "Configuration target \"%s\" does not have \"src\" field"
#: src/target.c:40
#, c-format
msgid "Failed to open the directory: %s"
msgstr "Failed to open the directory: %s"
#: src/target.c:84
#, c-format
msgid "Source directory \"%s\" does not exist"
msgstr "Source directory \"%s\" does not exist"
#: src/target.c:121
msgid "Target details:\n"
msgstr "Target details:\n"
#: src/target.c:123
msgid "Description"
msgstr "Description"
#: src/url.c:44
msgid "Failed to open /dev/null"
msgstr "Failed to open /dev/null"
#: src/url.c:51
msgid "Failed to init curl"
msgstr "Failed to init curl"
#: src/url.c:63
msgid "Request failed"
msgstr "Request failed"
#: src/url.c:70
msgid "Failed to get the response code"
msgstr "Failed to get the response code"
#: src/url.c:76
msgid "Response is not a redirect"
msgstr "Response is not a redirect"
#: src/url.c:83
msgid "Failed to get the location header"
msgstr "Failed to get the location header"
#: src/url.c:89
msgid "Invalid location header"
msgstr "Invalid location header"
#: src/util.c:105 src/util.c:116
#, c-format
msgid "Failed to create directory: %s"
msgstr "Failed to create directory: %s"
#: src/util.c:195
#, c-format
msgid "Failed to open \"%s\" for reading"
msgstr "Failed to open \"%s\" for reading"
#: src/util.c:197
#, c-format
msgid "Failed to open \"%s\" for writing"
msgstr "Failed to open \"%s\" for writing"

View File

@ -1,297 +0,0 @@
# Turkish translations for PACKAGE package.
# Copyright (C) 2024 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <ngn@ngn.tf>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-05-09 23:28+0300\n"
"PO-Revision-Date: 2024-05-01 13:34+0300\n"
"Last-Translator: <ngn@ngn.tf>\n"
"Language-Team: Turkish <gnome-turk@gnome.org>\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/config.c:24
msgid "Configuration does not have a name field"
msgstr ""
#: src/config.c:29
msgid "Configuration does not have an author field"
msgstr ""
#: src/config.c:34
msgid "Configuration does not have any targets"
msgstr ""
#: src/config.c:95
msgid "Configuration contains multiple targets with the same name"
msgstr ""
#: src/config.c:122
#, c-format
msgid "Key %s is unknown"
msgstr ""
#: src/config.c:154
msgid "Configuration file not found"
msgstr ""
#: src/config.c:170
msgid "Failed to parse configuration file"
msgstr ""
#: src/config.c:186
msgid "Configuration details:\n"
msgstr ""
#: src/config.c:187 src/target.c:122
msgid "Name"
msgstr ""
#: src/config.c:189
msgid "Desc"
msgstr ""
#: src/config.c:190
msgid "Author"
msgstr ""
#: src/config.c:192
msgid "Keywords"
msgstr ""
#: src/gen.c:15
msgid "Please specify a directory for the repository"
msgstr ""
#: src/gen.c:20
msgid "Failed to access the directory"
msgstr ""
#: src/gen.c:25
msgid "Failed to change directory to the specified directory"
msgstr ""
#: src/gen.c:29 src/gen.c:36 src/pull.c:95
msgid "Loaded repository configuration"
msgstr ""
#: src/gen.c:31 src/pull.c:90
msgid "Failed to load the configuration file (mc.cfg):"
msgstr ""
#: src/gen.c:42 src/pull.c:122
msgid "Copying all the targets"
msgstr ""
#: src/gen.c:48 src/pull.c:136
msgid "Failed to copy the target:"
msgstr ""
#: src/log.c:145
msgid "y"
msgstr ""
#: src/log.c:145
msgid "Y"
msgstr ""
#: src/log.c:146
msgid "n"
msgstr ""
#: src/log.c:146
msgid "N"
msgstr ""
#: src/log.c:149
#, c-format
msgid "%s [y/N] "
msgstr ""
#: src/log.c:169
msgid "Please answer with y/n"
msgstr ""
#: src/main.c:62
msgid "Program received a segfault"
msgstr ""
#: src/main.c:81
#, c-format
msgid "Failed to access paths (%s)"
msgstr ""
#: src/main.c:89
msgid "Failed to lock, mc is already running"
msgstr ""
#: src/main.c:92
msgid "Failed to lock, did you mess up your directory permissions?"
msgstr ""
#: src/main.c:101
#, c-format
msgid "%s: command failed"
msgstr ""
#: src/main.c:105
#, c-format
msgid "%s: command successful"
msgstr ""
#: src/main.c:109
#, c-format
msgid "MatterLinux Configuration Manager (%s)"
msgstr ""
#: src/main.c:110
msgid "Different operations are done using different commands\n"
msgstr ""
#: src/main.c:113
msgid "pull down a configuration"
msgstr ""
#: src/main.c:116
msgid "build the configuration in the current directory"
msgstr ""
#: src/main.c:118
msgid ""
"Licensed under GPLv3, see <https://www.gnu.org/licenses/> for more "
"information"
msgstr ""
#: src/pull.c:28
msgid "Please specify a config name or a URL"
msgstr ""
#: src/pull.c:69
#, c-format
msgid "Cloning %s"
msgstr ""
#: src/pull.c:74
#, c-format
msgid "Failed to clone the %s:"
msgstr ""
#: src/pull.c:85
#, c-format
msgid "Failed to chdir to %s"
msgstr ""
#: src/pull.c:98
msgid "Do you want to continue?"
msgstr ""
#: src/pull.c:104
msgid "Checking all the targets"
msgstr ""
#: src/pull.c:110
#, c-format
msgid "Failed to access the source for the target \"%s\""
msgstr ""
#: src/pull.c:119
msgid "All the target checks were successful"
msgstr ""
#: src/pull.c:130
msgid "Install the target?"
msgstr ""
#: src/pull.c:131
msgid "Skipping target"
msgstr ""
#: src/pull.c:169
msgid "Installing all the requirements"
msgstr ""
#: src/pull.c:172
msgid "Failed to run the mp-install command"
msgstr ""
#: src/target.c:15
msgid "Configuration target is missing a name"
msgstr ""
#: src/target.c:20
#, c-format
msgid "Configuration target \"%s\" does not have \"dst\" field"
msgstr ""
#: src/target.c:25
#, c-format
msgid "Configuration target \"%s\" does not have \"src\" field"
msgstr ""
#: src/target.c:40
#, c-format
msgid "Failed to open the directory: %s"
msgstr ""
#: src/target.c:84
#, c-format
msgid "Source directory \"%s\" does not exist"
msgstr ""
#: src/target.c:121
msgid "Target details:\n"
msgstr ""
#: src/target.c:123
msgid "Description"
msgstr ""
#: src/url.c:44
msgid "Failed to open /dev/null"
msgstr ""
#: src/url.c:51
msgid "Failed to init curl"
msgstr ""
#: src/url.c:63
msgid "Request failed"
msgstr ""
#: src/url.c:70
msgid "Failed to get the response code"
msgstr ""
#: src/url.c:76
msgid "Response is not a redirect"
msgstr ""
#: src/url.c:83
msgid "Failed to get the location header"
msgstr ""
#: src/url.c:89
msgid "Invalid location header"
msgstr ""
#: src/util.c:115 src/util.c:126
#, c-format
msgid "Failed to create directory: %s"
msgstr ""
#: src/util.c:205
#, c-format
msgid "Failed to open \"%s\" for reading"
msgstr ""
#: src/util.c:207
#, c-format
msgid "Failed to open \"%s\" for writing"
msgstr ""

View File

@ -1,8 +1,113 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "args.h" #include "args.h"
#include "util.h"
args_t args; void args_add_name(args_t *args, char *name) {
if (NULL == args->list)
args->list = malloc(sizeof(arg_t) * (args->count + 1));
else
args->list = realloc(args->list, sizeof(arg_t) * (args->count + 1));
void args_load(int argc, char *argv[]) { args->list[args->count].name = name;
args.count = argc; args->list[args->count++].value = NULL;
args.list = argv; }
void args_add_value(args_t *args, char *value) {
if (NULL == args->list)
args->list = malloc(sizeof(arg_t) * (args->count + 1));
else
args->list = realloc(args->list, sizeof(arg_t) * (args->count + 1));
args->list[args->count].name = NULL;
args->list[args->count++].value = value;
}
void args_set_value(args_t *args, char *value) {
if (NULL != args->list && args->list[args->count - 1].value == NULL) {
args->list[args->count - 1].value = value;
return;
}
args_add_value(args, value);
}
bool args_split(args_t *args, char *name) {
char *value = NULL;
for (int i = 0; i < args->count; i++) {
if (NULL == args->list[i].name || !eq(args->list[i].name, name))
continue;
value = args->list[i].value;
args->list[i].value = NULL;
break;
}
if (NULL == value)
return false;
args_add_value(args, value);
return true;
}
args_t *args_parse(int argc, char *argv[]) {
args_t *args = malloc(sizeof(args_t));
bzero(args, sizeof(args_t));
if (argc <= 1)
return args;
for (int i = 1; i < argc; i++) {
if (startswith(argv[i], "--"))
args_add_name(args, argv[i] + 2);
else
args_set_value(args, argv[i]);
}
return args;
}
void args_free(args_t *args) {
free(args->list);
free(args);
}
char *args_get_string(args_t *args, char *name) {
for (int i = 0; i < args->count; i++) {
if (NULL == args->list[i].name)
continue;
if (eq(args->list[i].name, name))
return args->list[i].value;
}
return NULL;
}
bool args_get_bool(args_t *args, char *name) {
for (int i = 0; i < args->count; i++) {
if (NULL == args->list[i].name)
continue;
if (eq(args->list[i].name, name))
return true;
}
return false;
}
int args_get_int(args_t *args, char *name) {
for (int i = 0; i < args->count; i++) {
if (NULL == args->list[i].name)
continue;
if (eq(args->list[i].name, name))
return atoi(args->list[i].value);
}
return -1;
} }

View File

@ -1,9 +1,20 @@
#pragma once #pragma once
#include <stdbool.h>
#include <stddef.h>
typedef struct Args { typedef struct arg {
int count; char *name;
char **list; char *value;
} arg_t;
typedef struct args {
arg_t *list;
size_t count;
} args_t; } args_t;
extern args_t args; args_t *args_parse(int argc, char *argv[]);
void args_load(int, char *[]); char *args_get_string(args_t *args, char *name);
bool args_get_bool(args_t *args, char *name);
int args_get_int(args_t *args, char *name);
bool args_split(args_t *args, char *name);
void args_free(args_t *args);

18
src/cmd.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <libmp/all.h>
#include <stdbool.h>
#include "args.h"
#include "ctx.h"
typedef bool (*cmd_func_t)(ctx_t *ctx, args_t *args);
typedef struct cmd {
char *name;
char *desc;
cmd_func_t func;
bool lock;
} cmd_t;
bool cmd_pull(ctx_t *ctx, args_t *args);
bool cmd_gen(ctx_t *ctx, args_t *args);

View File

@ -1,34 +1,49 @@
#include "gen.h" #include "../args.h"
#include "args.h" #include "../cmd.h"
#include "config.h" #include "../config.h"
#include "error.h" #include "../error.h"
#include "intl.h" #include "../intl.h"
#include "log.h" #include "../log.h"
#include "util.h" #include "../util.h"
#include <unistd.h> #include <unistd.h>
bool gen_cmd() { bool cmd_gen(ctx_t *ctx, args_t *args) {
bool ret = false; bool ret = false;
char *dir = NULL;
config_t cfg; config_t cfg;
if (args.count != 2) { for (size_t i = 0; i < args->count; i++) {
error(_("Please specify a directory for the repository")); if (NULL != args->list[i].name || eq(args->list[i].value, "gen"))
return ret; continue;
if (NULL == dir) {
dir = args->list[i].value;
continue;
}
error(_("Please specify only a signle directory for the repository"));
return false;
} }
if (!exists(args.list[1]) || !is_dir(args.list[1])) { if (NULL == dir) {
error(_("Please specify a directory for the repository"));
return false;
}
if (!exists(dir) || !is_dir(dir)) {
error(_("Failed to access the directory")); error(_("Failed to access the directory"));
return ret; return ret;
} }
if (chdir(args.list[1]) < 0) { if (chdir(dir) < 0) {
error(_("Failed to change directory to the specified directory")); error(_("Failed to change directory to the specified directory"));
return ret; return ret;
} }
success(_("Loaded repository configuration")); success(_("Loaded repository configuration"));
if (!config_load(&cfg, "mc.cfg")) {
error(_("Failed to load the configuration file (mc.cfg):")); if (!config_load(ctx, &cfg, "confer.ini")) {
error(_("Failed to load the configuration file (confer.ini):"));
details(errch); details(errch);
return ret; return ret;
} }

View File

@ -1,12 +1,11 @@
#include "pull.h" #include "../args.h"
#include "args.h" #include "../cmd.h"
#include "config.h" #include "../config.h"
#include "error.h" #include "../error.h"
#include "log.h" #include "../log.h"
#include "paths.h" #include "../run.h"
#include "run.h" #include "../url.h"
#include "url.h" #include "../util.h"
#include "util.h"
#include <git2.h> #include <git2.h>
#include <git2/global.h> #include <git2/global.h>
@ -23,41 +22,54 @@ int pull_progress(const git_indexer_progress *stats, void *data) {
return 0; return 0;
} }
bool pull_cmd() { bool cmd_pull(ctx_t *ctx, args_t *args) {
if (args.count != 2) { char *repo_url = NULL, *repo_root = NULL, *url = NULL;
config_t repo_cfg = {.name = NULL};
bool ret = false;
for (size_t i = 0; i < args->count; i++) {
if (NULL != args->list[i].name || eq(args->list[i].value, "pull"))
continue;
if (NULL == url) {
url = args->list[i].value;
continue;
}
error(_("Please specify only a single config name or a URL"));
return false;
}
if (NULL == url) {
error(_("Please specify a config name or a URL")); error(_("Please specify a config name or a URL"));
return false; return false;
} }
char *repo_url = NULL, *repo_root = NULL; if (url_is_local(url)) {
config_t repo_cfg = {.name = NULL}; repo_root = url;
bool ret = false;
if (url_is_local(args.list[1])) {
repo_root = args.list[1];
goto COPY; goto COPY;
} }
else if (url_is_name(args.list[1])) else if (url_is_name(url))
repo_url = url_complete(args.list[1]); repo_url = url_complete(url);
else else
repo_url = url_ensure_protocol(args.list[1]); repo_url = url_ensure_protocol(url);
if (NULL == repo_url) { if (NULL == repo_url) {
switch (errno) { switch (errno) {
case UrlReqBadCode: case UrlReqBadCode:
error("Specified configuration is not found"); error(_("Specified configuration is not found"));
break; break;
default: default:
error("Failed to access the URL"); error(_("Failed to access the URL"));
details(errch); details(errch);
} }
goto END; goto END;
} }
rmrf(mc_tmp_path); rmrf(ctx->tmp_path);
repo_root = mc_tmp_path; repo_root = ctx->tmp_path;
git_libgit2_init(); git_libgit2_init();
@ -86,7 +98,7 @@ COPY:
goto END; goto END;
} }
if (!config_load(&repo_cfg, "mc.cfg")) { if (!config_load(ctx, &repo_cfg, "mc.cfg")) {
error(_("Failed to load the configuration file (mc.cfg):")); error(_("Failed to load the configuration file (mc.cfg):"));
details(errch); details(errch);
goto END; goto END;

View File

@ -1,14 +1,20 @@
#include <ini.h> #include <ini.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "config.h" #include "config.h"
#include "ctx.h"
#include "error.h" #include "error.h"
#include "intl.h" #include "intl.h"
#include "log.h" #include "log.h"
#include "paths.h"
#include "util.h" #include "util.h"
struct __config_args {
config_t *config;
ctx_t *ctx;
};
bool config_contains_target(config_t *config, char *name) { bool config_contains_target(config_t *config, char *name) {
target_t *cur = config->t_last; target_t *cur = config->t_last;
while (cur) { while (cur) {
@ -70,7 +76,9 @@ int config_handler(void *data, const char *section, const char *key, const char
if (strlen(section) == 0) if (strlen(section) == 0)
return 1; return 1;
config_t *config = data; struct __config_args *args = data;
config_t *config = args->config;
ctx_t *ctx = args->ctx;
if (MATCH("details", "name")) { if (MATCH("details", "name")) {
config->name = strdup(value); config->name = strdup(value);
@ -90,7 +98,6 @@ int config_handler(void *data, const char *section, const char *key, const char
} }
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))) {
debug("adding new target => %s", section);
if (config_contains_target(config, (char *)section)) { if (config_contains_target(config, (char *)section)) {
error_set(_("Configuration contains multiple targets with the same name")); error_set(_("Configuration contains multiple targets with the same name"));
errno = ConfigMultiple; errno = ConfigMultiple;
@ -103,9 +110,9 @@ int config_handler(void *data, const char *section, const char *key, const char
config->t_last->desc = strdup(value); config->t_last->desc = strdup(value);
return 1; return 1;
} else if (MATCHKEY("dst")) { } else if (MATCHKEY("dst")) {
int len = strlen(value) + strlen(mc_root) + 2; int len = strlen(value) + strlen(ctx->home_path) + 2;
config->t_last->dst = malloc(len); config->t_last->dst = malloc(len);
join(config->t_last->dst, mc_root, value); join(config->t_last->dst, ctx->home_path, value);
return 1; return 1;
} else if (MATCHKEY("src")) { } else if (MATCHKEY("src")) {
config->t_last->src = strdup(value); config->t_last->src = strdup(value);
@ -149,22 +156,22 @@ void config_free(config_t *config) {
clist_init(&config->keywords); clist_init(&config->keywords);
} }
bool config_load(config_t *config, char *path) { bool config_load(ctx_t *ctx, config_t *config, char *path) {
if (!exists(path) || is_dir(path)) { if (!exists(path) || is_dir(path)) {
error_set(_("Configuration file not found")); error_set(_("Configuration file not found"));
errno = ConfigNotFound; errno = ConfigNotFound;
return false; return false;
} }
config->name = NULL; bzero(config, sizeof(config_t));
config->desc = NULL;
config->author = NULL;
config->t_first = NULL;
config->t_last = NULL;
config->t_len = 0;
clist_init(&config->keywords); clist_init(&config->keywords);
if (ini_parse(path, config_handler, config) < 0) { struct __config_args args = {
.config = config,
.ctx = ctx,
};
if (ini_parse(path, config_handler, &args) < 0) {
config_free(config); config_free(config);
if (errno != ConfigUnknown || errno != ConfigMultiple) { if (errno != ConfigUnknown || errno != ConfigMultiple) {
error_set(_("Failed to parse configuration file")); error_set(_("Failed to parse configuration file"));
@ -184,12 +191,12 @@ bool config_load(config_t *config, char *path) {
void config_print(config_t *config) { void config_print(config_t *config) {
info(_("Configuration details:\n")); info(_("Configuration details:\n"));
printf(COLOR_BOLD " %s " COLOR_RESET "=> %s\n", _("Name"), config->name); printf(FG_BOLD " %s " FG_RESET "=> %s\n", _("Name"), config->name);
if (NULL != config->desc) if (NULL != config->desc)
printf(COLOR_BOLD " %s " COLOR_RESET "=> %s\n", _("Desc"), config->desc); printf(FG_BOLD " %s " FG_RESET "=> %s\n", _("Desc"), config->desc);
printf(COLOR_BOLD " %s " COLOR_RESET "=> %s\n", _("Author"), config->author); printf(FG_BOLD " %s " FG_RESET "=> %s\n", _("Author"), config->author);
printf(COLOR_BOLD " %s " COLOR_RESET "=> ", _("Keywords")); printf(FG_BOLD " %s " FG_RESET "=> ", _("Keywords"));
for (int i = 0; i < config->keywords.s; i++) for (int i = 0; i < config->keywords.s; i++)
printf("%s ", config->keywords.c[i]); printf("%s ", config->keywords.c[i]);
printf("\n\n"); printf("\n\n");

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "ctx.h"
#include "target.h" #include "target.h"
#include "util.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@ -15,6 +16,6 @@ typedef struct config {
clist_t keywords; clist_t keywords;
} config_t; } config_t;
bool config_load(config_t *, char *); bool config_load(ctx_t *ctx, config_t *config, char *path);
void config_free(config_t *); void config_free(config_t *config);
void config_print(config_t *); void config_print(config_t *config);

33
src/ctx.c Normal file
View File

@ -0,0 +1,33 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "ctx.h"
#include "util.h"
bool ctx_init(ctx_t *ctx, char *homedir) {
bzero(ctx, sizeof(ctx_t));
if (NULL == homedir)
return false;
size_t home_len = strlen(homedir);
ctx->dir_path = malloc(home_len + 20);
ctx->tmp_path = malloc(home_len + 25);
ctx->lock_path = malloc(home_len + 25);
ctx->home_path = strdup(homedir);
join(ctx->dir_path, homedir, ".local/share/mc");
join(ctx->lock_path, ctx->dir_path, "lock");
join(ctx->tmp_path, ctx->dir_path, "tmp");
return true;
}
void ctx_free(ctx_t *ctx) {
free(ctx->dir_path);
free(ctx->tmp_path);
free(ctx->lock_path);
free(ctx->home_path);
bzero(ctx, sizeof(ctx_t));
}

12
src/ctx.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <stdbool.h>
typedef struct ctx {
char *home_path;
char *lock_path;
char *tmp_path;
char *dir_path;
} ctx_t;
bool ctx_init(ctx_t *ctx, char *homedir);
void ctx_free(ctx_t *ctx);

View File

@ -1,23 +0,0 @@
#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");
}

View File

@ -1,6 +0,0 @@
#pragma once
#include <stdbool.h>
char *env_mc_root();
bool env_mc_yes();
bool env_mc_debug();

View File

@ -1,4 +0,0 @@
#pragma once
#include <stdbool.h>
bool gen_cmd();

View File

@ -4,14 +4,14 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
lock_st lock() { lock_st lock(char *lock_path) {
if (exists(mc_lock_path)) if (exists(lock_path))
return ALREADY_LOCKED; return ALREADY_LOCKED;
if (creat(mc_lock_path, 0600) == -1) if (creat(lock_path, 0600) == -1)
return LOCK_ERROR; return LOCK_ERROR;
return LOCK_SUCCESS; return LOCK_SUCCESS;
} }
void unlock() { void unlock(char *lock_path) {
unlink(mc_lock_path); unlink(lock_path);
} }

View File

@ -5,5 +5,5 @@ typedef enum lock_state {
LOCK_ERROR = 3, LOCK_ERROR = 3,
} lock_st; } lock_st;
lock_st lock(); lock_st lock(char *lock_path);
void unlock(); void unlock(char *lock_path);

View File

@ -1,5 +1,4 @@
#include "log.h" #include "log.h"
#include "env.h"
#include "intl.h" #include "intl.h"
#include "util.h" #include "util.h"
@ -54,18 +53,18 @@ bool bar(float cur, float max) {
return true; return true;
lastprog = prog; lastprog = prog;
printf("\r" COLOR_BOLD "["); printf("\r" FG_BOLD "[");
for (int i = 0; i < prog; i++) { for (int i = 0; i < prog; i++) {
printf("#"); printf("#");
} }
printf(COLOR_BLUE "#" COLOR_RESET COLOR_BOLD); printf(FG_BLUE "#" FG_RESET FG_BOLD);
for (int i = prog; i < size; i++) { for (int i = prog; i < size; i++) {
printf(" "); printf(" ");
} }
printf("]" COLOR_RESET); printf("]" FG_RESET);
printf(COLOR_BOLD COLOR_BLUE "%s" COLOR_RESET "\r", perc); printf(FG_BOLD FG_BLUE "%s" FG_RESET "\r", perc);
return true; return true;
} }
@ -73,9 +72,9 @@ void info(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(COLOR_BOLD COLOR_BLUE ">>> " COLOR_RESET COLOR_BOLD); printf(FG_BOLD FG_BLUE ">>> " FG_RESET);
vprintf(msg, args); vprintf(msg, args);
printf(COLOR_RESET "\n"); printf(FG_RESET "\n");
va_end(args); va_end(args);
} }
@ -84,9 +83,9 @@ void error(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(COLOR_BOLD COLOR_RED ">>> " COLOR_RESET COLOR_BOLD); printf(FG_BOLD FG_RED ">>> " FG_RESET);
vprintf(msg, args); vprintf(msg, args);
printf(COLOR_RESET "\n"); printf(FG_RESET "\n");
va_end(args); va_end(args);
} }
@ -95,9 +94,9 @@ void details(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(" " COLOR_RESET); printf(" " FG_RESET);
vprintf(msg, args); vprintf(msg, args);
printf(COLOR_RESET "\n"); printf(FG_RESET "\n");
va_end(args); va_end(args);
} }
@ -106,23 +105,9 @@ void success(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(COLOR_BOLD COLOR_GREEN ">>> " COLOR_RESET COLOR_BOLD); printf(FG_BOLD FG_GREEN ">>> " FG_RESET);
vprintf(msg, args); vprintf(msg, args);
printf(COLOR_RESET "\n"); printf(FG_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); va_end(args);
} }
@ -131,17 +116,14 @@ void input(const char *msg, ...) {
va_list args; va_list args;
va_start(args, msg); va_start(args, msg);
printf(COLOR_BOLD COLOR_CYAN ">>> " COLOR_RESET COLOR_BOLD); printf(FG_BOLD FG_CYAN ">>> " FG_RESET);
vprintf(msg, args); vprintf(msg, args);
printf(COLOR_RESET); printf(FG_RESET);
va_end(args); va_end(args);
} }
bool yesno(const char *msg) { bool yesno(const char *msg) {
if (env_mc_yes())
return true;
char *yes[] = {_("y"), _("Y")}; char *yes[] = {_("y"), _("Y")};
char *no[] = {_("n"), _("N")}; char *no[] = {_("n"), _("N")};

View File

@ -1,14 +1,14 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#define COLOR_RED "\x1b[31m" #define FG_RED "\x1b[31m"
#define COLOR_BOLD "\x1b[1m" #define FG_BOLD "\x1b[1m"
#define COLOR_BLUE "\x1b[34m" #define FG_BLUE "\x1b[34m"
#define COLOR_CYAN "\x1b[36m" #define FG_CYAN "\x1b[36m"
#define COLOR_GREEN "\x1b[32m" #define FG_GREEN "\x1b[32m"
#define COLOR_MAGENTA "\x1b[35m" #define FG_MAGENTA "\x1b[35m"
#define COLOR_UNDERLINE "\x1b[4m" #define FG_UNDERLINE "\x1b[4m"
#define COLOR_RESET "\x1b[0m" #define FG_RESET "\x1b[0m"
void bar_init(); void bar_init();
bool bar(float, float); bool bar(float, float);
@ -18,6 +18,5 @@ void info(const char *, ...);
void error(const char *, ...); void error(const char *, ...);
void details(const char *, ...); void details(const char *, ...);
void success(const char *, ...); void success(const char *, ...);
void debug(const char *, ...);
void input(const char *, ...); void input(const char *, ...);
bool yesno(const char *); bool yesno(const char *);

View File

@ -22,6 +22,7 @@
// clang-format on // clang-format on
#include <libmp/util.h>
#include <locale.h> #include <locale.h>
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
@ -30,92 +31,100 @@
#include <string.h> #include <string.h>
#include "args.h" #include "args.h"
#include "gen.h" #include "cmd.h"
#include "ctx.h"
#include "intl.h" #include "intl.h"
#include "lock.h" #include "lock.h"
#include "log.h" #include "log.h"
#include "paths.h" #include "paths.h"
#include "pull.h"
#include "util.h" #include "util.h"
typedef bool (*cmd)(); ctx_t ctx;
struct CmdMap {
char *name;
bool lock;
cmd func;
};
struct CmdMap cmdmap[] = { void handler(int sig){
{.name = "mc-pull", .lock = true, .func = pull_cmd}, unlock(ctx.lock_path);
{.name = "mc-gen", .lock = false, .func = gen_cmd }, printf("\e[?25h\n");
}; if(SIGSEGV == sig)
error(_("Program received a segfault"));
void handler_int(int sig){
unlock();
printf("\e[?25h");
exit(1);
}
void handler_seg(int sig){
unlock();
printf("\e[?25h");
error(_("Program received a segfault"));
exit(1); exit(1);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
signal(SIGINT, handler_int); signal(SIGINT, handler);
signal(SIGSEGV, handler_seg); signal(SIGSEGV, handler);
setbuf(stdout, NULL); setbuf(stdout, NULL);
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
textdomain("mc"); textdomain("confer");
for (int i = 0; i < sizeof(cmdmap) / sizeof(struct CmdMap); i++) { cmd_t commands[] = {
if (strcmp(argv[0], cmdmap[i].name) != 0) {.name = "pull", .lock = true, .desc = _("pull down a configuration"), .func = cmd_pull },
{.name = "gen", .lock = false, .desc = _("build the configuration in the current directory"), .func = cmd_gen },
};
args_t *args = NULL;
char *homedir = NULL;
bool ret = false;
args = args_parse(argc, argv);
if (args->count <= 0 || args->list[0].name != NULL)
goto help;
if((homedir = args_get_string(args, "home")) == NULL)
homedir = getenv("HOME");
if(!ctx_init(&ctx, homedir)){
error(_("Please specify the homedir with "FG_BOLD"--home"FG_RESET" option or specify the "FG_BOLD"HOME"FG_RESET" environment variable"));
goto end;
}
for (int i = 0; i < sizeof(commands) / sizeof(cmd_t); i++) {
if (!eq(commands[i].name, args->list[0].value))
continue; continue;
args_load(argc, argv); if (commands[i].lock) {
switch (lock(ctx.lock_path)) {
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: case ALREADY_LOCKED:
error(_("Failed to lock, mc is already running")); error(_("Failed to lock, confer is already running"));
return EXIT_FAILURE; goto end;
case LOCK_ERROR: case LOCK_ERROR:
error(_("Failed to lock, did you mess up your directory permissions?")); error(_("Failed to lock, are you root?"));
return EXIT_FAILURE; goto end;
default:
break;
} }
} }
bool ret = cmdmap[i].func(); ret = commands[i].func(&ctx, args);
unlock(); goto end;
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); error(_("Command not found: " FG_BOLD "%s"), args->list[0].value);
info(_("Different operations are done using different commands\n")); help:
info(_("MatterLinux configuration manager (version %s)"), VERSION);
info(_("Usage: " FG_BOLD "%s [command] <options> <arguments>"), argv[0]);
printf("\n");
info(_("Here is a list of available commands:"));
printf(COLOR_BOLD " mc-pull" COLOR_RESET ": "); for (int i = 0; i < sizeof(commands) / sizeof(cmd_t); i++)
printf(" %s\n", _("pull down a configuration")); printf(" " FG_BOLD "%s" FG_RESET ":\t %s\n", commands[i].name, commands[i].desc);
printf("\n");
printf(COLOR_BOLD " mc-gen" COLOR_RESET ": "); info(_("Here is a list of available options:"));
printf(" %s\n\n", _("build the configuration in the current directory"));
info(_("Licensed under GPLv3, see <https://www.gnu.org/licenses/> for more " printf(
"information")); _(" " FG_BOLD "--yes" FG_RESET ":\t skip the confirmation\n"));
return EXIT_SUCCESS; printf(_(" " FG_BOLD "--home" FG_RESET ":\t path to your home directory\n\n"));
info(_("Licensed under GPLv3, see https://www.gnu.org/licenses/ for more information"));
ret = true;
end:
unlock(ctx.lock_path);
args_free(args);
ctx_free(&ctx);
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
} }

View File

@ -1,32 +0,0 @@
#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_home;
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;
}

View File

@ -1,11 +0,0 @@
#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;

View File

@ -1,4 +0,0 @@
#pragma once
#include <stdbool.h>
bool pull_cmd();

View File

@ -1,26 +0,0 @@
#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);
}

View File

@ -1 +0,0 @@
char *repo_clone(char *);

View File

@ -56,6 +56,8 @@ bool run_cmd_root(char *cmd, char **args) {
return false; return false;
RUN: RUN:
errno = 0;
int arg_count = 0; int arg_count = 0;
while (args[arg_count] != NULL) while (args[arg_count] != NULL)
arg_count++; arg_count++;

View File

@ -119,7 +119,7 @@ void target_free(target_t *t) {
void target_print(target_t *t) { void target_print(target_t *t) {
info(_("Target details:\n")); info(_("Target details:\n"));
printf(COLOR_BOLD " %s " COLOR_RESET "=> %s\n", _("Name"), t->name); printf(FG_BOLD " %s " FG_RESET "=> %s\n", _("Name"), t->name);
printf(COLOR_BOLD " %s " COLOR_RESET "=> %s\n", _("Description"), t->desc); printf(FG_BOLD " %s " FG_RESET "=> %s\n", _("Description"), t->desc);
printf("\n"); printf("\n");
} }

View File

@ -18,16 +18,6 @@ bool eq(char *s1, char *s2) {
return strcmp(s1, s2) == 0; 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) { bool exists(char *path) {
return access(path, F_OK) == 0; return access(path, F_OK) == 0;
} }

View File

@ -10,7 +10,6 @@ typedef struct clist {
bool eq(char *, char *); bool eq(char *, char *);
bool exists(char *); bool exists(char *);
char *check_path(char *); char *check_path(char *);
bool joinhome(char *, char *);
bool startswith(char *, char *); bool startswith(char *, char *);
bool endswith(const char *, const char *); bool endswith(const char *, const char *);
int join(char *, const char *, const char *); int join(char *, const char *, const char *);