Merge branch 'nd/struct-pathspec'

* nd/struct-pathspec:
  pathspec: rename per-item field has_wildcard to use_wildcard
  Improve tree_entry_interesting() handling code
  Convert read_tree{,_recursive} to support struct pathspec
  Reimplement read_tree_recursive() using tree_entry_interesting()
maint
Junio C Hamano 2011-05-06 10:50:06 -07:00
commit 1273738f05
15 changed files with 148 additions and 169 deletions

View File

@ -157,6 +157,7 @@ int write_archive_entries(struct archiver_args *args,
struct archiver_context context; struct archiver_context context;
struct unpack_trees_options opts; struct unpack_trees_options opts;
struct tree_desc t; struct tree_desc t;
struct pathspec pathspec;
int err; int err;


if (args->baselen > 0 && args->base[args->baselen - 1] == '/') { if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
@ -191,8 +192,10 @@ int write_archive_entries(struct archiver_args *args,
git_attr_set_direction(GIT_ATTR_INDEX, &the_index); git_attr_set_direction(GIT_ATTR_INDEX, &the_index);
} }


err = read_tree_recursive(args->tree, "", 0, 0, args->pathspec, init_pathspec(&pathspec, args->pathspec);
err = read_tree_recursive(args->tree, "", 0, 0, &pathspec,
write_archive_entry, &context); write_archive_entry, &context);
free_pathspec(&pathspec);
if (err == READ_TREE_RECURSIVE) if (err == READ_TREE_RECURSIVE)
err = 0; err = 0;
return err; return err;
@ -221,11 +224,14 @@ static int reject_entry(const unsigned char *sha1, const char *base,


static int path_exists(struct tree *tree, const char *path) static int path_exists(struct tree *tree, const char *path)
{ {
const char *pathspec[] = { path, NULL }; const char *paths[] = { path, NULL };
struct pathspec pathspec;
int ret;


if (read_tree_recursive(tree, "", 0, 0, pathspec, reject_entry, NULL)) init_pathspec(&pathspec, paths);
return 1; ret = read_tree_recursive(tree, "", 0, 0, &pathspec, reject_entry, NULL);
return 0; free_pathspec(&pathspec);
return ret != 0;
} }


static void parse_pathspec_arg(const char **pathspec, static void parse_pathspec_arg(const char **pathspec,

View File

@ -79,7 +79,10 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,


static int read_tree_some(struct tree *tree, const char **pathspec) static int read_tree_some(struct tree *tree, const char **pathspec)
{ {
read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL); struct pathspec ps;
init_pathspec(&ps, pathspec);
read_tree_recursive(tree, "", 0, 0, &ps, update_some, NULL);
free_pathspec(&ps);


/* update the index with the given tree's info /* update the index with the given tree's info
* for all args, expanding wildcards, and exit * for all args, expanding wildcards, and exit

View File

@ -533,18 +533,18 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec, static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
struct tree_desc *tree, struct strbuf *base, int tn_len) struct tree_desc *tree, struct strbuf *base, int tn_len)
{ {
int hit = 0, matched = 0; int hit = 0, match = 0;
struct name_entry entry; struct name_entry entry;
int old_baselen = base->len; int old_baselen = base->len;


while (tree_entry(tree, &entry)) { while (tree_entry(tree, &entry)) {
int te_len = tree_entry_len(entry.path, entry.sha1); int te_len = tree_entry_len(entry.path, entry.sha1);


if (matched != 2) { if (match != 2) {
matched = tree_entry_interesting(&entry, base, tn_len, pathspec); match = tree_entry_interesting(&entry, base, tn_len, pathspec);
if (matched == -1) if (match < 0)
break; /* no more matches */ break;
if (!matched) if (match == 0)
continue; continue;
} }



View File

@ -414,6 +414,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
struct rev_info rev; struct rev_info rev;
struct object_array_entry *objects; struct object_array_entry *objects;
struct setup_revision_opt opt; struct setup_revision_opt opt;
struct pathspec match_all;
int i, count, ret = 0; int i, count, ret = 0;


git_config(git_log_config, NULL); git_config(git_log_config, NULL);
@ -421,6 +422,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
if (diff_use_color_default == -1) if (diff_use_color_default == -1)
diff_use_color_default = git_use_color_default; diff_use_color_default = git_use_color_default;


init_pathspec(&match_all, NULL);
init_revisions(&rev, prefix); init_revisions(&rev, prefix);
rev.diff = 1; rev.diff = 1;
rev.always_show_header = 1; rev.always_show_header = 1;
@ -467,7 +469,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT), diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
name, name,
diff_get_color_opt(&rev.diffopt, DIFF_RESET)); diff_get_color_opt(&rev.diffopt, DIFF_RESET));
read_tree_recursive((struct tree *)o, "", 0, 0, NULL, read_tree_recursive((struct tree *)o, "", 0, 0, &match_all,
show_tree_object, NULL); show_tree_object, NULL);
rev.shown_one = 1; rev.shown_one = 1;
break; break;

