git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Linus Torvalds <torvalds@osdl.org>
To: Junio C Hamano <junkio@cox.net>
Cc: Git Mailing List <git@vger.kernel.org>
Subject: Re: [PATCH 6/8] ls-tree: work from subdirectory.
Date: Sat, 26 Nov 2005 09:38:20 -0800 (PST)	[thread overview]
Message-ID: <Pine.LNX.4.64.0511260855560.13959@g5.osdl.org> (raw)
In-Reply-To: <7vpson4tqi.fsf@assigned-by-dhcp.cox.net>



On Sat, 26 Nov 2005, Junio C Hamano wrote:
> 
> --- a/ls-tree.c
> +++ b/ls-tree.c
> @@ -8,6 +8,8 @@
>  #include "tree.h"
>  #include "quote.h"
>  
> +static const char *prefix;
> +

No need to have this visible outside of "main()".

> +	prefix = setup_git_directory_gently(&nongit);
> +	if (prefix)
> +		path0[0] = prefix;
...
> +	if (argc == 2)
> +		path = path0;
> +	else
> +		path = get_pathspec(prefix, argv + 2);
> +

And this is just ugly.

git-ls-tree should be rewritten to use a pathspec the same way everybody 
else does. Right now it's the odd man out: if you do

	git-ls-tree HEAD divers/char drivers/

it will show the same files _twice_, which is not how pathspecs in general 
work.

