git-fetch: rewrite expand_ref_wildcard in C

This does not seem to make measurable improvement when dealing
with 1000 unpacked refs, but we would need something like it
if we were to do a full rewrite in C somedaoy.

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano 2007-01-16 13:43:28 -08:00
parent d1e0ef6cc8
commit 86551586da
2 changed files with 91 additions and 45 deletions

View file

@ -323,6 +323,91 @@ static int parse_reflist(const char *reflist)
return 0;
}
static int expand_refs_wildcard(const char *ls_remote_result, int numrefs,
const char **refs)
{
int i, matchlen, replacelen;
int found_one = 0;
const char *remote = *refs++;
numrefs--;
if (numrefs == 0) {
fprintf(stderr, "Nothing specified for fetching with remote.%s.fetch\n",
remote);
printf("empty\n");
}
for (i = 0; i < numrefs; i++) {
const char *ref = refs[i];
const char *lref = ref;
const char *colon;
const char *tail;
const char *ls;
const char *next;
if (*lref == '+')
lref++;
colon = strchr(lref, ':');
tail = lref + strlen(lref);
if (!(colon &&
2 < colon - lref &&
colon[-1] == '*' &&
colon[-2] == '/' &&
2 < tail - (colon + 1) &&
tail[-1] == '*' &&
tail[-2] == '/')) {
/* not a glob */
if (!found_one++)
printf("explicit\n");
printf("%s\n", ref);
continue;
}
/* glob */
if (!found_one++)
printf("glob\n");
/* lref to colon-2 is remote hierarchy name;
* colon+1 to tail-2 is local.
*/
matchlen = (colon-1) - lref;
replacelen = (tail-1) - (colon+1);
for (ls = ls_remote_result; ls; ls = next) {
const char *eol;
unsigned char sha1[20];
int namelen;
while (*ls && isspace(*ls))
ls++;
next = strchr(ls, '\n');
eol = !next ? (ls + strlen(ls)) : next;
if (!memcmp("^{}", eol-3, 3))
continue;
if (get_sha1_hex(ls, sha1))
continue;
ls += 40;
while (ls < eol && isspace(*ls))
ls++;
/* ls to next (or eol) is the name.
* is it identical to lref to colon-2?
*/
if ((eol - ls) <= matchlen ||
strncmp(ls, lref, matchlen))
continue;
/* Yes, it is a match */
namelen = eol - ls;
if (lref != ref)
putchar('+');
printf("%.*s:%.*s%.*s\n",
namelen, ls,
replacelen, colon + 1,
namelen - matchlen, ls + matchlen);
}
}
return 0;
}
int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
{
int verbose = 0;
@ -380,6 +465,11 @@ int cmd_fetch__tool(int argc, const char **argv, const char *prefix)
return error("parse-reflist takes 1 arg");
return parse_reflist(argv[2]);
}
if (!strcmp("expand-refs-wildcard", argv[1])) {
if (argc < 4)
return error("expand-refs-wildcard takes at least 2 args");
return expand_refs_wildcard(argv[2], argc - 3, argv + 3);
}
return error("Unknown subcommand: %s", argv[1]);
}

View file

@ -81,51 +81,7 @@ get_remote_default_refs_for_push () {
# is to help prevent randomly "globbed" ref from being chosen as
# a merge candidate
expand_refs_wildcard () {
remote="$1"
shift
first_one=yes
if test "$#" = 0
then
echo empty
echo >&2 "Nothing specified for fetching with remote.$remote.fetch"
fi
for ref
do
lref=${ref#'+'}
# a non glob pattern is given back as-is.
expr "z$lref" : 'zrefs/.*/\*:refs/.*/\*$' >/dev/null || {
if test -n "$first_one"
then
echo "explicit"
first_one=
fi
echo "$ref"
continue
}
# glob
if test -n "$first_one"
then
echo "glob"
first_one=
fi
from=`expr "z$lref" : 'z\(refs/.*/\)\*:refs/.*/\*$'`
to=`expr "z$lref" : 'zrefs/.*/\*:\(refs/.*/\)\*$'`
local_force=
test "z$lref" = "z$ref" || local_force='+'
echo "$ls_remote_result" |
sed -e '/\^{}$/d' |
(
IFS=' '
while read sha1 name
do
# ignore the ones that do not start with $from
mapped=${name#"$from"}
test "z$name" = "z$mapped" && continue
echo "${local_force}${name}:${to}${mapped}"
done
)
done
git fetch--tool expand-refs-wildcard "$ls_remote_result" "$@"
}
# Subroutine to canonicalize remote:local notation.