builtin / submodule--helper.con commit submodule: rewrite `module_name` shell function in C (0ea306e)
   1#include "builtin.h"
   2#include "cache.h"
   3#include "parse-options.h"
   4#include "quote.h"
   5#include "pathspec.h"
   6#include "dir.h"
   7#include "utf8.h"
   8#include "submodule.h"
   9#include "submodule-config.h"
  10#include "string-list.h"
  11
  12struct module_list {
  13        const struct cache_entry **entries;
  14        int alloc, nr;
  15};
  16#define MODULE_LIST_INIT { NULL, 0, 0 }
  17
  18static int module_list_compute(int argc, const char **argv,
  19                               const char *prefix,
  20                               struct pathspec *pathspec,
  21                               struct module_list *list)
  22{
  23        int i, result = 0;
  24        char *max_prefix, *ps_matched = NULL;
  25        int max_prefix_len;
  26        parse_pathspec(pathspec, 0,
  27                       PATHSPEC_PREFER_FULL |
  28                       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
  29                       prefix, argv);
  30
  31        /* Find common prefix for all pathspec's */
  32        max_prefix = common_prefix(pathspec);
  33        max_prefix_len = max_prefix ? strlen(max_prefix) : 0;
  34
  35        if (pathspec->nr)
  36                ps_matched = xcalloc(pathspec->nr, 1);
  37
  38        if (read_cache() < 0)
  39                die(_("index file corrupt"));
  40
  41        for (i = 0; i < active_nr; i++) {
  42                const struct cache_entry *ce = active_cache[i];
  43
  44                if (!S_ISGITLINK(ce->ce_mode) ||
  45                    !match_pathspec(pathspec, ce->name, ce_namelen(ce),
  46                                    max_prefix_len, ps_matched, 1))
  47                        continue;
  48
  49                ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
  50                list->entries[list->nr++] = ce;
  51                while (i + 1 < active_nr &&
  52                       !strcmp(ce->name, active_cache[i + 1]->name))
  53                        /*
  54                         * Skip entries with the same name in different stages
  55                         * to make sure an entry is returned only once.
  56                         */
  57                        i++;
  58        }
  59        free(max_prefix);
  60
  61        if (ps_matched && report_path_error(ps_matched, pathspec, prefix))
  62                result = -1;
  63
  64        free(ps_matched);
  65
  66        return result;
  67}
  68
  69static int module_list(int argc, const char **argv, const char *prefix)
  70{
  71        int i;
  72        struct pathspec pathspec;
  73        struct module_list list = MODULE_LIST_INIT;
  74
  75        struct option module_list_options[] = {
  76                OPT_STRING(0, "prefix", &prefix,
  77                           N_("path"),
  78                           N_("alternative anchor for relative paths")),
  79                OPT_END()
  80        };
  81
  82        const char *const git_submodule_helper_usage[] = {
  83                N_("git submodule--helper list [--prefix=<path>] [<path>...]"),
  84                NULL
  85        };
  86
  87        argc = parse_options(argc, argv, prefix, module_list_options,
  88                             git_submodule_helper_usage, 0);
  89
  90        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) {
  91                printf("#unmatched\n");
  92                return 1;
  93        }
  94
  95        for (i = 0; i < list.nr; i++) {
  96                const struct cache_entry *ce = list.entries[i];
  97
  98                if (ce_stage(ce))
  99                        printf("%06o %s U\t", ce->ce_mode, sha1_to_hex(null_sha1));
 100                else
 101                        printf("%06o %s %d\t", ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce));
 102
 103                utf8_fprintf(stdout, "%s\n", ce->name);
 104        }
 105        return 0;
 106}
 107
 108static int module_name(int argc, const char **argv, const char *prefix)
 109{
 110        const struct submodule *sub;
 111
 112        if (argc != 2)
 113                usage(_("git submodule--helper name <path>"));
 114
 115        gitmodules_config();
 116        sub = submodule_from_path(null_sha1, argv[1]);
 117
 118        if (!sub)
 119                die(_("no submodule mapping found in .gitmodules for path '%s'"),
 120                    argv[1]);
 121
 122        printf("%s\n", sub->name);
 123
 124        return 0;
 125}
 126
 127struct cmd_struct {
 128        const char *cmd;
 129        int (*fn)(int, const char **, const char *);
 130};
 131
 132static struct cmd_struct commands[] = {
 133        {"list", module_list},
 134        {"name", module_name},
 135};
 136
 137int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
 138{
 139        int i;
 140        if (argc < 2)
 141                die(_("fatal: submodule--helper subcommand must be "
 142                      "called with a subcommand"));
 143
 144        for (i = 0; i < ARRAY_SIZE(commands); i++)
 145                if (!strcmp(argv[1], commands[i].cmd))
 146                        return commands[i].fn(argc - 1, argv + 1, prefix);
 147
 148        die(_("fatal: '%s' is not a valid submodule--helper "
 149              "subcommand"), argv[1]);
 150}