git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org, Junio C Hamano <gitster@pobox.com>,
	Michael J Gruber <git@drmicha.warpmail.net>
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 1/3] Reimplement read_tree_recursive() using tree_entry_interesting()
Date: Fri, 25 Mar 2011 16:34:18 +0700	[thread overview]
Message-ID: <1301045660-25053-1-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <7vlj048f97.fsf@alter.siamese.dyndns.org>

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>
---
 2011/3/25 Junio C Hamano <gitster@pobox.com>:
 > Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
 >
 >> +static int read_tree_1(struct tree *tree, struct strbuf *base,
 >> +                    int stage, struct pathspec *pathspecs,
 >> +                    read_tree_fn_t fn, void *context)
 >
 > Micronit: call the variable pathspec, not pathspecs.

 Fixed (also in the second patch)

 > This "if all-interesting then avoid calling into an expensive matcher"
 > logic looks familiar but is not something that came from the parts deleted
 > by this patch.  Where did I see it? Is that something we can share in a
 > common helper function? Is such a sharing worth pursuing, considering that
 > the above is a reasonably trivial logic in a tight loop?
 >
 > "That's how the return value of tree-entry-interesting is designed to be
 > used, and it is unsurprising that all the callers will fall into that
 > pattern" is a perfectly acceptable answer, I guess.

 Actually the surrounding code could be improved so that helper function
 is not needed. I also update other t_e_i() callsites in the third patch.

 tree.c |  152 ++++++++++++++++++++++++----------------------------------------
 1 files changed, 57 insertions(+), 95 deletions(-)

diff --git a/tree.c b/tree.c
index 5ab90af..db3a5c3 100644
--- a/tree.c
+++ b/tree.c
@@ -45,62 +45,14 @@ static int read_one_entry_quick(const unsigned char *sha1, const char *base, int
 				  ADD_CACHE_JUST_APPEND);
 }
 
-static int match_tree_entry(const char *base, int baselen, const char *path, unsigned int mode, const char **paths)
-{
-	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)
+static int read_tree_1(struct tree *tree, struct strbuf *base,
+		       int stage, struct pathspec *pathspec,
+		       read_tree_fn_t fn, void *context)
 {
 	struct tree_desc desc;
 	struct name_entry entry;
+	unsigned char sha1[20];
+	int len, retval = 0, oldlen = base->len;
 
 	if (parse_tree(tree))
 		return -1;
@@ -108,10 +60,16 @@ int read_tree_recursive(struct tree *tree,
 	init_tree_desc(&desc, tree->buffer, tree->size);
 
 	while (tree_entry(&desc, &entry)) {
-		if (!match_tree_entry(base, baselen, entry.path, entry.mode, match))
-			continue;
+		if (retval != 2) {
+			retval = tree_entry_interesting(&entry, base, 0, pathspec);
+			if (retval < 0)
+				break;
+			if (retval == 0)
+				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:
 			continue;
 		case READ_TREE_RECURSIVE:
@@ -119,56 +77,60 @@ int read_tree_recursive(struct tree *tree,
 		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, '/');
+		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 not found",
-				    sha1_to_hex(entry.sha1), path.buf);
+				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",
-				    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;
+				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;
+
+		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;
 }
 
+int read_tree_recursive(struct tree *tree,
+			const char *base, int baselen,
+			int stage, const char **match,
+			read_tree_fn_t fn, void *context)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct pathspec pathspec;
+	int i, ret;
+
+	init_pathspec(&pathspec, match);
+	for (i = 0; i < pathspec.nr; i++)
+		pathspec.items[i].has_wildcard = 0;
+	strbuf_add(&sb, base, baselen);
+	ret = read_tree_1(tree, &sb, stage, &pathspec, fn, context);
+	strbuf_release(&sb);
+	free_pathspec(&pathspec);
+	return ret;
+}
+
 static int cmp_cache_name_compare(const void *a_, const void *b_)
 {
 	const struct cache_entry *ce1, *ce2;
-- 
1.7.4.74.g639db

  reply	other threads:[~2011-03-25  9:34 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-03-23 10:33 Relative ls-files John Tapsell
2011-03-23 10:49 ` Michael J Gruber
2011-03-23 11:27   ` John Tapsell
2011-03-23 11:28     ` demerphq
2011-03-23 11:42       ` Michael J Gruber
2011-03-23 13:54         ` Martin Langhoff
2011-03-23 14:09           ` Junio C Hamano
2011-03-23 14:14             ` Nguyen Thai Ngoc Duy
2011-03-23 15:20               ` Junio C Hamano
2011-03-23 15:41                 ` Nguyen Thai Ngoc Duy
2011-03-23 22:44                   ` Junio C Hamano
2011-03-24 13:26                     ` Nguyen Thai Ngoc Duy
2011-03-24 14:41                       ` [PATCH 1/2] Reimplement read_tree_recursive() using tree_entry_interesting() Nguyễn Thái Ngọc Duy
2011-03-24 14:41                         ` [PATCH 2/2] Convert read_tree{,_recursive} to support struct pathspec Nguyễn Thái Ngọc Duy
2011-03-24 14:49                           ` Nguyen Thai Ngoc Duy
2011-03-24 19:58                           ` Junio C Hamano
2011-03-24 19:07                         ` [PATCH 1/2] Reimplement read_tree_recursive() using tree_entry_interesting() Junio C Hamano
2011-03-24 19:55                         ` Junio C Hamano
2011-03-25  9:34                           ` Nguyễn Thái Ngọc Duy [this message]
2011-03-25  9:34                             ` [PATCH 2/3] Convert read_tree{,_recursive} to support struct pathspec Nguyễn Thái Ngọc Duy
2011-03-25  9:34                             ` [PATCH 3/3] Improve tree_entry_interesting() handling code Nguyễn Thái Ngọc Duy
2011-03-24 14:47                       ` Relative ls-files Junio C Hamano
2011-03-23 14:46             ` Martin Langhoff
2011-03-23 15:24               ` Junio C Hamano
2011-03-23 17:35             ` Junio C Hamano
2011-03-23 15:42         ` Junio C Hamano
2011-03-23 15:57           ` Michael J Gruber
2011-03-23 16:10             ` Nguyen Thai Ngoc Duy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1301045660-25053-1-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@drmicha.warpmail.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).