diff --git a/Makefile b/Makefile index 7a7e5d0..900956c 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,30 @@ -HEADERS = $(wildcard src/*.h) $(wildcard src/*/*.h) -CSRCS = $(wildcard src/*.c) $(wildcard src/*/*.c) -CMDS = mc-pull mc-gen +SRCS = $(wildcard src/*.c) $(wildcard src/*/*.c) +OBJS = $(patsubst src/%.c,dist/%.o,$(SRCS)) +HDRS = $(wildcard src/*.h) PO_SRCS = $(wildcard locale/*/*/*.po) PO_OUTS = $(patsubst locale/%.po,locale/%.mo,$(PO_SRCS)) PO_DIRS = $(wildcard locale/*/*) -VERSION = 24.02 -prefix = /usr +CFLAGS = -O3 -fstack-protector-strong -fcf-protection=full -fstack-clash-protection +LIBS = -linih -lgit2 -lcurl -lcrypto + +VERSION = 24.03 +PREFIX = /usr CC = gcc -all: dist/mc $(PO_OUTS) +all: dist dist/confer $(PO_OUTS) -dist/mc: $(CSRCS) $(HEADERS) - mkdir -p dist - $(CC) $(CFLAGS) $(CSRCS) -o $@ -DVERSION=\"${VERSION}\" -linih -lgit2 -lcurl -lcrypto +dist: + mkdir -pv dist/cmd -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 $@ locale/%.po: locale/mc.pot @@ -29,36 +37,30 @@ locale/%.po: locale/mc.pot mv $@.old $@ ; \ fi; \ -locale/mc.pot: $(CSRCS) +locale/confer.pot: $(SRCS) mkdir -p locale xgettext -k_ -c $^ -o $@ install: - mkdir -pv $(DESTDIR)$(prefix)/bin - install -v -m755 dist/mc $(DESTDIR)$(prefix)/bin/mc - @for cmd in $(CMDS) ; do \ - ln -sfv mc $(DESTDIR)$(prefix)/bin/$$cmd ; \ - done + mkdir -pv $(DESTDIR)/$(PREFIX)/bin + install -v -m755 dist/confer $(DESTDIR)/$(PREFIX)/bin/confer @for po in $(PO_DIRS) ; do \ echo "installing locale: $$po/mc.mo" ; \ - mkdir -pv $(DESTDIR)/usr/share/$$po ; \ - cp $$po/mc.mo $(DESTDIR)/usr/share/$$po ; \ + mkdir -pv $(DESTDIR)/$(PREFIX)/share/$$po ; \ + cp $$po/mc.mo $(DESTDIR)/$(PREFIX)/share/$$po ; \ done uninstall: - rm -v $(DESTDIR)$(prefix)/bin/mc - @for cmd in $(CMDS) ; do \ - unlink $(DESTDIR)$(prefix)/bin/$$cmd ; \ - done + rm -v $(DESTDIR)/$(PREFIX)/bin/confer clean: rm dist/mc rm locale/mc.pot @for po in $(PO_DIRS) ; do \ - rm $$po/mc.mo ; \ + rm $$po/confer.mo ; \ done 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 diff --git a/README.md b/README.md index 4d289d2..39376d4 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# mc | MatterLinux configuration manager -`mc` is a simple tool for managing desktop/window manager configurations, +# confer | MatterLinux configuration manager +`coner` is a simple tool for managing desktop/window manager configurations, it allows you to easily create configurations from your dot files and allows you to easily install them ### 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 - libgit2 - 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 `make` tool: -``` +```bash make ``` After compiling it, you can install the binary, locales and the symbolic links: -``` +```bash make install ``` diff --git a/locale/tr/LC_MESSAGES/confer.po b/locale/tr/LC_MESSAGES/confer.po new file mode 100644 index 0000000..4e633d7 --- /dev/null +++ b/locale/tr/LC_MESSAGES/confer.po @@ -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 , 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 \n" +"Language-Team: LANGUAGE \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" diff --git a/locale/tr/LC_MESSAGES/mc.po b/locale/tr/LC_MESSAGES/mc.po deleted file mode 100644 index b2342a1..0000000 --- a/locale/tr/LC_MESSAGES/mc.po +++ /dev/null @@ -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. -# , 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: \n" -"Language-Team: Turkish \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 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 "" diff --git a/src/args.c b/src/args.c index 4bc4a1c..ad31847 100644 --- a/src/args.c +++ b/src/args.c @@ -1,8 +1,113 @@ +#include +#include +#include +#include + #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.count = argc; - args.list = argv; + args->list[args->count].name = name; + args->list[args->count++].value = NULL; +} + +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; } diff --git a/src/args.h b/src/args.h index 026cc35..44c797d 100644 --- a/src/args.h +++ b/src/args.h @@ -1,9 +1,20 @@ #pragma once +#include +#include -typedef struct Args { - int count; - char **list; +typedef struct arg { + char *name; + char *value; +} arg_t; + +typedef struct args { + arg_t *list; + size_t count; } args_t; -extern args_t args; -void args_load(int, char *[]); +args_t *args_parse(int argc, char *argv[]); +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); diff --git a/src/cmd.h b/src/cmd.h new file mode 100644 index 0000000..72bccb1 --- /dev/null +++ b/src/cmd.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include + +#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); diff --git a/src/gen.c b/src/cmd/gen.c similarity index 54% rename from src/gen.c rename to src/cmd/gen.c index 925a2dd..d14657d 100644 --- a/src/gen.c +++ b/src/cmd/gen.c @@ -1,34 +1,49 @@ -#include "gen.h" -#include "args.h" -#include "config.h" -#include "error.h" -#include "intl.h" -#include "log.h" -#include "util.h" +#include "../args.h" +#include "../cmd.h" +#include "../config.h" +#include "../error.h" +#include "../intl.h" +#include "../log.h" +#include "../util.h" #include -bool gen_cmd() { +bool cmd_gen(ctx_t *ctx, args_t *args) { bool ret = false; + char *dir = NULL; config_t cfg; - if (args.count != 2) { - error(_("Please specify a directory for the repository")); - return ret; + for (size_t i = 0; i < args->count; i++) { + if (NULL != args->list[i].name || eq(args->list[i].value, "gen")) + 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")); return ret; } - if (chdir(args.list[1]) < 0) { + if (chdir(dir) < 0) { error(_("Failed to change directory to the specified directory")); return ret; } 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); return ret; } diff --git a/src/pull.c b/src/cmd/pull.c similarity index 77% rename from src/pull.c rename to src/cmd/pull.c index 283a38e..5a7c27a 100644 --- a/src/pull.c +++ b/src/cmd/pull.c @@ -1,12 +1,11 @@ -#include "pull.h" -#include "args.h" -#include "config.h" -#include "error.h" -#include "log.h" -#include "paths.h" -#include "run.h" -#include "url.h" -#include "util.h" +#include "../args.h" +#include "../cmd.h" +#include "../config.h" +#include "../error.h" +#include "../log.h" +#include "../run.h" +#include "../url.h" +#include "../util.h" #include #include @@ -23,41 +22,54 @@ int pull_progress(const git_indexer_progress *stats, void *data) { return 0; } -bool pull_cmd() { - if (args.count != 2) { +bool cmd_pull(ctx_t *ctx, args_t *args) { + 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")); return false; } - char *repo_url = NULL, *repo_root = NULL; - config_t repo_cfg = {.name = NULL}; - bool ret = false; - - if (url_is_local(args.list[1])) { - repo_root = args.list[1]; + if (url_is_local(url)) { + repo_root = url; goto COPY; } - else if (url_is_name(args.list[1])) - repo_url = url_complete(args.list[1]); + else if (url_is_name(url)) + repo_url = url_complete(url); else - repo_url = url_ensure_protocol(args.list[1]); + repo_url = url_ensure_protocol(url); if (NULL == repo_url) { switch (errno) { case UrlReqBadCode: - error("Specified configuration is not found"); + error(_("Specified configuration is not found")); break; default: - error("Failed to access the URL"); + error(_("Failed to access the URL")); details(errch); } goto END; } - rmrf(mc_tmp_path); - repo_root = mc_tmp_path; + rmrf(ctx->tmp_path); + repo_root = ctx->tmp_path; git_libgit2_init(); @@ -86,7 +98,7 @@ COPY: 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):")); details(errch); goto END; diff --git a/src/config.c b/src/config.c index 3a188c7..41e9825 100644 --- a/src/config.c +++ b/src/config.c @@ -1,14 +1,20 @@ #include +#include #include #include #include "config.h" +#include "ctx.h" #include "error.h" #include "intl.h" #include "log.h" -#include "paths.h" #include "util.h" +struct __config_args { + config_t *config; + ctx_t *ctx; +}; + bool config_contains_target(config_t *config, char *name) { target_t *cur = config->t_last; while (cur) { @@ -70,7 +76,9 @@ int config_handler(void *data, const char *section, const char *key, const char if (strlen(section) == 0) 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")) { 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))) { - debug("adding new target => %s", section); if (config_contains_target(config, (char *)section)) { error_set(_("Configuration contains multiple targets with the same name")); 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); return 1; } 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); - join(config->t_last->dst, mc_root, value); + join(config->t_last->dst, ctx->home_path, value); return 1; } else if (MATCHKEY("src")) { config->t_last->src = strdup(value); @@ -149,22 +156,22 @@ void config_free(config_t *config) { 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)) { error_set(_("Configuration file not found")); errno = ConfigNotFound; return false; } - config->name = NULL; - config->desc = NULL; - config->author = NULL; - config->t_first = NULL; - config->t_last = NULL; - config->t_len = 0; + bzero(config, sizeof(config_t)); 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); if (errno != ConfigUnknown || errno != ConfigMultiple) { 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) { 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) - printf(COLOR_BOLD " %s " COLOR_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", _("Desc"), config->desc); + 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++) printf("%s ", config->keywords.c[i]); printf("\n\n"); diff --git a/src/config.h b/src/config.h index 242e78c..4cc53d9 100644 --- a/src/config.h +++ b/src/config.h @@ -1,6 +1,7 @@ #pragma once +#include "ctx.h" #include "target.h" -#include "util.h" + #include #include @@ -15,6 +16,6 @@ typedef struct config { clist_t keywords; } config_t; -bool config_load(config_t *, char *); -void config_free(config_t *); -void config_print(config_t *); +bool config_load(ctx_t *ctx, config_t *config, char *path); +void config_free(config_t *config); +void config_print(config_t *config); diff --git a/src/ctx.c b/src/ctx.c new file mode 100644 index 0000000..7612877 --- /dev/null +++ b/src/ctx.c @@ -0,0 +1,33 @@ +#include +#include +#include + +#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)); +} diff --git a/src/ctx.h b/src/ctx.h new file mode 100644 index 0000000..6d807c5 --- /dev/null +++ b/src/ctx.h @@ -0,0 +1,12 @@ +#pragma once +#include + +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); diff --git a/src/env.c b/src/env.c deleted file mode 100644 index e8e6bed..0000000 --- a/src/env.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "env.h" -#include -#include -#include -#include - -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"); -} diff --git a/src/env.h b/src/env.h deleted file mode 100644 index 7be9ba2..0000000 --- a/src/env.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include - -char *env_mc_root(); -bool env_mc_yes(); -bool env_mc_debug(); diff --git a/src/gen.h b/src/gen.h deleted file mode 100644 index 592d7b6..0000000 --- a/src/gen.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include - -bool gen_cmd(); diff --git a/src/lock.c b/src/lock.c index 844a05f..f90e8a9 100644 --- a/src/lock.c +++ b/src/lock.c @@ -4,14 +4,14 @@ #include #include -lock_st lock() { - if (exists(mc_lock_path)) +lock_st lock(char *lock_path) { + if (exists(lock_path)) return ALREADY_LOCKED; - if (creat(mc_lock_path, 0600) == -1) + if (creat(lock_path, 0600) == -1) return LOCK_ERROR; return LOCK_SUCCESS; } -void unlock() { - unlink(mc_lock_path); +void unlock(char *lock_path) { + unlink(lock_path); } diff --git a/src/lock.h b/src/lock.h index 496d9ca..826fc4f 100644 --- a/src/lock.h +++ b/src/lock.h @@ -5,5 +5,5 @@ typedef enum lock_state { LOCK_ERROR = 3, } lock_st; -lock_st lock(); -void unlock(); +lock_st lock(char *lock_path); +void unlock(char *lock_path); diff --git a/src/log.c b/src/log.c index f22d8e9..5edac73 100644 --- a/src/log.c +++ b/src/log.c @@ -1,5 +1,4 @@ #include "log.h" -#include "env.h" #include "intl.h" #include "util.h" @@ -54,18 +53,18 @@ bool bar(float cur, float max) { return true; lastprog = prog; - printf("\r" COLOR_BOLD "["); + printf("\r" FG_BOLD "["); for (int i = 0; i < prog; i++) { printf("#"); } - printf(COLOR_BLUE "#" COLOR_RESET COLOR_BOLD); + printf(FG_BLUE "#" FG_RESET FG_BOLD); for (int i = prog; i < size; i++) { 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; } @@ -73,9 +72,9 @@ void info(const char *msg, ...) { va_list args; va_start(args, msg); - printf(COLOR_BOLD COLOR_BLUE ">>> " COLOR_RESET COLOR_BOLD); + printf(FG_BOLD FG_BLUE ">>> " FG_RESET); vprintf(msg, args); - printf(COLOR_RESET "\n"); + printf(FG_RESET "\n"); va_end(args); } @@ -84,9 +83,9 @@ void error(const char *msg, ...) { va_list args; va_start(args, msg); - printf(COLOR_BOLD COLOR_RED ">>> " COLOR_RESET COLOR_BOLD); + printf(FG_BOLD FG_RED ">>> " FG_RESET); vprintf(msg, args); - printf(COLOR_RESET "\n"); + printf(FG_RESET "\n"); va_end(args); } @@ -95,9 +94,9 @@ void details(const char *msg, ...) { va_list args; va_start(args, msg); - printf(" " COLOR_RESET); + printf(" " FG_RESET); vprintf(msg, args); - printf(COLOR_RESET "\n"); + printf(FG_RESET "\n"); va_end(args); } @@ -106,23 +105,9 @@ void success(const char *msg, ...) { va_list args; va_start(args, msg); - printf(COLOR_BOLD COLOR_GREEN ">>> " COLOR_RESET COLOR_BOLD); + printf(FG_BOLD FG_GREEN ">>> " FG_RESET); 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"); + printf(FG_RESET "\n"); va_end(args); } @@ -131,17 +116,14 @@ void input(const char *msg, ...) { va_list args; va_start(args, msg); - printf(COLOR_BOLD COLOR_CYAN ">>> " COLOR_RESET COLOR_BOLD); + printf(FG_BOLD FG_CYAN ">>> " FG_RESET); vprintf(msg, args); - printf(COLOR_RESET); + printf(FG_RESET); va_end(args); } bool yesno(const char *msg) { - if (env_mc_yes()) - return true; - char *yes[] = {_("y"), _("Y")}; char *no[] = {_("n"), _("N")}; diff --git a/src/log.h b/src/log.h index 7fdf0b0..0767334 100644 --- a/src/log.h +++ b/src/log.h @@ -1,14 +1,14 @@ #pragma once #include -#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_UNDERLINE "\x1b[4m" -#define COLOR_RESET "\x1b[0m" +#define FG_RED "\x1b[31m" +#define FG_BOLD "\x1b[1m" +#define FG_BLUE "\x1b[34m" +#define FG_CYAN "\x1b[36m" +#define FG_GREEN "\x1b[32m" +#define FG_MAGENTA "\x1b[35m" +#define FG_UNDERLINE "\x1b[4m" +#define FG_RESET "\x1b[0m" void bar_init(); bool bar(float, float); @@ -18,6 +18,5 @@ 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 *); diff --git a/src/main.c b/src/main.c index e857690..abeb35f 100644 --- a/src/main.c +++ b/src/main.c @@ -22,6 +22,7 @@ // clang-format on +#include #include #include #include @@ -30,92 +31,100 @@ #include #include "args.h" -#include "gen.h" +#include "cmd.h" +#include "ctx.h" #include "intl.h" #include "lock.h" #include "log.h" #include "paths.h" -#include "pull.h" #include "util.h" -typedef bool (*cmd)(); -struct CmdMap { - char *name; - bool lock; - cmd func; -}; +ctx_t ctx; -struct CmdMap cmdmap[] = { - {.name = "mc-pull", .lock = true, .func = pull_cmd}, - {.name = "mc-gen", .lock = false, .func = gen_cmd }, -}; - -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")); +void handler(int sig){ + unlock(ctx.lock_path); + printf("\e[?25h\n"); + if(SIGSEGV == sig) + error(_("Program received a segfault")); exit(1); } int main(int argc, char *argv[]) { - signal(SIGINT, handler_int); - signal(SIGSEGV, handler_seg); + signal(SIGINT, handler); + signal(SIGSEGV, handler); setbuf(stdout, NULL); setlocale(LC_ALL, ""); - textdomain("mc"); + textdomain("confer"); - for (int i = 0; i < sizeof(cmdmap) / sizeof(struct CmdMap); i++) { - if (strcmp(argv[0], cmdmap[i].name) != 0) + cmd_t commands[] = { + {.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; - 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) { + if (commands[i].lock) { + switch (lock(ctx.lock_path)) { case ALREADY_LOCKED: - error(_("Failed to lock, mc is already running")); - return EXIT_FAILURE; + error(_("Failed to lock, confer is already running")); + goto end; + case LOCK_ERROR: - error(_("Failed to lock, did you mess up your directory permissions?")); - return EXIT_FAILURE; + error(_("Failed to lock, are you root?")); + goto end; + + default: + break; } } - 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; + ret = commands[i].func(&ctx, args); + goto end; } - info(_("MatterLinux Configuration Manager (%s)"), VERSION); - info(_("Different operations are done using different commands\n")); + error(_("Command not found: " FG_BOLD "%s"), args->list[0].value); +help: + info(_("MatterLinux configuration manager (version %s)"), VERSION); + info(_("Usage: " FG_BOLD "%s [command] "), argv[0]); + printf("\n"); + info(_("Here is a list of available commands:")); - printf(COLOR_BOLD " mc-pull" COLOR_RESET ": "); - printf(" %s\n", _("pull down a configuration")); + for (int i = 0; i < sizeof(commands) / sizeof(cmd_t); i++) + printf(" " FG_BOLD "%s" FG_RESET ":\t %s\n", commands[i].name, commands[i].desc); + printf("\n"); - printf(COLOR_BOLD " mc-gen" COLOR_RESET ": "); - printf(" %s\n\n", _("build the configuration in the current directory")); + info(_("Here is a list of available options:")); - info(_("Licensed under GPLv3, see for more " - "information")); - return EXIT_SUCCESS; + printf( + _(" " FG_BOLD "--yes" FG_RESET ":\t skip the confirmation\n")); + 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; } diff --git a/src/paths.c b/src/paths.c deleted file mode 100644 index 85a5feb..0000000 --- a/src/paths.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -#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; -} diff --git a/src/paths.h b/src/paths.h deleted file mode 100644 index b94e8f7..0000000 --- a/src/paths.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include -#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; diff --git a/src/pull.h b/src/pull.h deleted file mode 100644 index 611d4cf..0000000 --- a/src/pull.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include - -bool pull_cmd(); diff --git a/src/repo.c b/src/repo.c deleted file mode 100644 index 5f726c0..0000000 --- a/src/repo.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "log.h" -#include "util.h" -#include -#include -#include -#include -#include - -#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); -} diff --git a/src/repo.h b/src/repo.h deleted file mode 100644 index 609a1ef..0000000 --- a/src/repo.h +++ /dev/null @@ -1 +0,0 @@ -char *repo_clone(char *); diff --git a/src/run.c b/src/run.c index 9dd7d4a..d031c01 100644 --- a/src/run.c +++ b/src/run.c @@ -56,6 +56,8 @@ bool run_cmd_root(char *cmd, char **args) { return false; RUN: + errno = 0; + int arg_count = 0; while (args[arg_count] != NULL) arg_count++; diff --git a/src/target.c b/src/target.c index ba8431d..78f3e0e 100644 --- a/src/target.c +++ b/src/target.c @@ -119,7 +119,7 @@ void target_free(target_t *t) { void target_print(target_t *t) { info(_("Target details:\n")); - printf(COLOR_BOLD " %s " COLOR_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", _("Name"), t->name); + printf(FG_BOLD " %s " FG_RESET "=> %s\n", _("Description"), t->desc); printf("\n"); } diff --git a/src/util.c b/src/util.c index ed57ed1..1abad68 100644 --- a/src/util.c +++ b/src/util.c @@ -18,16 +18,6 @@ bool eq(char *s1, char *s2) { 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; } diff --git a/src/util.h b/src/util.h index 66d9963..d1dae1d 100644 --- a/src/util.h +++ b/src/util.h @@ -10,7 +10,6 @@ typedef struct clist { 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 *);