View File

@ -338,7 +338,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
{ {
struct tree *tree; struct tree *tree;
unsigned char sha1[20]; unsigned char sha1[20];
const char **match; struct pathspec pathspec;
struct cache_entry *last_stage0 = NULL; struct cache_entry *last_stage0 = NULL;
int i; int i;


@ -360,10 +360,11 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix)
static const char *(matchbuf[2]); static const char *(matchbuf[2]);
matchbuf[0] = prefix; matchbuf[0] = prefix;
matchbuf[1] = NULL; matchbuf[1] = NULL;
match = matchbuf; init_pathspec(&pathspec, matchbuf);
pathspec.items[0].use_wildcard = 0;
} else } else
match = NULL; init_pathspec(&pathspec, NULL);
if (read_tree(tree, 1, match)) if (read_tree(tree, 1, &pathspec))
die("unable to read tree entries %s", tree_name); die("unable to read tree entries %s", tree_name);


for (i = 0; i < active_nr; i++) { for (i = 0; i < active_nr; i++) {

View File

@ -19,7 +19,7 @@ static int line_termination = '\n';
#define LS_SHOW_SIZE 16 #define LS_SHOW_SIZE 16
static int abbrev; static int abbrev;
static int ls_options; static int ls_options;
static const char **pathspec; static struct pathspec pathspec;
static int chomp_prefix; static int chomp_prefix;
static const char *ls_tree_prefix; static const char *ls_tree_prefix;


@ -35,7 +35,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
if (ls_options & LS_RECURSIVE) if (ls_options & LS_RECURSIVE)
return 1; return 1;


s = pathspec; s = pathspec.raw;
if (!s) if (!s)
return 0; return 0;


@ -120,7 +120,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
{ {
unsigned char sha1[20]; unsigned char sha1[20];
struct tree *tree; struct tree *tree;
int full_tree = 0; int i, full_tree = 0;
const struct option ls_tree_options[] = { const struct option ls_tree_options[] = {
OPT_BIT('d', NULL, &ls_options, "only show trees", OPT_BIT('d', NULL, &ls_options, "only show trees",
LS_TREE_ONLY), LS_TREE_ONLY),
@ -166,11 +166,14 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
if (get_sha1(argv[0], sha1)) if (get_sha1(argv[0], sha1))
die("Not a valid object name %s", argv[0]); die("Not a valid object name %s", argv[0]);


pathspec = get_pathspec(prefix, argv + 1); init_pathspec(&pathspec, get_pathspec(prefix, argv + 1));
for (i = 0; i < pathspec.nr; i++)
pathspec.items[i].use_wildcard = 0;
pathspec.has_wildcard = 0;
tree = parse_tree_indirect(sha1); tree = parse_tree_indirect(sha1);
if (!tree) if (!tree)
die("not a tree object"); die("not a tree object");
read_tree_recursive(tree, "", 0, 0, pathspec, show_tree, NULL); read_tree_recursive(tree, "", 0, 0, &pathspec, show_tree, NULL);


return 0; return 0;
} }

View File

@ -511,7 +511,7 @@ struct pathspec {
struct pathspec_item { struct pathspec_item {
const char *match; const char *match;
int len; int len;
unsigned int has_wildcard:1; unsigned int use_wildcard:1;
} *items; } *items;
}; };



6
dir.c
View File

@ -230,7 +230,7 @@ static int match_pathspec_item(const struct pathspec_item *item, int prefix,
return MATCHED_RECURSIVELY; return MATCHED_RECURSIVELY;
} }


if (item->has_wildcard && !fnmatch(match, name, 0)) if (item->use_wildcard && !fnmatch(match, name, 0))
return MATCHED_FNMATCH; return MATCHED_FNMATCH;


return 0; return 0;
@ -1274,8 +1274,8 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)


item->match = path; item->match = path;
item->len = strlen(path); item->len = strlen(path);
item->has_wildcard = !no_wildcard(path); item->use_wildcard = !no_wildcard(path);
if (item->has_wildcard) if (item->use_wildcard)
pathspec->has_wildcard = 1; pathspec->has_wildcard = 1;
} }



