dep

Package manager for embedded C libraries
git clone git://git.finwo.net/app/dep
Log | Files | Refs | README | LICENSE

commit 78a82661a25a170ca566c13d8107431038430d8b
parent 63267da059803b24337e2f890d2cc0be8f627fc1
Author: Yersa Nordman <finwo@pm.me>
Date:   Sat, 12 Sep 2026 22:00:34 +0200

Added versioning

Diffstat:
M.gitignore | 1+
MMakefile | 16+++++++++++++++-
MREADME.md | 26++++++++++++--------------
Msrc/command/help/main.c | 59++++++++++++++++++++---------------------------------------
Asrc/command/version/main.c | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/common/usage.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/common/usage.h | 11+++++++++++
Msrc/main.c | 48++++++++++--------------------------------------
8 files changed, 190 insertions(+), 92 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -2,3 +2,4 @@ *.o /dep /license.c +/.version diff --git a/Makefile b/Makefile @@ -5,6 +5,8 @@ FIND=$(shell which gfind find | head -1) UNAME_S:=$(shell uname -s) UNAME_M:=$(shell uname -m) +VERSION?=0.1.0 + SRC:= INCLUDES:= CFLAGS:= @@ -55,10 +57,14 @@ OBJ:=$(OBJ:.cc=.o) OBJ+=$(LICENSE_OBJ) CFLAGS+=${INCLUDES} +CFLAGS+=-DDEP_VERSION=\"$(VERSION)\" .PHONY: default default: dep +.PHONY: FORCE +FORCE: + license.o: LICENSE.md $(OBJCOPY) --input binary --output $(ARCH_TARGET) --binary-architecture $(ARCH_BIN) $< $@ @@ -107,6 +113,14 @@ lib/tidwall/json.c: .c.o: ${CC} $< ${CFLAGS} -c -o $@ +# Tracks the version we last built with, only rewritten when it actually +# changes, so overriding VERSION on the command line rebuilds what it should +.version: FORCE + @echo '$(VERSION)' | cmp -s - $@ || echo '$(VERSION)' > $@ + +# Bakes in DEP_VERSION, so it must follow changes to VERSION +src/command/version/main.o: .version + dep: $(LIBS) $(OBJ) ${CC} ${OBJ} ${CFLAGS} ${LDFLAGS} -o dep strip -u -r dep 2>/dev/null || true @@ -117,7 +131,7 @@ install: dep .PHONY: clean clean: - rm -f $(OBJ) + rm -f $(OBJ) .version .PHONY: format format: diff --git a/README.md b/README.md @@ -9,25 +9,23 @@ Summary ``` Usage: dep [global options] <command> [command options] + Global options: - n/a + -h, --help Show this help message and exit + -V, --version Show version information and exit Commands: - a(dd) Add a new dependency to the project - i(nstall) Install all the project's dependencies - init Initialize a new project with a .dep file - license Show license information - r(epo(sitory)) Repository management - help [topic] Show this help or the top-level info about a command - -Help topics: - global This help text - add More detailed explanation on the add command - install More detailed explanation on the install command - init More detailed explanation on the init command - repository More detailed explanation on the repository command + v(ersion) Show version information + help [command] Show this help or the top-level info about a command + r(epo(sitory)) Repository management + license Show license information + i(nstall) Install all the project's dependencies + init Initialize a new project with a .dep file + a(dd) Add a new dependency to the project ``` +Run `dep help <command>` for the details on a single command. + Installation ------------ diff --git a/src/command/help/main.c b/src/command/help/main.c @@ -3,66 +3,47 @@ #include <string.h> #include "command/command.h" - -static void print_global_help(void) { - printf("Usage: dep [global options] <command> [command options]\n"); - printf("\n"); - printf("Global options:\n"); - printf(" n/a\n"); - printf("\n"); - printf("Commands:\n"); - - struct cmd_struct *cmd = commands; - while (cmd) { - printf(" %-16s %s\n", cmd->display ? cmd->display : cmd->name[0], cmd->description ? cmd->description : ""); - cmd = cmd->next; - } - - printf("\n"); - printf("Help topics:\n"); - printf(" global This help text\n"); - - cmd = commands; - while (cmd) { - printf(" %-16s More detailed explanation on the %s command\n", cmd->name[0], cmd->name[0]); - cmd = cmd->next; - } -} +#include "common/usage.h" static int cmd_help(int argc, const char **argv) { if (argc < 1) { - print_global_help(); + dep_print_global_usage(); return 0; } if (argc == 1 && (!strcmp(argv[0], "help") || !strcmp(argv[0], "h") || !strcmp(argv[0], "global"))) { - print_global_help(); + dep_print_global_usage(); return 0; } const char *topic = (argc > 1) ? argv[1] : argv[0]; if (!strcmp(topic, "global")) { - print_global_help(); + dep_print_global_usage(); return 0; } struct cmd_struct *cmd = commands; while (cmd) { - if (!strcmp(topic, cmd->name[0])) { - if (cmd->help_text) { - printf("%s\n", cmd->help_text); - } else { - printf("dep %s - %s\n\n", cmd->name[0], cmd->description); - printf(" %s\n", cmd->display); + // Aliases resolve to the same help as the command itself + const char **name = cmd->name; + while (*name) { + if (!strcmp(topic, *name)) { + if (cmd->help_text) { + printf("%s\n", cmd->help_text); + } else { + printf("dep %s - %s\n\n", cmd->name[0], cmd->description); + printf(" %s\n", cmd->display); + } + return 0; } - return 0; + name++; } cmd = cmd->next; } - fprintf(stderr, "Error: unknown help topic '%s'\n", topic); - fprintf(stderr, "Run 'dep help' for available topics.\n"); + fprintf(stderr, "Error: no help available for '%s'\n", topic); + fprintf(stderr, "Run 'dep help' for the available commands.\n"); return 1; } @@ -76,7 +57,7 @@ void __attribute__((constructor)) cmd_help_setup(void) { cmd->fn = cmd_help; static const char *help_names[] = {"help", "h", NULL}; cmd->name = help_names; - cmd->display = "help [topic]"; + cmd->display = "help [command]"; cmd->description = "Show this help or the top-level info about a command"; cmd->help_text = "dep help - Show this help or the top-level info about a command\n" @@ -91,6 +72,6 @@ void __attribute__((constructor)) cmd_help_setup(void) { "Examples:\n" " dep help # Show general help\n" " dep help add # Show help for add command\n" - " dep help install # Show help for install command\n"; + " dep help install # Show help for install command\n"; commands = cmd; } diff --git a/src/command/version/main.c b/src/command/version/main.c @@ -0,0 +1,43 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "command/command.h" + +static int cmd_version(int argc, const char **argv) { + (void)argc; + (void)argv; + printf("%s\n", DEP_VERSION); + return 0; +} + +void __attribute__((constructor)) cmd_version_setup(void) { + struct cmd_struct *cmd = calloc(1, sizeof(struct cmd_struct)); + if (!cmd) { + fprintf(stderr, "Failed to allocate memory for version command\n"); + return; + } + cmd->next = commands; + cmd->fn = cmd_version; + static const char *version_names[] = {"version", "v", NULL}; + cmd->name = version_names; + cmd->display = "v(ersion)"; + cmd->description = "Show version information"; + cmd->help_text = + "dep version - Show version information\n" + "\n" + "Usage:\n" + " dep version\n" + " dep v\n" + "\n" + "Description:\n" + " Print the version of dep and exit.\n" + "\n" + " The global --version flag is dispatched to this command, so both\n" + " produce the exact same output.\n" + "\n" + "Examples:\n" + " dep version # Show the version\n" + " dep --version # Same, as a global flag\n" + " dep -V # Same, short form\n"; + commands = cmd; +} diff --git a/src/common/usage.c b/src/common/usage.c @@ -0,0 +1,78 @@ +#include "usage.h" + +#include <stdio.h> +#include <stdlib.h> + +#include "cofyc/argparse.h" +#include "command/command.h" + +static int opt_version = 0; + +static const char *const usages[] = { + "dep [global options] <command> [command options]", + NULL, +}; + +static struct argparse_option options[] = { + OPT_GROUP("Global options:"), + OPT_BOOLEAN('h', "help", NULL, "Show this help message and exit", argparse_help_cb, 0, OPT_NONEG), + OPT_BOOLEAN('V', "version", &opt_version, "Show version information and exit", NULL, 0, OPT_NONEG), + OPT_END(), +}; + +// argparse prints the epilog at the end of its usage output, which is the only +// way to get our command listing into the built-in --help handler +static char *build_epilog(void) { + char *buffer = NULL; + size_t size = 0; + FILE *out = open_memstream(&buffer, &size); + if (!out) { + return NULL; + } + + struct cmd_struct *cmd = commands; + + // The %-17s aligns our descriptions with the ones argparse prints + fprintf(out, "\nCommands:\n"); + while (cmd) { + fprintf(out, " %-17s %s\n", cmd->display ? cmd->display : cmd->name[0], + cmd->description ? cmd->description : ""); + cmd = cmd->next; + } + + fclose(out); + + // argparse adds a newline of its own + if (size && buffer[size - 1] == '\n') { + buffer[size - 1] = '\0'; + } + + return buffer; +} + +int dep_global_options(int argc, const char **argv, int *show_version) { + struct argparse argparse; + char *epilog = build_epilog(); + + opt_version = 0; + argparse_init(&argparse, options, usages, ARGPARSE_STOP_AT_NON_OPTION); + argparse_describe(&argparse, NULL, epilog); + argc = argparse_parse(&argparse, argc, argv); + free(epilog); + + if (show_version) { + *show_version = opt_version; + } + + return argc; +} + +void dep_print_global_usage(void) { + struct argparse argparse; + char *epilog = build_epilog(); + + argparse_init(&argparse, options, usages, ARGPARSE_STOP_AT_NON_OPTION); + argparse_describe(&argparse, NULL, epilog); + argparse_usage(&argparse); + free(epilog); +} diff --git a/src/common/usage.h b/src/common/usage.h @@ -0,0 +1,11 @@ +#ifndef USAGE_H +#define USAGE_H + +// Parse the global options, returns the remaining argument count +// Sets show_version when --version was given, handles --help by itself +int dep_global_options(int argc, const char **argv, int *show_version); + +// Print the global usage: options, commands and help topics +void dep_print_global_usage(void); + +#endif // USAGE_H diff --git a/src/main.c b/src/main.c @@ -2,55 +2,27 @@ #include <stdlib.h> #include <string.h> -#include "cofyc/argparse.h" #include "command/command.h" +#include "common/usage.h" #include "erkkah/naett.h" #include "rxi/microtar.h" -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - struct cmd_struct *commands = NULL; -static void print_global_usage(void) { - printf("Usage: dep [global options] <command> [command options]\n"); - printf("\n"); - printf("Global options:\n"); - printf(" n/a\n"); - printf("\n"); - printf("Commands:\n"); - - struct cmd_struct *cmd = commands; - while (cmd) { - printf(" %-16s %s\n", cmd->display ? cmd->display : cmd->name[0], cmd->description ? cmd->description : ""); - cmd = cmd->next; - } +int main(int argc, const char **argv) { + int show_version = 0; - printf("\n"); - printf("Help topics:\n"); - printf(" global This help text\n"); + argc = dep_global_options(argc, argv, &show_version); - cmd = commands; - while (cmd) { - printf(" %-16s More detailed explanation on the %s command\n", cmd->name[0], cmd->name[0]); - cmd = cmd->next; + /* --version is nothing but another way of calling the version command */ + if (show_version) { + static const char *version_argv[] = {"version", NULL}; + argv = version_argv; + argc = 1; } -} - -static const char *const usages[] = { - "dep [global options] <command> [command options]", - NULL, -}; -int main(int argc, const char **argv) { - struct argparse argparse; - struct argparse_option options[] = { - OPT_HELP(), - OPT_END(), - }; - argparse_init(&argparse, options, usages, ARGPARSE_STOP_AT_NON_OPTION); - argc = argparse_parse(&argparse, argc, argv); if (argc < 1) { - print_global_usage(); + dep_print_global_usage(); return 0; }