How about this patch? It breaks some of the git-ls-tree tests, but it 
makes git-ls-tree work a lot more like other git pathspec commands, and it 
removes more than 150 lines by re-using the recursive tree traversal (but 
the "-d" flag is gone for good, so I'm not pushing this too hard).

		Linus

---
diff --git a/ls-tree.c b/ls-tree.c
index d9f15e3..598b729 100644
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -13,215 +13,32 @@ static int line_termination = '\n';
 #define LS_TREE_ONLY 2
 static int ls_options = 0;
 
-static struct tree_entry_list root_entry;
-
-static void prepare_root(unsigned char *sha1)
-{
-	unsigned char rsha[20];
-	unsigned long size;
-	void *buf;
-	struct tree *root_tree;
-
-	buf = read_object_with_reference(sha1, "tree", &size, rsha);
-	free(buf);
-	if (!buf)
-		die("Could not read %s", sha1_to_hex(sha1));
-
-	root_tree = lookup_tree(rsha);
-	if (!root_tree)
-		die("Could not read %s", sha1_to_hex(sha1));
-
-	/* Prepare a fake entry */
-	root_entry.directory = 1;
-	root_entry.executable = root_entry.symlink = 0;
-	root_entry.mode = S_IFDIR;
-	root_entry.name = "";
-	root_entry.item.tree = root_tree;
-	root_entry.parent = NULL;
-}
-
-static int prepare_children(struct tree_entry_list *elem)
-{
-	if (!elem->directory)
-		return -1;
-	if (!elem->item.tree->object.parsed) {
-		struct tree_entry_list *e;
-		if (parse_tree(elem->item.tree))
-			return -1;
-		/* Set up the parent link */
-		for (e = elem->item.tree->entries; e; e = e->next)
-			e->parent = elem;
-	}
-	return 0;
-}
-
-static struct tree_entry_list *find_entry(const char *path, char *pathbuf)
-{
-	const char *next, *slash;
-	int len;
-	struct tree_entry_list *elem = &root_entry, *oldelem = NULL;
-
-	*(pathbuf) = '\0';
-
-	/* Find tree element, descending from root, that
-	 * corresponds to the named path, lazily expanding
-	 * the tree if possible.
-	 */
-
-	while (path) {
-		/* The fact we still have path means that the caller
-		 * wants us to make sure that elem at this point is a
-		 * directory, and possibly descend into it.  Even what
-		 * is left is just trailing slashes, we loop back to
-		 * here, and this call to prepare_children() will
-		 * catch elem not being a tree.  Nice.
-		 */
-		if (prepare_children(elem))
-			return NULL;
-
-		slash = strchr(path, '/');
-		if (!slash) {
-			len = strlen(path);
-			next = NULL;
-		}
-		else {
-			next = slash + 1;
-			len = slash - path;
-		}
-		if (len) {
-			if (oldelem) {
-				pathbuf += sprintf(pathbuf, "%s/", oldelem->name);
-			}
-
-			/* (len == 0) if the original path was "drivers/char/"
-			 * and we have run already two rounds, having elem
-			 * pointing at the drivers/char directory.
-			 */
-			elem = elem->item.tree->entries;
-			while (elem) {
-				if ((strlen(elem->name) == len) &&
-				    !strncmp(elem->name, path, len)) {
-					/* found */
-					break;
-				}
-				elem = elem->next;
-			}
-			if (!elem)
-				return NULL;
-
-			oldelem = elem;
-		}
-		path = next;
-	}
-
-	return elem;
-}
-
-static const char *entry_type(struct tree_entry_list *e)
-{
-	return (e->directory ? "tree" : "blob");
-}
-
-static const char *entry_hex(struct tree_entry_list *e)
-{
-	return sha1_to_hex(e->directory
-			   ? e->item.tree->object.sha1
-			   : e->item.blob->object.sha1);
-}
-
-/* forward declaration for mutually recursive routines */
-static int show_entry(struct tree_entry_list *, int, char *pathbuf);
-
-static int show_children(struct tree_entry_list *e, int level, char *pathbuf)
-{
-	int oldlen = strlen(pathbuf);
-
-	if (e != &root_entry)
-		sprintf(pathbuf + oldlen, "%s/", e->name);
-
-	if (prepare_children(e))
-		die("internal error: ls-tree show_children called with non tree");
-	e = e->item.tree->entries;
-	while (e) {
-		show_entry(e, level, pathbuf);
-		e = e->next;
-	}
-
-	pathbuf[oldlen] = '\0';
-
-	return 0;
-}
+static const char ls_tree_usage[] =
+	"git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
 
-static int show_entry(struct tree_entry_list *e, int level, char *pathbuf)
+static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
 {
-	int err = 0; 
-
-	if (e != &root_entry) {
-		printf("%06o %s %s	",
-		       e->mode, entry_type(e), entry_hex(e));
-		write_name_quoted(pathbuf, e->name, line_termination, stdout);
-		putchar(line_termination);
-	}
+	const char *type = "blob";
+	int retval = 0;
 
-	if (e->directory) {
-		/* If this is a directory, we have the following cases:
-		 * (1) This is the top-level request (explicit path from the
-		 *     command line, or "root" if there is no command line).
-		 *  a. Without any flag.  We show direct children.  We do not 
-		 *     recurse into them.
-		 *  b. With -r.  We do recurse into children.
-		 *  c. With -d.  We do not recurse into children.
-		 * (2) We came here because our caller is either (1-a) or
-		 *     (1-b).
-		 *  a. Without any flag.  We do not show our children (which
-		 *     are grandchildren for the original request).
-		 *  b. With -r.  We continue to recurse into our children.
-		 *  c. With -d.  We should not have come here to begin with.
-		 */
-		if (level == 0 && !(ls_options & LS_TREE_ONLY))
-			/* case (1)-a and (1)-b */
-			err = err | show_children(e, level+1, pathbuf);
-		else if (level && ls_options & LS_RECURSIVE)
-			/* case (2)-b */
-			err = err | show_children(e, level+1, pathbuf);
+	if (S_ISDIR(mode)) {
+		type = "tree";
+		if (ls_options & LS_RECURSIVE)
+			retval = READ_TREE_RECURSIVE;
 	}
-	return err;
-}
 
-static int list_one(const char *path)
-{
-	int err = 0;
-	char pathbuf[MAXPATHLEN + 1];
-	struct tree_entry_list *e = find_entry(path, pathbuf);
-	if (!e) {
-		/* traditionally ls-tree does not complain about
-		 * missing path.  We may change this later to match
-		 * what "/bin/ls -a" does, which is to complain.
-		 */
-		return err;
-	}
-	err = err | show_entry(e, 0, pathbuf);
-	return err;
+	printf("%06o %s %s\t%.*s%s%c", mode, type, sha1_to_hex(sha1), baselen, base, pathname, line_termination);
+	return retval;
 }
 
-static int list(char **path)
+int main(int argc, const char **argv)
 {
-	int i;
-	int err = 0;
-	for (i = 0; path[i]; i++)
-		err = err | list_one(path[i]);
-	return err;
-}
-
-static const char ls_tree_usage[] =
-	"git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
-
-int main(int argc, char **argv)
-{
-	static char *path0[] = { "", NULL };
-	char **path;
+	const char **path, *prefix;
 	unsigned char sha1[20];
+	char *buf;
+	unsigned long size;
 
+	prefix = setup_git_directory();
 	while (1 < argc && argv[1][0] == '-') {
 		switch (argv[1][1]) {
 		case 'z':
@@ -244,9 +61,11 @@ int main(int argc, char **argv)
 	if (get_sha1(argv[1], sha1) < 0)
 		usage(ls_tree_usage);
 
-	path = (argc == 2) ? path0 : (argv + 2);
-	prepare_root(sha1);
-	if (list(path) < 0)
-		die("list failed");
+	path = get_pathspec(prefix, argv + 2);
+	buf = read_object_with_reference(sha1, "tree", &size, NULL);
+	if (!buf)
+		die("not a tree object");
+	read_tree_recursive(buf, size, "", 0, 0, path, show_tree);
+
 	return 0;
 }
diff --git a/tree.c b/tree.c
index 8b42a07..043f032 100644
--- a/tree.c
+++ b/tree.c
@@ -9,9 +9,16 @@ const char *tree_type = "tree";
 
 static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
 {
-	int len = strlen(pathname);
-	unsigned int size = cache_entry_size(baselen + len);
-	struct cache_entry *ce = xmalloc(size);
+	int len;
+	unsigned int size;
+	struct cache_entry *ce;
+
+	if (S_ISDIR(mode))
+		return READ_TREE_RECURSIVE;
+
+	len = strlen(pathname);
+	size = cache_entry_size(baselen + len);
+	ce = xmalloc(size);
 
 	memset(ce, 0, size);
 
@@ -67,9 +74,10 @@ static int match_tree_entry(const char *
 	return 0;
 }
 
-static int read_tree_recursive(void *buffer, unsigned long size,
-			       const char *base, int baselen,
-			       int stage, const char **match)
+int read_tree_recursive(void *buffer, unsigned long size,
+			const char *base, int baselen,
+			int stage, const char **match,
+			read_tree_fn_t fn)
 {
 	while (size) {
 		int len = strlen(buffer)+1;
@@ -86,6 +94,14 @@ static int read_tree_recursive(void *buf
 		if (!match_tree_entry(base, baselen, path, mode, match))
 			continue;
 
+		switch (fn(sha1, base, baselen, path, mode, stage)) {
+		case 0:
+			continue;
+		case READ_TREE_RECURSIVE:
+			break;;
+		default:
+			return -1;
+		}
 		if (S_ISDIR(mode)) {
 			int retval;
 			int pathlen = strlen(path);
@@ -106,22 +122,20 @@ static int read_tree_recursive(void *buf
 			retval = read_tree_recursive(eltbuf, eltsize,
 						     newbase,
 						     baselen + pathlen + 1,
-						     stage, match);
+						     stage, match, fn);
 			free(eltbuf);
 			free(newbase);
 			if (retval)
 				return -1;
 			continue;
 		}
-		if (read_one_entry(sha1, base, baselen, path, mode, stage) < 0)
-			return -1;
 	}
 	return 0;
 }
 
 int read_tree(void *buffer, unsigned long size, int stage, const char **match)
 {
-	return read_tree_recursive(buffer, size, "", 0, stage, match);
+	return read_tree_recursive(buffer, size, "", 0, stage, match, read_one_entry);
 }
 
 struct tree *lookup_tree(const unsigned char *sha1)
diff --git a/tree.h b/tree.h
index 9975e88..768e5e9 100644
--- a/tree.h
+++ b/tree.h
@@ -35,4 +35,13 @@ int parse_tree(struct tree *tree);
 /* Parses and returns the tree in the given ent, chasing tags and commits. */
 struct tree *parse_tree_indirect(const unsigned char *sha1);
 
+#define READ_TREE_RECURSIVE 1
+typedef int (*read_tree_fn_t)(unsigned char *, const char *, int, const char *, unsigned int, int);
+
+extern int read_tree_recursive(void *buffer, unsigned long size,
+			const char *base, int baselen,
+			int stage, const char **match,
+			read_tree_fn_t fn);
+
+
 #endif /* TREE_H */

  reply	other threads:[~2005-11-26 17:38 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-11-20 17:00 Get rid of .git/branches/ and .git/remotes/? Johannes Schindelin
2005-11-20 18:09 ` Linus Torvalds
2005-11-20 18:29   ` Sven Verdoolaege
2005-11-20 19:07     ` Linus Torvalds
2005-11-20 19:16       ` Andreas Ericsson
2005-11-20 19:50   ` Johannes Schindelin
2005-11-26 23:50     ` Petr Baudis
2005-11-27  0:38       ` Junio C Hamano
2005-11-20 23:26   ` Josef Weidendorfer
2005-11-20 23:58     ` Johannes Schindelin
2005-11-22 17:31     ` Josef Weidendorfer
2005-11-22 17:56       ` Johannes Schindelin
2005-11-22 19:30         ` Andreas Ericsson
2005-11-23 15:08           ` Johannes Schindelin
2005-11-23 23:21             ` Junio C Hamano
2005-11-23 23:29               ` Andreas Ericsson
2005-11-23 23:42                 ` Johannes Schindelin
2005-11-24  8:05                   ` Andreas Ericsson
2005-11-24  8:33                     ` Junio C Hamano
2005-11-24 10:36                       ` [PATCH] Rename git-config-set to git-repo-config Johannes Schindelin
2005-11-24 11:33                         ` Junio C Hamano
2005-11-24 13:28                           ` Johannes Schindelin
2005-11-24 21:24                             ` Junio C Hamano
2005-11-24 21:54                               ` Johannes Schindelin
2005-11-26  2:22                                 ` Junio C Hamano
2005-11-26  4:05                                   ` Linus Torvalds
2005-11-26  4:07                                     ` Linus Torvalds
2005-11-26  9:51                                     ` [PATCH 0/8] Make C-level operable from subdirectories Junio C Hamano
2005-11-26 10:59                                       ` Junio C Hamano
2005-11-26 18:44                                       ` Ryan Anderson
2005-11-27  9:21                                     ` [PATCH 6/8] ls-tree: work from subdirectory Junio C Hamano
2005-11-27 11:08                                       ` Petr Baudis
2005-11-27 18:01                                       ` Linus Torvalds
2005-11-27 18:22                                         ` Petr Baudis
2005-11-27 19:00                                           ` Linus Torvalds
2005-11-28  1:07                                             ` Junio C Hamano
2005-11-28  1:46                                               ` Linus Torvalds
2005-11-28  6:11                                                 ` Junio C Hamano
2005-11-28  6:48                                                   ` Linus Torvalds
2005-11-28  8:32                                                     ` Junio C Hamano
2005-11-28 10:51                                                       ` Junio C Hamano
2005-11-28 10:51                                                     ` [PATCH] ls-tree: Resurrect funny name quoting lost during rewrite Junio C Hamano
2005-11-26  5:52                               ` [PATCH] Rename git-config-set to git-repo-config Junio C Hamano
2005-11-26  9:56                               ` [PATCH 1/8] git-apply: work from subdirectory Junio C Hamano
2005-11-26 17:36                                 ` Linus Torvalds
2005-11-26 18:54                                   ` Junio C Hamano
2005-11-27  4:06                                   ` Junio C Hamano
2005-11-27 14:39                                     ` Lars Magne Ingebrigtsen
     [not found]                                       ` <7vy839dfzk.fsf@assigned-by-dhcp.cox.net>
2005-11-27 21:13                                         ` Lars Magne Ingebrigtsen
2005-11-27 22:12                                           ` Junio C Hamano
2005-11-26  9:56                               ` [PATCH 2/8] peek-remote: honor proxy config even " Junio C Hamano
2005-11-26  9:56                               ` [PATCH 3/8] fsck-objects: work " Junio C Hamano
2005-11-26  9:56                               ` [PATCH 4/8] checkout-index: " Junio C Hamano
2005-11-26  9:57                               ` [PATCH 5/8] hash-object: work within subdirectory Junio C Hamano
2005-11-26  9:57                               ` [PATCH 6/8] ls-tree: work from subdirectory Junio C Hamano
2005-11-26 17:38                                 ` Linus Torvalds [this message]
2005-11-26  9:57                               ` [PATCH 7/8] Make networking commands to work from a subdirectory Junio C Hamano
2005-11-26  9:57                               ` [PATCH 8/8] Make the rest of commands " Junio C Hamano
2005-11-22 23:05         ` Get rid of .git/branches/ and .git/remotes/? Josef Weidendorfer
2005-11-23 14:53           ` Johannes Schindelin
2005-11-23 15:39             ` Josef Weidendorfer
2005-11-23 17:22               ` Johannes Schindelin

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

  List information: http://vger.kernel.org/majordomo-info.html

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

  git send-email \
    --in-reply-to=Pine.LNX.4.64.0511260855560.13959@g5.osdl.org \
    --to=torvalds@osdl.org \
    --cc=git@vger.kernel.org \
    --cc=junkio@cox.net \
    /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.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).