View File

@ -68,7 +68,7 @@ static void process_tree(struct rev_info *revs,
struct tree_desc desc; struct tree_desc desc;
struct name_entry entry; struct name_entry entry;
struct name_path me; struct name_path me;
int all_interesting = (revs->diffopt.pathspec.nr == 0); int match = revs->diffopt.pathspec.nr == 0 ? 2 : 0;
int baselen = base->len; int baselen = base->len;


if (!revs->tree_objects) if (!revs->tree_objects)
@ -85,7 +85,7 @@ static void process_tree(struct rev_info *revs,
me.elem = name; me.elem = name;
me.elem_len = strlen(name); me.elem_len = strlen(name);


if (!all_interesting) { if (!match) {
strbuf_addstr(base, name); strbuf_addstr(base, name);
if (base->len) if (base->len)
strbuf_addch(base, '/'); strbuf_addch(base, '/');
@ -94,17 +94,13 @@ static void process_tree(struct rev_info *revs,
init_tree_desc(&desc, tree->buffer, tree->size); init_tree_desc(&desc, tree->buffer, tree->size);


while (tree_entry(&desc, &entry)) { while (tree_entry(&desc, &entry)) {
if (!all_interesting) { if (match != 2) {
int showit = tree_entry_interesting(&entry, match = tree_entry_interesting(&entry, base, 0,
base, 0,
&revs->diffopt.pathspec); &revs->diffopt.pathspec);

if (match < 0)
if (showit < 0)
break; break;
else if (!showit) if (match == 0)
continue; continue;
else if (showit == 2)
all_interesting = 1;
} }


if (S_ISDIR(entry.mode)) if (S_ISDIR(entry.mode))

View File

@ -273,7 +273,9 @@ static int save_files_dirs(const unsigned char *sha1,
static int get_files_dirs(struct merge_options *o, struct tree *tree) static int get_files_dirs(struct merge_options *o, struct tree *tree)
{ {
int n; int n;
if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs, o)) struct pathspec match_all;
init_pathspec(&match_all, NULL);
if (read_tree_recursive(tree, "", 0, 0, &match_all, save_files_dirs, o))
return 0; return 0;
n = o->current_file_set.nr + o->current_directory_set.nr; n = o->current_file_set.nr + o->current_directory_set.nr;
return n; return n;

22
t/t3102-ls-tree-wildcards.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh

test_description='ls-tree with(out) wildcards'

. ./test-lib.sh

test_expect_success 'setup' '
mkdir a aa "a*" &&
touch a/one aa/two "a*/three" &&
git add a/one aa/two "a*/three" &&
git commit -m test
'

test_expect_success 'ls-tree a* matches literally' '
cat >expected <<EOF &&
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a*/three
EOF
git ls-tree -r HEAD "a*" >actual &&
test_cmp expected actual
'

test_done

View File

@ -64,23 +64,17 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
static void show_tree(struct diff_options *opt, const char *prefix, static void show_tree(struct diff_options *opt, const char *prefix,
struct tree_desc *desc, struct strbuf *base) struct tree_desc *desc, struct strbuf *base)
{ {
int all_interesting = 0; int match = 0;
while (desc->size) { for (; desc->size; update_tree_entry(desc)) {
int show; if (match != 2) {

match = tree_entry_interesting(&desc->entry, base, 0,
if (all_interesting)
show = 1;
else {
show = tree_entry_interesting(&desc->entry, base, 0,
&opt->pathspec); &opt->pathspec);
if (show == 2) if (match < 0)
all_interesting = 1;
}
if (show < 0)
break; break;
if (show) if (match == 0)
continue;
}
show_entry(opt, prefix, desc, base); show_entry(opt, prefix, desc, base);
update_tree_entry(desc);
} }
} }


@ -120,20 +114,16 @@ static void show_entry(struct diff_options *opt, const char *prefix,
} }


static void skip_uninteresting(struct tree_desc *t, struct strbuf *base, static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
struct diff_options *opt, int *all_interesting) struct diff_options *opt, int *match)
{ {
while (t->size) { while (t->size) {
int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec); *match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
if (show == 2) if (*match) {
*all_interesting = 1; if (*match < 0)
if (!show) {
update_tree_entry(t);
continue;
}
/* Skip it all? */
if (show < 0)
t->size = 0; t->size = 0;
return; break;
}
update_tree_entry(t);
} }
} }


@ -142,8 +132,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
{ {
struct strbuf base; struct strbuf base;
int baselen = strlen(base_str); int baselen = strlen(base_str);
int all_t1_interesting = 0; int t1_match = 0, t2_match = 0;
int all_t2_interesting = 0;


/* Enable recursion indefinitely */ /* Enable recursion indefinitely */
opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE); opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
@ -157,10 +146,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
DIFF_OPT_TST(opt, HAS_CHANGES)) DIFF_OPT_TST(opt, HAS_CHANGES))
break; break;
if (opt->pathspec.nr) { if (opt->pathspec.nr) {
if (!all_t1_interesting) skip_uninteresting(t1, &base, opt, &t1_match);
skip_uninteresting(t1, &base, opt, &all_t1_interesting); skip_uninteresting(t2, &base, opt, &t2_match);
if (!all_t2_interesting)
skip_uninteresting(t2, &base, opt, &all_t2_interesting);
} }
if (!t1->size) { if (!t1->size) {
if (!t2->size) if (!t2->size)

View File

@ -598,7 +598,7 @@ int tree_entry_interesting(const struct name_entry *entry,
&never_interesting)) &never_interesting))
return 1; return 1;


if (ps->items[i].has_wildcard) { if (ps->items[i].use_wildcard) {
if (!fnmatch(match + baselen, entry->path, 0)) if (!fnmatch(match + baselen, entry->path, 0))
return 1; return 1;


@ -614,7 +614,7 @@ int tree_entry_interesting(const struct name_entry *entry,
} }


match_wildcards: match_wildcards:
if (!ps->items[i].has_wildcard) if (!ps->items[i].use_wildcard)
continue; continue;


/* /*

139
tree.c
View File

@ -45,62 +45,14 @@ 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,
const char *match;
int pathlen;

if (!paths)
return 1;
pathlen = strlen(path);
while ((match = *paths++) != NULL) {
int matchlen = strlen(match);

if (baselen >= matchlen) {
/* 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? */
if (strncmp(base, match, baselen))
continue;

match += baselen;
matchlen -= baselen;

if (pathlen > matchlen)
continue;

if (matchlen > pathlen) {
if (match[pathlen] != '/')
continue;
if (!S_ISDIR(mode))
continue;
}

if (strncmp(path, match, pathlen))
continue;

return 1;
}
return 0;
}

int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
int stage, const char **match,
read_tree_fn_t fn, void *context) read_tree_fn_t fn, void *context)
{ {
struct tree_desc desc; struct tree_desc desc;
struct name_entry entry; struct name_entry entry;
unsigned char sha1[20];
int len, retval = 0, oldlen = base->len;


if (parse_tree(tree)) if (parse_tree(tree))
return -1; return -1;
@ -108,10 +60,16 @@ int read_tree_recursive(struct tree *tree,
init_tree_desc(&desc, tree->buffer, tree->size); init_tree_desc(&desc, tree->buffer, tree->size);


while (tree_entry(&desc, &entry)) { while (tree_entry(&desc, &entry)) {
if (!match_tree_entry(base, baselen, entry.path, entry.mode, match)) if (retval != 2) {
retval = tree_entry_interesting(&entry, base, 0, pathspec);
if (retval < 0)
break;
if (retval == 0)
continue; continue;
}


switch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage, context)) { switch (fn(entry.sha1, base->buf, base->len,
entry.path, entry.mode, stage, context)) {
case 0: case 0:
continue; continue;
case READ_TREE_RECURSIVE: case READ_TREE_RECURSIVE:
@ -119,56 +77,55 @@ int read_tree_recursive(struct tree *tree,
default: default:
return -1; 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); if (S_ISDIR(entry.mode))
memcpy(newbase, base, baselen); hashcpy(sha1, entry.sha1);
memcpy(newbase + baselen, entry.path, pathlen); else if (S_ISGITLINK(entry.mode)) {
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; 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); commit = lookup_commit(entry.sha1);
if (!commit) if (!commit)
die("Commit %s in submodule path %s not found", die("Commit %s in submodule path %s%s not found",
sha1_to_hex(entry.sha1), path.buf); sha1_to_hex(entry.sha1),
base->buf, entry.path);


if (parse_commit(commit)) if (parse_commit(commit))
die("Invalid commit %s in submodule path %s", die("Invalid commit %s in submodule path %s%s",
sha1_to_hex(entry.sha1), path.buf); sha1_to_hex(entry.sha1),
base->buf, entry.path);


retval = read_tree_recursive(commit->tree, hashcpy(sha1, commit->tree->object.sha1);
path.buf, path.len, }
stage, match, fn, context); else
strbuf_release(&path); continue;

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) if (retval)
return -1; return -1;
continue;
}
} }
return 0; return 0;
} }


