]> git.ipfire.org Git - pakfire.git/commitdiff
cli: pakfire-build: Implement command line option parsing with argp
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 8 Oct 2023 14:39:02 +0000 (14:39 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 8 Oct 2023 14:39:02 +0000 (14:39 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
16 files changed:
src/cli/lib/build.c
src/cli/lib/command.c
src/cli/lib/command.h
src/cli/lib/dist.c
src/cli/lib/image.c
src/cli/lib/image_create.c
src/cli/lib/info.c
src/cli/lib/install.c
src/cli/lib/provides.c
src/cli/lib/remove.c
src/cli/lib/repo.c
src/cli/lib/repo_compose.c
src/cli/lib/requires.c
src/cli/lib/search.c
src/cli/lib/update.c
src/cli/pakfire-builder.c

index 87565703864e0f28e6d4ff5bb45baa891762799d..f1e98f0879ad2847ff5bd499983956f37e83141b 100644 (file)
@@ -186,7 +186,7 @@ int cli_build(struct pakfire* pakfire, int argc, char* argv[]) {
        }
 
        // Process all packages
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                // Run the build
                r = pakfire_build_exec(build, argv[i]);
                if (r) {
index 6fa3f7bf1e59c537c1d3d95159a9e0dc076b0170..81b46a46180c6d422cbdf2adbeae7723e9ff6e0f 100644 (file)
 #############################################################################*/
 
 #include <errno.h>
-#include <getopt.h>
+#include <stdio.h>
 #include <string.h>
 
 #include <pakfire/pakfire.h>
 
 #include "command.h"
 
-// Do not let getopt_long print any error messages
-int opterr = 0;
-
 static const struct command* command_find(const struct command* commands, const char* verb) {
        for (const struct command* command = commands; command->verb; command++) {
                if (strcmp(command->verb, verb) == 0)
@@ -38,15 +35,15 @@ static const struct command* command_find(const struct command* commands, const
        return NULL;
 }
 
-int command_dispatch(struct pakfire* pakfire, const struct command* commands, int argc, char* argv[]) {
+int command_dispatch(struct pakfire* pakfire, const struct command* commands,
+               int arg_index, int argc, char* argv[]) {
        const struct command* command = NULL;
 
-       if (optind >= argc) {
-               fprintf(stderr, "Command required\n");
-               return -EINVAL;
-       }
+       const char* verb = argv[arg_index - 1];
 
-       const char* verb = argv[optind];
+       // Shift
+       argc -= arg_index;
+       argv += arg_index;
 
        // Find a matching command
        command = command_find(commands, verb);
@@ -55,8 +52,5 @@ int command_dispatch(struct pakfire* pakfire, const struct command* commands, in
                return -EINVAL;
        }
 
-       // Reset optind (to parse everything again)
-       optind = 0;
-
        return command->callback(pakfire, argc, argv);
 }
index 1f7046d06e363281ad56fcaed31085095316e2bd..5caa7d0ddd3ca3f105cd0dede015a1e734a2e24c 100644 (file)
@@ -29,6 +29,7 @@ struct command {
        int (*callback)(struct pakfire* pakfire, int argc, char* argv[]);
 };
 
-int command_dispatch(struct pakfire* pakfire, const struct command* commands, int argc, char* argv[]);
+int command_dispatch(struct pakfire* pakfire, const struct command* commands,
+       int arg_index, int argc, char* argv[]);
 
 #endif /* PAKFIRE_CLI_COMMAND_H */
index c78f2a302a2e9646311770bc0e37d48313512da3..e4ade4cfde9b0ef975b695d250d1310b99afdea1 100644 (file)
@@ -90,7 +90,7 @@ int cli_dist(struct pakfire* pakfire, int argc, char* argv[]) {
                config.resultdir = getcwd(cwd, sizeof(cwd));
 
        // Run for all arguments
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                r = pakfire_dist(pakfire, argv[i], config.resultdir, NULL);
                if (r)
                        break;
index cdc44bd9364bd6a9a5dde84f2707f41dda901575..79d050c9b187db54499610831bc067ddafe7e246 100644 (file)
@@ -30,5 +30,5 @@ int cli_image(struct pakfire* pakfire, int argc, char* argv[]) {
                { NULL },
        };
 
-       return command_dispatch(pakfire, commands, argc, argv);
+       return command_dispatch(pakfire, commands, 1, argc, argv);
 }
index 58cc97594202d7dbb55d9a6dce58384509a7e1da..205255bdd30ca78f758c831864859e228b8d94e9 100644 (file)
@@ -77,11 +77,6 @@ int cli_image_create(struct pakfire* pakfire, int argc, char* argv[]) {
 
        // XXX check arguments
 
-       if (optind >= argc) {
-               fprintf(stderr, "Not enough arguments\n");
-               return 1;
-       }
-
        f = fopen(argv[2], "w");
        if (!f) {
                fprintf(stderr, "Could not open %s: %m\n", argv[2]);
index 85079c7a9bb9fbb2d3ead5e328a24933b4c00423..41c183aef875e8c560b2946189cc400bc8a5997b 100644 (file)
@@ -107,7 +107,7 @@ int cli_info(struct pakfire* pakfire, int argc, char* argv[]) {
                goto ERROR;
 
        // Perform search
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                r = pakfire_search(pakfire, argv[i], PAKFIRE_SEARCH_NAME_ONLY, list);
                if (r)
                        goto ERROR;
index b8fc4a8f113119fe506aa1b845c4cc8026946043..e00457125536be95be11af56e8627c4f47ca660b 100644 (file)
@@ -106,7 +106,7 @@ static int __cli_install(struct pakfire_transaction* transaction, int argc, char
        int r;
 
        // Add the remaining command line options as packages
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                r = pakfire_transaction_request(transaction,
                                PAKFIRE_JOB_INSTALL, argv[i], config->job_flags);
                if (r) {
index 9afe350eaeb7174dbf14d11ff1744aaac77ed27e..0552be37fe5e85cb94cf2588ca8c50fe93794e10 100644 (file)
@@ -33,7 +33,7 @@ int cli_provides(struct pakfire* pakfire, int argc, char* argv[]) {
                goto ERROR;
 
        // Perform search
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                r = pakfire_whatprovides(pakfire, argv[i], 0, list);
                if (r)
                        goto ERROR;
index 8d86f8b1ef2f79a6b19168e743149f151df9104b..4b08ca13ff44bea6f5f40235414406e49bea5b77 100644 (file)
@@ -85,7 +85,7 @@ static int __cli_remove(struct pakfire_transaction* transaction, int argc, char*
        int r;
 
        // Add the remaining command line options as packages
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                r = pakfire_transaction_request(transaction,
                                PAKFIRE_JOB_ERASE, argv[i], config->job_flags);
                if (r) {
index b594fa050a202dc4306ea5e5fb2d29a5e362e3b6..6caff547f483a682ed755fe680fdf2a7cbf7626f 100644 (file)
@@ -30,5 +30,5 @@ int cli_repo(struct pakfire* pakfire, int argc, char* argv[]) {
                { NULL },
        };
 
-       return command_dispatch(pakfire, commands, argc, argv);
+       return command_dispatch(pakfire, commands, 1, argc, argv);
 }
index 464920f9af5c3af19ef83d0aa121b30bae18e293..a824c30ba3abc9faa797be95ce7beecec8f1fe92 100644 (file)
@@ -124,11 +124,6 @@ int cli_repo_compose(struct pakfire* pakfire, int argc, char* argv[]) {
 
        // XXX check if we have enough arguments
 
-       if (optind >= argc) {
-               fprintf(stderr, "Not enough arguments\n");
-               return 1;
-       }
-
        // Set path
        config.path = argv[optind++]; argc--;
        config.files = argv + optind;
index 7cd23dedd7dec5d0c0b8713e0ba25d2828da98be..3a1aaf7c27e8b139084144406cdec2048ec83cd1 100644 (file)
@@ -33,7 +33,7 @@ int cli_requires(struct pakfire* pakfire, int argc, char* argv[]) {
                goto ERROR;
 
        // Perform search
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                r = pakfire_whatrequires(pakfire, argv[i], 0, list);
                if (r)
                        goto ERROR;
index 5119ccc80c1677ff24eb51e701ccaadb9d40c881..faf6adb9cfffdafacaa18395d9f123f9c17c739c 100644 (file)
@@ -33,7 +33,7 @@ int cli_search(struct pakfire* pakfire, int argc, char* argv[]) {
                goto ERROR;
 
        // Perform search
-       for (int i = optind + 1; i < argc; i++) {
+       for (int i = 0; i < argc; i++) {
                r = pakfire_search(pakfire, argv[i], 0, list);
                if (r)
                        goto ERROR;
index a3fef339780bb374f7f6bafc1ce008483de3565d..b4a8dbb85038188c153f1d367c70985e2d100b6a 100644 (file)
@@ -114,9 +114,9 @@ static int __cli_update(struct pakfire_transaction* transaction, int argc, char*
        }
 
        // Did the user pass any packages?
-       if (optind < argc) {
+       if (argc) {
                // Add the remaining command line options as packages
-               for (int i = optind + 1; i < argc; i++) {
+               for (int i = 0; i < argc; i++) {
                        r = pakfire_transaction_request(transaction, PAKFIRE_JOB_UPDATE, argv[i], 0);
                        if (r) {
                                fprintf(stderr, "Could not find '%s': %m\n", argv[i]);
index 5888fd60d0665824a6b1616bfea292bf980fa8c9..5e3f8f55ce75e792cf559e2ce420a44c00bff9a1 100644 (file)
@@ -18,8 +18,7 @@
 #                                                                             #
 #############################################################################*/
 
-#include <errno.h>
-#include <getopt.h>
+#include <argp.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -59,117 +58,94 @@ struct config {
        unsigned int num_disable_repos;
 };
 
-static int cli_main(struct pakfire* pakfire, int argc, char* argv[]) {
-       static const struct command commands[] = {
-               { "build",    0, cli_build },
-               { "clean",    0, cli_clean },
-               { "dist",     0, cli_dist },
-               { "image",    0, cli_image },
-               { "info",     0, cli_info },
-               { "provides", 0, cli_provides },
-               { "repo",     0, cli_repo },
-               { "repolist", 0, cli_repolist },
-               { "requires", 0, cli_requires },
-               { "shell",    0, cli_shell },
-               { "search",   0, cli_search },
-               { NULL },
-       };
-
-       return command_dispatch(pakfire, commands, argc, argv);
-}
+const char* argp_program_version = PACKAGE_VERSION;
 
-static void help(void) {
-       printf(
-               "%s [OPTIONS...] COMMAND\n\n"
-               "Options:\n"
-               "  -a --arch          Run in different architecture\n"
-               "     --distro        Selects the distribution to compile for\n"
-               "     --debug         Run in debug mode\n"
-               "  -h --help          Show help\n"
-               "     --version       Show version\n"
-               "\n"
-               "Commands:\n"
-               "  search             Search for packages\n"
-               "  provides           Shows which package provides a dependency\n"
-               "  requires           Shows which package requries a dependency\n"
-               "  repolist           Show all configured repositories\n"
-               "  clean              Cleans up no longer needed resources\n",
-               program_invocation_short_name
-       );
-
-       exit(0);
-}
+enum {
+       OPT_ARCH         = 1,
+       OPT_DEBUG        = 2,
+       OPT_DISTRO       = 3,
 
-static int parse_argv(struct config* config, int argc, char* argv[]) {
-       enum {
-               ARG_DEBUG,
-               ARG_DISTRO,
-               ARG_VERSION,
+       OPT_ENABLE_REPO  = 4,
+       OPT_DISABLE_REPO = 5,
+};
 
-               // Repos
-               ARG_ENABLE_REPO,
-               ARG_DISABLE_REPO,
-       };
+static struct argp_option options[] = {
+       { "arch",   OPT_ARCH,     "ARCH", 0, "Choose an architecture",      0 },
+       { "debug",  OPT_DEBUG,      NULL, 0, "Run in debug mode",           0 },
+       { "distro", OPT_DISTRO, "DISTRO", 0, "Build for this distribution", 0 },
+       { NULL },
+};
 
-       static const struct option options[] = {
-               { "arch",         required_argument, NULL, 'a' },
-               { "debug",        no_argument,       NULL, ARG_DEBUG },
-               { "distro",       required_argument, NULL, ARG_DISTRO },
-               { "help",         no_argument,       NULL, 'h' },
-               { "version",      no_argument,       NULL, ARG_VERSION },
-
-               // Repos
-               { "enable-repo",  required_argument, NULL, ARG_ENABLE_REPO },
-               { "disable-repo", required_argument, NULL, ARG_DISABLE_REPO },
-               { NULL },
-       };
-       int c;
+static const struct command commands[] = {
+       { "build",    0, cli_build },
+       { "clean",    0, cli_clean },
+       { "dist",     0, cli_dist },
+       { "image",    0, cli_image },
+       { "info",     0, cli_info },
+       { "provides", 0, cli_provides },
+       { "repo",     0, cli_repo },
+       { "repolist", 0, cli_repolist },
+       { "requires", 0, cli_requires },
+       { "shell",    0, cli_shell },
+       { "search",   0, cli_search },
+       { NULL },
+};
 
-       for (;;) {
-               c = getopt_long(argc, argv, "ah", options, NULL);
-               if (c < 0)
+const char* doc =
+       "build [OPTIONS...] MAKEFILES...\n"
+       "clean\n"
+       "dist MAKEFILES...\n"
+       "image ...\n"
+       "provides PATTERN\n"
+       "repo compose PATH PACKAGES...\n"
+       "repolist\n"
+       "requires PATTERN\n"
+       "shell [OPTIONS...]\n"
+       "search [OPTIONS...] PATTERN";
+
+static error_t parse(int key, char* arg, struct argp_state* state) {
+       struct config* config = state->input;
+
+       switch (key) {
+               case OPT_ARCH:
+                       // XXX Check if the architecture is supported
+                       config->arch = arg;
                        break;
 
-               switch (c) {
-                       case 'a':
-                               config->arch = optarg;
-                               break;
-
-                       case 'h':
-                               help();
+               case OPT_DEBUG:
+                       config->flags |= PAKFIRE_FLAGS_DEBUG;
+                       break;
 
-                       case ARG_DEBUG:
-                               config->flags |= PAKFIRE_FLAGS_DEBUG;
-                               break;
+               case OPT_DISTRO:
+                       config->distro = arg;
+                       break;
 
-                       case ARG_DISTRO:
-                               config->distro = optarg;
-                               break;
+               // Enable/Disable Repositories
 
-                       case ARG_VERSION:
-                               cli_version();
-                               exit(0);
+               case OPT_ENABLE_REPO:
+                       if (config->num_enable_repos >= MAX_REPOS)
+                               return -ENOBUFS;
 
-                       case ARG_ENABLE_REPO:
-                               if (config->num_enable_repos >= MAX_REPOS)
-                                       return -ENOBUFS;
+                       config->enable_repos[config->num_enable_repos++] = arg;
+                       break;
 
-                               config->enable_repos[config->num_enable_repos++] = optarg;
-                               break;
+               case OPT_DISABLE_REPO:
+                       if (config->num_disable_repos >= MAX_REPOS)
+                               return -ENOBUFS;
 
-                       case ARG_DISABLE_REPO:
-                               if (config->num_disable_repos >= MAX_REPOS)
-                                       return -ENOBUFS;
+                       config->disable_repos[config->num_disable_repos++] = arg;
+                       break;
 
-                               config->disable_repos[config->num_disable_repos++] = optarg;
-                               break;
+               // Show help if no arguments have been passed
+               case ARGP_KEY_NO_ARGS:
+                       argp_usage(state);
 
-                       case '?':
-                               break;
+               // Stop parsing when we find the first argument
+               case ARGP_KEY_ARG:
+                       break;
 
-                       default:
-                               assert_unreachable();
-               }
+               default:
+                       return ARGP_ERR_UNKNOWN;
        }
 
        return 0;
@@ -257,18 +233,24 @@ ERROR:
 }
 
 int main(int argc, char* argv[]) {
-       struct pakfire* pakfire = NULL;
-       int r;
-
        struct config config = {
                // XXX hard-coded distro
                .distro   = "ipfire3",
                .arch     = NULL,
                .flags    = PAKFIRE_FLAGS_BUILD,
        };
+       struct pakfire* pakfire = NULL;
+       int r;
+
+       struct argp parser = {
+               .options   = options,
+               .parser    = parse,
+               .args_doc  = doc,
+       };
+       int arg_index = 0;
 
-       // Parse command line arguments
-       r = parse_argv(&config, argc, argv);
+       // Parse command line options
+       r = argp_parse(&parser, argc, argv, 0, &arg_index, &config);
        if (r)
                goto ERROR;
 
@@ -278,7 +260,7 @@ int main(int argc, char* argv[]) {
                goto ERROR;
 
        // Run a command
-       r = cli_main(pakfire, argc, argv);
+       r = command_dispatch(pakfire, commands, arg_index - 1, argc, argv);
 
 ERROR:
        if (pakfire)