bc79c41b5870868b3618710f316ac24ac1f70fe8
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}