Reimplement read_tree_recursive() using tree_entry_interesting()

read_tree_recursive() uses a very similar function, match_tree_entry, to
tree_entry_interesting() to do its path matching. This patch kills
match_tree_entry() in favor of tree_entry_interesting().

match_tree_entry(), like older version of tree_entry_interesting(), does
not support wildcard matching. New read_tree_recursive() retains this
behavior by forcing all pathspecs literal.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nguyễn Thái Ngọc Duy 2011-03-25 16:34:18 +07:00 committed by Junio C Hamano
parent f2cfc9c81e
commit ffd31f661d

168
tree.c
View File

@ -45,51 +45,69 @@ static int read_one_entry_quick(const unsigned char *sha1, const char *base, int
ADD_CACHE_JUST_APPEND); ADD_CACHE_JUST_APPEND);
} }
static int match_tree_entry(const char *base, int baselen, const char *path, unsigned int mode, const char **paths) static int read_tree_1(struct tree *tree, struct strbuf *base,
int stage, struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{ {
const char *match; struct tree_desc desc;
int pathlen; struct name_entry entry;
unsigned char sha1[20];
int len, retval = 0, oldlen = base->len;
if (!paths) if (parse_tree(tree))
return 1; return -1;
pathlen = strlen(path);
while ((match = *paths++) != NULL) {
int matchlen = strlen(match);
if (baselen >= matchlen) { init_tree_desc(&desc, tree->buffer, tree->size);
/* If it doesn't match, move along... */
if (strncmp(base, match, matchlen))
continue;
/* pathspecs match only at the directory boundaries */
if (!matchlen ||
baselen == matchlen ||
base[matchlen] == '/' ||
match[matchlen - 1] == '/')
return 1;
continue;
}
/* Does the base match? */ while (tree_entry(&desc, &entry)) {
if (strncmp(base, match, baselen)) if (retval != 2) {
continue; retval = tree_entry_interesting(&entry, base, 0, pathspec);
if (retval < 0)
match += baselen; break;
matchlen -= baselen; if (retval == 0)
if (pathlen > matchlen)
continue;
if (matchlen > pathlen) {
if (match[pathlen] != '/')
continue;
if (!S_ISDIR(mode))
continue; continue;
} }
if (strncmp(path, match, pathlen)) switch (fn(entry.sha1, base->buf, base->len,
entry.path, entry.mode, stage, context)) {
case 0:
continue;
case READ_TREE_RECURSIVE:
break;
default:
return -1;
}
if (S_ISDIR(entry.mode))
hashcpy(sha1, entry.sha1);
else if (S_ISGITLINK(entry.mode)) {
struct commit *commit;
commit = lookup_commit(entry.sha1);
if (!commit)
die("Commit %s in submodule path %s%s not found",
sha1_to_hex(entry.sha1),
base->buf, entry.path);
if (parse_commit(commit))
die("Invalid commit %s in submodule path %s%s",
sha1_to_hex(entry.sha1),
base->buf, entry.path);
hashcpy(sha1, commit->tree->object.sha1);
}
else
continue; continue;
return 1; len = tree_entry_len(entry.path, entry.sha1);
strbuf_add(base, entry.path, len);
strbuf_addch(base, '/');
retval = read_tree_1(lookup_tree(sha1),
base, stage, pathspec,
fn, context);
strbuf_setlen(base, oldlen);
if (retval)
return -1;
} }
return 0; return 0;
} }
@ -99,74 +117,18 @@ int read_tree_recursive(struct tree *tree,
int stage, const char **match, int stage, const char **match,
read_tree_fn_t fn, void *context) read_tree_fn_t fn, void *context)
{ {
struct tree_desc desc; struct strbuf sb = STRBUF_INIT;
struct name_entry entry; struct pathspec pathspec;
int i, ret;
if (parse_tree(tree)) init_pathspec(&pathspec, match);
return -1; for (i = 0; i < pathspec.nr; i++)
pathspec.items[i].has_wildcard = 0;
init_tree_desc(&desc, tree->buffer, tree->size); strbuf_add(&sb, base, baselen);
ret = read_tree_1(tree, &sb, stage, &pathspec, fn, context);
while (tree_entry(&desc, &entry)) { strbuf_release(&sb);
if (!match_tree_entry(base, baselen, entry.path, entry.mode, match)) free_pathspec(&pathspec);
continue; return ret;
switch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage, context)) {
case 0:
continue;
case READ_TREE_RECURSIVE:
break;
default:
return -1;
}
if (S_ISDIR(entry.mode)) {
int retval;
char *newbase;
unsigned int pathlen = tree_entry_len(entry.path, entry.sha1);
newbase = xmalloc(baselen + 1 + pathlen);
memcpy(newbase, base, baselen);
memcpy(newbase + baselen, entry.path, pathlen);
newbase[baselen + pathlen] = '/';
retval = read_tree_recursive(lookup_tree(entry.sha1),
newbase,
baselen + pathlen + 1,
stage, match, fn, context);
free(newbase);
if (retval)
return -1;
continue;
} else if (S_ISGITLINK(entry.mode)) {
int retval;
struct strbuf path;
unsigned int entrylen;
struct commit *commit;
entrylen = tree_entry_len(entry.path, entry.sha1);
strbuf_init(&path, baselen + entrylen + 1);
strbuf_add(&path, base, baselen);
strbuf_add(&path, entry.path, entrylen);
strbuf_addch(&path, '/');
commit = lookup_commit(entry.sha1);
if (!commit)
die("Commit %s in submodule path %s not found",
sha1_to_hex(entry.sha1), path.buf);
if (parse_commit(commit))
die("Invalid commit %s in submodule path %s",
sha1_to_hex(entry.sha1), path.buf);
retval = read_tree_recursive(commit->tree,
path.buf, path.len,
stage, match, fn, context);
strbuf_release(&path);
if (retval)
return -1;
continue;
}
}
return 0;
} }
static int cmp_cache_name_compare(const void *a_, const void *b_) static int cmp_cache_name_compare(const void *a_, const void *b_)