Browse Source
Most of the submodule operations work on a set of submodules. Calculating and using this set is usually done via: module_list "$@" | { while read mode sha1 stage sm_path do # the actual operation done } Currently the function `module_list` is implemented in the git-submodule.sh as a shell script wrapping a perl script. The rewrite is in C, such that it is faster and can later be easily adapted when other functions are rewritten in C. git-submodule.sh, similar to the builtin commands, will navigate to the top-most directory of the repository and keep the subdirectory as a variable. As the helper is called from within the git-submodule.sh script, we are already navigated to the root level, but the path arguments are still relative to the subdirectory we were in when calling git-submodule.sh. That's why there is a `--prefix` option pointing to an alternative path which to anchor relative path arguments. Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
Stefan Beller
9 years ago
committed by
Junio C Hamano
6 changed files with 138 additions and 48 deletions
@ -0,0 +1,128 @@ |
|||||||
|
#include "builtin.h" |
||||||
|
#include "cache.h" |
||||||
|
#include "parse-options.h" |
||||||
|
#include "quote.h" |
||||||
|
#include "pathspec.h" |
||||||
|
#include "dir.h" |
||||||
|
#include "utf8.h" |
||||||
|
|
||||||
|
struct module_list { |
||||||
|
const struct cache_entry **entries; |
||||||
|
int alloc, nr; |
||||||
|
}; |
||||||
|
#define MODULE_LIST_INIT { NULL, 0, 0 } |
||||||
|
|
||||||
|
static int module_list_compute(int argc, const char **argv, |
||||||
|
const char *prefix, |
||||||
|
struct pathspec *pathspec, |
||||||
|
struct module_list *list) |
||||||
|
{ |
||||||
|
int i, result = 0; |
||||||
|
char *max_prefix, *ps_matched = NULL; |
||||||
|
int max_prefix_len; |
||||||
|
parse_pathspec(pathspec, 0, |
||||||
|
PATHSPEC_PREFER_FULL | |
||||||
|
PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, |
||||||
|
prefix, argv); |
||||||
|
|
||||||
|
/* Find common prefix for all pathspec's */ |
||||||
|
max_prefix = common_prefix(pathspec); |
||||||
|
max_prefix_len = max_prefix ? strlen(max_prefix) : 0; |
||||||
|
|
||||||
|
if (pathspec->nr) |
||||||
|
ps_matched = xcalloc(pathspec->nr, 1); |
||||||
|
|
||||||
|
if (read_cache() < 0) |
||||||
|
die(_("index file corrupt")); |
||||||
|
|
||||||
|
for (i = 0; i < active_nr; i++) { |
||||||
|
const struct cache_entry *ce = active_cache[i]; |
||||||
|
|
||||||
|
if (!S_ISGITLINK(ce->ce_mode) || |
||||||
|
!match_pathspec(pathspec, ce->name, ce_namelen(ce), |
||||||
|
max_prefix_len, ps_matched, 1)) |
||||||
|
continue; |
||||||
|
|
||||||
|
ALLOC_GROW(list->entries, list->nr + 1, list->alloc); |
||||||
|
list->entries[list->nr++] = ce; |
||||||
|
while (i + 1 < active_nr && |
||||||
|
!strcmp(ce->name, active_cache[i + 1]->name)) |
||||||
|
/* |
||||||
|
* Skip entries with the same name in different stages |
||||||
|
* to make sure an entry is returned only once. |
||||||
|
*/ |
||||||
|
i++; |
||||||
|
} |
||||||
|
free(max_prefix); |
||||||
|
|
||||||
|
if (ps_matched && report_path_error(ps_matched, pathspec, prefix)) |
||||||
|
result = -1; |
||||||
|
|
||||||
|
free(ps_matched); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
static int module_list(int argc, const char **argv, const char *prefix) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
struct pathspec pathspec; |
||||||
|
struct module_list list = MODULE_LIST_INIT; |
||||||
|
|
||||||
|
struct option module_list_options[] = { |
||||||
|
OPT_STRING(0, "prefix", &prefix, |
||||||
|
N_("path"), |
||||||
|
N_("alternative anchor for relative paths")), |
||||||
|
OPT_END() |
||||||
|
}; |
||||||
|
|
||||||
|
const char *const git_submodule_helper_usage[] = { |
||||||
|
N_("git submodule--helper list [--prefix=<path>] [<path>...]"), |
||||||
|
NULL |
||||||
|
}; |
||||||
|
|
||||||
|
argc = parse_options(argc, argv, prefix, module_list_options, |
||||||
|
git_submodule_helper_usage, 0); |
||||||
|
|
||||||
|
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0) { |
||||||
|
printf("#unmatched\n"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
for (i = 0; i < list.nr; i++) { |
||||||
|
const struct cache_entry *ce = list.entries[i]; |
||||||
|
|
||||||
|
if (ce_stage(ce)) |
||||||
|
printf("%06o %s U\t", ce->ce_mode, sha1_to_hex(null_sha1)); |
||||||
|
else |
||||||
|
printf("%06o %s %d\t", ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce)); |
||||||
|
|
||||||
|
utf8_fprintf(stdout, "%s\n", ce->name); |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
struct cmd_struct { |
||||||
|
const char *cmd; |
||||||
|
int (*fn)(int, const char **, const char *); |
||||||
|
}; |
||||||
|
|
||||||
|
static struct cmd_struct commands[] = { |
||||||
|
{"list", module_list}, |
||||||
|
}; |
||||||
|
|
||||||
|
int cmd_submodule__helper(int argc, const char **argv, const char *prefix) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
if (argc < 2) |
||||||
|
die(_("fatal: submodule--helper subcommand must be " |
||||||
|
"called with a subcommand")); |
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(commands); i++) |
||||||
|
if (!strcmp(argv[1], commands[i].cmd)) |
||||||
|
return commands[i].fn(argc - 1, argv + 1, prefix); |
||||||
|
|
||||||
|
die(_("fatal: '%s' is not a valid submodule--helper " |
||||||
|
"subcommand"), argv[1]); |
||||||
|
} |
Loading…
Reference in new issue