author | Junio C Hamano <gitster@pobox.com> | |
Mon, 31 Jan 2011 03:03:00 +0000 (19:03 -0800) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Mon, 31 Jan 2011 03:03:00 +0000 (19:03 -0800) |
* nd/struct-pathspec: (21 commits)
t7810: overlapping pathspecs and depth limit
grep: drop pathspec_matches() in favor of tree_entry_interesting()
grep: use writable strbuf from caller for grep_tree()
grep: use match_pathspec_depth() for cache/worktree grepping
grep: convert to use struct pathspec
Convert ce_path_match() to use match_pathspec_depth()
Convert ce_path_match() to use struct pathspec
struct rev_info: convert prune_data to struct pathspec
pathspec: add match_pathspec_depth()
tree_entry_interesting(): optimize wildcard matching when base is matched
tree_entry_interesting(): support wildcard matching
tree_entry_interesting(): fix depth limit with overlapping pathspecs
tree_entry_interesting(): support depth limit
tree_entry_interesting(): refactor into separate smaller functions
diff-tree: convert base+baselen to writable strbuf
glossary: define pathspec
Move tree_entry_interesting() to tree-walk.c and export it
tree_entry_interesting(): remove dependency on struct diff_options
Convert struct diff_options to use struct pathspec
diff-no-index: use diff_tree_setup_paths()
...
Conflicts:
tree-diff.c
t7810: overlapping pathspecs and depth limit
grep: drop pathspec_matches() in favor of tree_entry_interesting()
grep: use writable strbuf from caller for grep_tree()
grep: use match_pathspec_depth() for cache/worktree grepping
grep: convert to use struct pathspec
Convert ce_path_match() to use match_pathspec_depth()
Convert ce_path_match() to use struct pathspec
struct rev_info: convert prune_data to struct pathspec
pathspec: add match_pathspec_depth()
tree_entry_interesting(): optimize wildcard matching when base is matched
tree_entry_interesting(): support wildcard matching
tree_entry_interesting(): fix depth limit with overlapping pathspecs
tree_entry_interesting(): support depth limit
tree_entry_interesting(): refactor into separate smaller functions
diff-tree: convert base+baselen to writable strbuf
glossary: define pathspec
Move tree_entry_interesting() to tree-walk.c and export it
tree_entry_interesting(): remove dependency on struct diff_options
Convert struct diff_options to use struct pathspec
diff-no-index: use diff_tree_setup_paths()
...
Conflicts:
tree-diff.c
16 files changed:
1 | 2 | |||
---|---|---|---|---|
Documentation/glossary-content.txt | patch | | diff1 | | diff2 | | blob | history |
builtin/add.c | patch | | diff1 | | diff2 | | blob | history |
builtin/diff.c | patch | | diff1 | | diff2 | | blob | history |
builtin/grep.c | patch | | diff1 | | diff2 | | blob | history |
builtin/log.c | patch | | diff1 | | diff2 | | blob | history |
builtin/update-index.c | patch | | diff1 | | diff2 | | blob | history |
cache.h | patch | | diff1 | | diff2 | | blob | history |
diff.h | patch | | diff1 | | diff2 | | blob | history |
dir.c | patch | | diff1 | | diff2 | | blob | history |
dir.h | patch | | diff1 | | diff2 | | blob | history |
read-cache.c | patch | | diff1 | | diff2 | | blob | history |
revision.c | patch | | diff1 | | diff2 | | blob | history |
t/t7810-grep.sh | patch | | diff1 | | diff2 | | blob | history |
tree-diff.c | patch | | diff1 | | diff2 | | blob | history |
tree-walk.c | patch | | diff1 | | diff2 | | blob | history |
wt-status.c | patch | | diff1 | | diff2 | | blob | history |
diff --cc Documentation/glossary-content.txt
Simple merge
diff --cc builtin/add.c
Simple merge
diff --cc builtin/diff.c
Simple merge
diff --cc builtin/grep.c
Simple merge
diff --cc builtin/log.c
Simple merge
diff --cc builtin/update-index.c
Simple merge
diff --cc cache.h
Simple merge
diff --cc diff.h
Simple merge
diff --cc dir.c
Simple merge
diff --cc dir.h
Simple merge
diff --cc read-cache.c
Simple merge
diff --cc revision.c
Simple merge
diff --cc t/t7810-grep.sh
Simple merge
diff --cc tree-diff.c
index 12c9a88884ec3bb70a1744e44235c578a44e08e6,e27782c70e62d6011ec32c61c660084a001bd5c9..3954281f509bbed9a9b095ed92d24b67275fed82
--- 1/tree-diff.c
--- 2/tree-diff.c
+++ b/tree-diff.c
if (!tree || type != OBJ_TREE)
die("corrupt tree sha %s", sha1_to_hex(sha1));
- if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
- newbase[baselen + pathlen] = 0;
- opt->add_remove(opt, *prefix, mode, sha1, newbase, 0);
- newbase[baselen + pathlen] = '/';
- }
+ if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
+ opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0);
- init_tree_desc(&inner, tree, size);
- show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);
+ strbuf_addch(base, '/');
+ init_tree_desc(&inner, tree, size);
+ show_tree(opt, prefix, &inner, base);
free(tree);
- free(newbase);
- } else {
- char *fullname = malloc_fullname(base, baselen, path, pathlen);
- opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0);
- free(fullname);
- }
+ } else
+ opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0);
+
+ strbuf_setlen(base, old_baselen);
}
- static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting)
+ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
- struct diff_options *opt)
++ struct diff_options *opt, int *all_interesting)
{
- int all_interesting = 0;
while (t->size) {
- int show = tree_entry_interesting(t, base, baselen, opt);
- int show;
-
- if (all_interesting)
- show = 1;
- else {
- show = tree_entry_interesting(&t->entry, base, 0,
- &opt->pathspec);
- if (show == 2)
- all_interesting = 1;
- }
++ int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
+ if (show == 2)
+ *all_interesting = 1;
if (!show) {
update_tree_entry(t);
continue;
}
}
- int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
+ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
+ const char *base_str, struct diff_options *opt)
{
- int baselen = strlen(base);
+ struct strbuf base;
+ int baselen = strlen(base_str);
+ int all_t1_interesting = 0;
+ int all_t2_interesting = 0;
+ /* Enable recursion indefinitely */
+ opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
+ opt->pathspec.max_depth = -1;
+
+ strbuf_init(&base, PATH_MAX);
+ strbuf_add(&base, base_str, baselen);
+
for (;;) {
if (DIFF_OPT_TST(opt, QUICK) &&
DIFF_OPT_TST(opt, HAS_CHANGES))
break;
- if (opt->nr_paths) {
+ if (opt->pathspec.nr) {
- skip_uninteresting(t1, &base, opt);
- skip_uninteresting(t2, &base, opt);
+ if (!all_t1_interesting)
- skip_uninteresting(t1, base, baselen, opt,
- &all_t1_interesting);
++ skip_uninteresting(t1, &base, opt, &all_t1_interesting);
+ if (!all_t2_interesting)
- skip_uninteresting(t2, base, baselen, opt,
- &all_t2_interesting);
++ skip_uninteresting(t2, &base, opt, &all_t2_interesting);
}
if (!t1->size) {
if (!t2->size)
diff --cc tree-walk.c
index a9bbf4e2354df5ce6b010873b419731343a12c7d,9b43ad58b55173f8a6535fb583e89ed004934ff7..ddcf50c30a25e5c3695b41363c050d1c1f6580bf
--- 1/tree-walk.c
--- 2/tree-walk.c
+++ b/tree-walk.c
free(tree);
return retval;
}
+
+ static int match_entry(const struct name_entry *entry, int pathlen,
+ const char *match, int matchlen,
+ int *never_interesting)
+ {
+ int m = -1; /* signals that we haven't called strncmp() */
+
+ if (*never_interesting) {
+ /*
+ * We have not seen any match that sorts later
+ * than the current path.
+ */
+
+ /*
+ * Does match sort strictly earlier than path
+ * with their common parts?
+ */
+ m = strncmp(match, entry->path,
+ (matchlen < pathlen) ? matchlen : pathlen);
+ if (m < 0)
+ return 0;
+
+ /*
+ * If we come here even once, that means there is at
+ * least one pathspec that would sort equal to or
+ * later than the path we are currently looking at.
+ * In other words, if we have never reached this point
+ * after iterating all pathspecs, it means all
+ * pathspecs are either outside of base, or inside the
+ * base but sorts strictly earlier than the current
+ * one. In either case, they will never match the
+ * subsequent entries. In such a case, we initialized
+ * the variable to -1 and that is what will be
+ * returned, allowing the caller to terminate early.
+ */
+ *never_interesting = 0;
+ }
+
+ if (pathlen > matchlen)
+ return 0;
+
+ if (matchlen > pathlen) {
+ if (match[pathlen] != '/')
+ return 0;
+ if (!S_ISDIR(entry->mode))
+ return 0;
+ }
+
+ if (m == -1)
+ /*
+ * we cheated and did not do strncmp(), so we do
+ * that here.
+ */
+ m = strncmp(match, entry->path, pathlen);
+
+ /*
+ * If common part matched earlier then it is a hit,
+ * because we rejected the case where path is not a
+ * leading directory and is shorter than match.
+ */
+ if (!m)
+ return 1;
+
+ return 0;
+ }
+
+ static int match_dir_prefix(const char *base, int baselen,
+ const char *match, int matchlen)
+ {
+ if (strncmp(base, match, matchlen))
+ return 0;
+
+ /*
+ * If the base is a subdirectory of a path which
+ * was specified, all of them are interesting.
+ */
+ if (!matchlen ||
+ base[matchlen] == '/' ||
+ match[matchlen - 1] == '/')
+ return 1;
+
+ /* Just a random prefix match */
+ return 0;
+ }
+
+ /*
+ * Is a tree entry interesting given the pathspec we have?
+ *
++ * Pre-condition: baselen == 0 || base[baselen-1] == '/'
++ *
+ * Return:
+ * - 2 for "yes, and all subsequent entries will be"
+ * - 1 for yes
+ * - zero for no
+ * - negative for "no, and no subsequent entries will be either"
+ */
+ int tree_entry_interesting(const struct name_entry *entry,
+ struct strbuf *base, int base_offset,
+ const struct pathspec *ps)
+ {
+ int i;
+ int pathlen, baselen = base->len - base_offset;
+ int never_interesting = ps->has_wildcard ? 0 : -1;
+
+ if (!ps->nr) {
+ if (!ps->recursive || ps->max_depth == -1)
+ return 1;
+ return !!within_depth(base->buf + base_offset, baselen,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth);
+ }
+
+ pathlen = tree_entry_len(entry->path, entry->sha1);
+
+ for (i = ps->nr-1; i >= 0; i--) {
+ const struct pathspec_item *item = ps->items+i;
+ const char *match = item->match;
+ const char *base_str = base->buf + base_offset;
+ int matchlen = item->len;
+
+ if (baselen >= matchlen) {
+ /* If it doesn't match, move along... */
+ if (!match_dir_prefix(base_str, baselen, match, matchlen))
+ goto match_wildcards;
+
+ if (!ps->recursive || ps->max_depth == -1)
+ return 2;
+
+ return !!within_depth(base_str + matchlen + 1,
+ baselen - matchlen - 1,
+ !!S_ISDIR(entry->mode),
+ ps->max_depth);
+ }
+
+ /* Does the base match? */
+ if (!strncmp(base_str, match, baselen)) {
+ if (match_entry(entry, pathlen,
+ match + baselen, matchlen - baselen,
+ &never_interesting))
+ return 1;
+
+ if (ps->items[i].has_wildcard) {
+ if (!fnmatch(match + baselen, entry->path, 0))
+ return 1;
+
+ /*
+ * Match all directories. We'll try to
+ * match files later on.
+ */
+ if (ps->recursive && S_ISDIR(entry->mode))
+ return 1;
+ }
+
+ continue;
+ }
+
+ match_wildcards:
+ if (!ps->items[i].has_wildcard)
+ continue;
+
+ /*
+ * Concatenate base and entry->path into one and do
+ * fnmatch() on it.
+ */
+
+ strbuf_add(base, entry->path, pathlen);
+
+ if (!fnmatch(match, base->buf + base_offset, 0)) {
+ strbuf_setlen(base, base_offset + baselen);
+ return 1;
+ }
+ strbuf_setlen(base, base_offset + baselen);
+
+ /*
+ * Match all directories. We'll try to match files
+ * later on.
+ */
+ if (ps->recursive && S_ISDIR(entry->mode))
+ return 1;
+ }
+ return never_interesting; /* No matches */
+ }
diff --cc wt-status.c
Simple merge