int read_tree_recursive(struct tree *tree,
const char *base, int baselen,
int stage, struct pathspec *pathspec,
read_tree_fn_t fn, void *context)
{
struct strbuf sb = STRBUF_INIT;
int ret;

strbuf_add(&sb, base, baselen);
ret = read_tree_1(tree, &sb, stage, pathspec, fn, context);
strbuf_release(&sb);
return ret;
}

static int cmp_cache_name_compare(const void *a_, const void *b_) static int cmp_cache_name_compare(const void *a_, const void *b_)
{ {
const struct cache_entry *ce1, *ce2; const struct cache_entry *ce1, *ce2;
@ -179,7 +136,7 @@ static int cmp_cache_name_compare(const void *a_, const void *b_)
ce2->name, ce2->ce_flags); ce2->name, ce2->ce_flags);
} }


int read_tree(struct tree *tree, int stage, const char **match) int read_tree(struct tree *tree, int stage, struct pathspec *match)
{ {
read_tree_fn_t fn = NULL; read_tree_fn_t fn = NULL;
int i, err; int i, err;

4
tree.h
View File

@ -25,9 +25,9 @@ typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const ch


extern int read_tree_recursive(struct tree *tree, extern int read_tree_recursive(struct tree *tree,
const char *base, int baselen, const char *base, int baselen,
int stage, const char **match, int stage, struct pathspec *pathspec,
read_tree_fn_t fn, void *context); read_tree_fn_t fn, void *context);


extern int read_tree(struct tree *tree, int stage, const char **paths); extern int read_tree(struct tree *tree, int stage, struct pathspec *pathspec);


#endif /* TREE_H */ #endif /* TREE_H */