threads / patch / 7030

patch, 2 partsgit-show: use pathattr to run "display"

Subject: [PATCH 2/2] git-show: use pathattr to run "display"

## tl;dr

6 messages between Mar 1, 2007 and Mar 1, 2007. Diffs are folded; open one to read it.

replies: 5people: 2as markdown or json

Junio C Hamano· Mar 1, 2007, 07:18 UTC · lore

This is a bit of detour, to demonstrate a possible use of pathattr infrastructure. With this,

	$ git show v1.4.4:t/test4012.png
would hopefully do what you would expect.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 * I was planning to write the config reader as a follow-up, but
   got sidetracked.  After all, doing something whose effect is
   visible is more fun.
 builtin-log.c |   31 ++++++++++++++++++++++++-------
 pathattr.c    |    8 ++++++++
 pathattr.h    |    3 +++
 3 files changed, 35 insertions(+), 7 deletions(-)
Show changes to 3 files +35 −7

builtin-log.c, pathattr.c, pathattr.h

diff --git a/builtin-log.c b/builtin-log.c
index 1c9f7d0..519fab2 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -12,6 +12,7 @@
 #include "builtin.h"
 #include "tag.h"
 #include "reflog-walk.h"
+#include "pathattr.h"
 
 static int default_show_root = 1;
 
@@ -86,26 +87,42 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
 	return cmd_log_walk(&rev);
 }
 
-static int show_object(const unsigned char *sha1, int suppress_header)
+static void to_stdout(const unsigned char *blobdata, unsigned long size)
+{
+	fwrite(blobdata, size, 1, stdout);
+}
+
+static int show_object(const unsigned char *sha1, const char *path, int nohead)
 {
 	unsigned long size;
 	enum object_type type;
-	char *buf = read_sha1_file(sha1, &type, &size);
+	unsigned char *buf = read_sha1_file(sha1, &type, &size);
 	int offset = 0;
+	pretty_fn pretty = to_stdout;
 
 	if (!buf)
 		return error("Could not read object %s", sha1_to_hex(sha1));
 
-	if (suppress_header)
+	if (nohead) {
 		while (offset < size && buf[offset++] != '\n') {
 			int new_offset = offset;
 			while (new_offset < size && buf[new_offset++] != '\n')
 				; /* do nothing */
 			offset = new_offset;
 		}
+	}
+
+	if (size <= offset)
+		goto finish;
+
+	if (path) {
+		const struct pathattr *a = pathattr_lookup(path);
+		if (a && a->pretty)
+			pretty = a->pretty;
+	}
 
-	if (offset < size)
-		fwrite(buf + offset, size - offset, 1, stdout);
+	pretty(buf + offset, size - offset);
+ finish:
 	free(buf);
 	return 0;
 }
@@ -142,7 +159,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 		const char *name = objects[i].name;
 		switch (o->type) {
 		case OBJ_BLOB:
-			ret = show_object(o->sha1, 0);
+			ret = show_object(o->sha1, name, 0);
 			break;
 		case OBJ_TAG: {
 			struct tag *t = (struct tag *)o;
@@ -153,7 +170,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					t->tag,
 					diff_get_color(rev.diffopt.color_diff,
 						DIFF_RESET));
-			ret = show_object(o->sha1, 1);
+			ret = show_object(o->sha1, name, 1);
 			objects[i].item = (struct object *)t->tagged;
 			i--;
 			break;
diff --git a/pathattr.c b/pathattr.c
index 06bbb4e..c84be39 100644
--- a/pathattr.c
+++ b/pathattr.c
@@ -1,6 +1,13 @@
 #include "cache.h"
 #include "pathattr.h"
 
+static void show_display(const unsigned char *blobdata, unsigned long size)
+{
+	FILE *display = popen("display -", "w");
+	fwrite(blobdata, size, 1, display);
+	fclose(display);
+}
+
 /*
  * Path match specification
  */
@@ -93,6 +100,7 @@ static void init_stack(void)
 	a = locate(stk, "image/*");
 	a->conv_i = NULL;
 	a->conv_o = NULL;
+	a->pretty = show_display;
 	add_match(stk, a, "*.png");
 	add_match(stk, a, "*.jpg");
 	add_match(stk, a, "*.gif");
diff --git a/pathattr.h b/pathattr.h
index 4ca4e60..bfd9ff1 100644
--- a/pathattr.h
+++ b/pathattr.h
@@ -3,6 +3,8 @@
 
 #include "convert.h"
 
+typedef void (*pretty_fn)(const unsigned char *blobdata, unsigned long size);
+
 /*
  * Data in one section of [pathattr "name"], except
  * the path match specification.
@@ -11,6 +13,7 @@ struct pathattr {
 	char *name;
 	convi_fn conv_i;
 	convo_fn conv_o;
+	pretty_fn pretty;
 };
 
 const struct pathattr *pathattr_lookup(const char *);
-- 
1.5.0.2.809.g0f936
Andy Parkins· Mar 1, 2007, 09:04 UTC · re: Junio C Hamano · lore

Re: [PATCH 2/2] git-show: use pathattr to run "display"

On Thursday 2007 March 01 07:18, Junio C Hamano wrote:
Show 6 quoted lines
> This is a bit of detour, to demonstrate a possible use of
> pathattr infrastructure.  With this,
>
> 	$ git show v1.4.4:t/test4012.png
>
> would hopefully do what you would expect.
Is this serious?  This doesn't belong inside git does it?

What if I don't want to run "display"? What if I don't want to run anything, and just want png files dumped raw to the terminal?

Andy
-- 
Dr Andy Parkins, M Eng (hons), MIET
andyparkins@gmail.com
Andy Parkins· Mar 1, 2007, 09:17 UTC · re: Andy Parkins · lore

Re: [PATCH 2/2] git-show: use pathattr to run "display"

On Thursday 2007 March 01 09:04, Andy Parkins wrote:
> Is this serious?  This doesn't belong inside git does it?
I see from the source that it's not.  It's just a demo.  Sorry Junio.
Andy
-- 
Dr Andy Parkins, M Eng (hons), MIET
andyparkins@gmail.com
Junio C Hamano· Mar 1, 2007, 09:26 UTC · re: Junio C Hamano · lore

[PATCH 3/2] pathattr: read from git_config().

Now we read the path traits from the usual configuration mechanism. No per-directory .gitattributes yet, though.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 * [3/2] (this one) and [4/2] are the follow-up to the pathattr
   series.
 pathattr.c |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 62 insertions(+), 1 deletions(-)
Show changes to pathattr.c +62 −1
diff --git a/pathattr.c b/pathattr.c
index c84be39..2532c9a 100644
--- a/pathattr.c
+++ b/pathattr.c
@@ -85,6 +85,67 @@ static void add_match(struct pathattr_stack *s, struct pathattr *a, const char *
 	m->attr = a;
 }
 
+static convi_fn conv_i_trait(const char *value)
+{
+	if (!strcmp(value, "crlf"))
+		return convi_crlf;
+	return NULL;
+}
+
+static convo_fn conv_o_trait(const char *value)
+{
+	if (!strcmp(value, "crlf"))
+		return convo_crlf;
+	return NULL;
+}
+
+static pretty_fn pretty_trait(const char *value)
+{
+	if (!strcmp(value, "display"))
+		return show_display;
+	return NULL;
+}
+
+static int attr_config(const char *var, const char *value)
+{
+	struct pathattr *a;
+	static const char pa[] = "pathattr.";
+	const char *trait;
+	char group[256];
+	int group_len;
+
+	if (prefixcmp(var, pa))
+		return 0; /* we are not interested in other configs */
+	trait = strrchr(var, '.');
+	if (!trait)
+		return 0; /* huh? */
+	group_len = trait - var - (sizeof(pa) - 1);
+	if (group_len <= 0)
+		return 0; /* huh? */
+	trait++;
+	if (sizeof(group) < group_len)
+		die("'%.*s' is too long as a group name", group_len,
+		    var + sizeof(pa) - 1);
+	memcpy(group, var + sizeof(pa) - 1, group_len);
+	group[group_len] = 0;
+	a = locate(stk, group);
+
+	if (!strcmp(trait, "path"))
+		add_match(stk, a, value);
+	else if (!strcmp(trait, "conv_i"))
+		a->conv_i = conv_i_trait(value);
+	else if (!strcmp(trait, "conv_o"))
+		a->conv_i = conv_o_trait(value);
+	else if (!strcmp(trait, "pretty"))
+		a->pretty = pretty_trait(value);
+	/*
+	 * Do not barf if the configuration has unknown trait.
+	 * the user might be bisecting git and trying an older
+	 * version on the latest repository.
+	 */
+	return 0;
+}
+
 static void init_stack(void)
 {
 	struct pathattr *a;
@@ -105,7 +166,7 @@ static void init_stack(void)
 	add_match(stk, a, "*.jpg");
 	add_match(stk, a, "*.gif");
 
-	/* NEEDSWORK: read from config */
+	git_config(attr_config);
 }
 
 static void pop_stack(void)
-- 
1.5.0.2.809.g0f936
Junio C Hamano· Mar 1, 2007, 09:29 UTC · re: Junio C Hamano · lore

[PATCH 4/2] pathattr: allow piping to external program.

This sets up capability for various traits to be an external process, accessed via pipe. conv-i and conv-o need to spawn bidirectional pipe, but I have not coded that part yet.

You can try running:
    $ git show HEAD:Documentation/*.txt
with:
    [pathattr "kludge"]
        path = Documentation/*.txt
        pretty = "pipe sed -e 's/^/>> /'"
to see what it does.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 * I somehow suspect two Johannes'es would hate me for doing
   this.  I should instead resume coding the part to read
   .gitattributes from each directory, but spawning external
   stuff to borrow what other people already have done is much
   more fun than doing gruntwork in C.
 builtin-log.c |   18 ++++++++++---
 convert.c     |   16 ++++++------
 convert.h     |    3 --
 pathattr.c    |   77 ++++++++++++++++++++++++++++++++++++++++++++++----------
 pathattr.h    |    8 +++++-
 5 files changed, 92 insertions(+), 30 deletions(-)
Show changes to 5 files +92 −30

builtin-log.c, convert.c, convert.h, pathattr.c, pathattr.h

diff --git a/builtin-log.c b/builtin-log.c
index 519fab2..86062d3 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -87,7 +87,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
 	return cmd_log_walk(&rev);
 }
 
-static void to_stdout(const unsigned char *blobdata, unsigned long size)
+static void to_stdout(const unsigned char *blobdata, unsigned long size, const char *unused)
 {
 	fwrite(blobdata, size, 1, stdout);
 }
@@ -99,6 +99,7 @@ static int show_object(const unsigned char *sha1, const char *path, int nohead)
 	unsigned char *buf = read_sha1_file(sha1, &type, &size);
 	int offset = 0;
 	pretty_fn pretty = to_stdout;
+	char *pretty_args = NULL;
 
 	if (!buf)
 		return error("Could not read object %s", sha1_to_hex(sha1));
@@ -117,11 +118,13 @@ static int show_object(const unsigned char *sha1, const char *path, int nohead)
 
 	if (path) {
 		const struct pathattr *a = pathattr_lookup(path);
-		if (a && a->pretty)
+		if (a && a->pretty) {
 			pretty = a->pretty;
+			pretty_args = a->pretty_args;
+		}
 	}
 
-	pretty(buf + offset, size - offset);
+	pretty(buf + offset, size - offset, pretty_args);
  finish:
 	free(buf);
 	return 0;
@@ -159,6 +162,13 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 		const char *name = objects[i].name;
 		switch (o->type) {
 		case OBJ_BLOB:
+			/*
+			 * This is a hack to make v2.6.0:README
+			 * and friends to work.  Anybody have
+			 * better ideas?
+			 */
+			if (strchr(name, ':'))
+				name = strchr(name, ':') + 1;
 			ret = show_object(o->sha1, name, 0);
 			break;
 		case OBJ_TAG: {
@@ -170,7 +180,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
 					t->tag,
 					diff_get_color(rev.diffopt.color_diff,
 						DIFF_RESET));
-			ret = show_object(o->sha1, name, 1);
+			ret = show_object(o->sha1, NULL, 1);
 			objects[i].item = (struct object *)t->tagged;
 			i--;
 			break;
diff --git a/convert.c b/convert.c
index c39946d..504036e 100644
--- a/convert.c
+++ b/convert.c
@@ -253,11 +253,11 @@ static int convo_autocrlf(const char *path, char **bufp, unsigned long *sizep)
 int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
 {
 	if (path) {
-		const struct pathattr *attr = pathattr_lookup(path);
-		if (attr) {
-			if (!attr->conv_i)
+		const struct pathattr *a = pathattr_lookup(path);
+		if (a) {
+			if (!a->conv_i)
 				return 0;
-			return attr->conv_i(path, bufp, sizep);
+			return a->conv_i(path, bufp, sizep, a->conv_i_args);
 		}
 	}
 	/* Fallback */
@@ -268,11 +268,11 @@ int convert_to_working_tree(const char *path, char **bufp,
 			    unsigned long *sizep)
 {
 	if (path) {
-		const struct pathattr *attr = pathattr_lookup(path);
-		if (attr) {
-			if (!attr->conv_o)
+		const struct pathattr *a = pathattr_lookup(path);
+		if (a) {
+			if (!a->conv_o)
 				return 0;
-			return attr->conv_o(path, bufp, sizep);
+			return a->conv_o(path, bufp, sizep, a->conv_o_args);
 		}
 	}
 	/* Fallback */
diff --git a/convert.h b/convert.h
index e54b3ef..ff6fb85 100644
--- a/convert.h
+++ b/convert.h
@@ -1,9 +1,6 @@
 #ifndef CONVERT_H
 #define CONVERT_H
 
-typedef int (*convi_fn)(const char *, char **, unsigned long *);
-typedef int (*convo_fn)(const char *, char **, unsigned long *);
-
 int convi_crlf(const char *path, char **bufp, unsigned long *sizep);
 int convo_crlf(const char *path, char **bufp, unsigned long *sizep);
 
diff --git a/pathattr.c b/pathattr.c
index 2532c9a..9362234 100644
--- a/pathattr.c
+++ b/pathattr.c
@@ -1,9 +1,30 @@
 #include "cache.h"
 #include "pathattr.h"
 
-static void show_display(const unsigned char *blobdata, unsigned long size)
+static int convi_pipe(const char *path, char **bufp, unsigned long *sizep,
+		      const char *args)
 {
-	FILE *display = popen("display -", "w");
+	/* NEEDSWORK: set up two-way pipe, spawn command specified
+	 * with args, and have it convert bufp & sizep
+	 */
+	return 0;
+}
+
+static int convo_pipe(const char *path, char **bufp, unsigned long *sizep,
+		      const char *args)
+{
+	/* NEEDSWORK: set up two-way pipe, spawn command specified
+	 * with args, and have it convert bufp & sizep
+	 */
+	return 0;
+}
+
+static void pretty_pipe(const unsigned char *blobdata, unsigned long size,
+			const char *args)
+{
+	FILE *display;
+
+	display = popen(args, "w");
 	fwrite(blobdata, size, 1, display);
 	fclose(display);
 }
@@ -67,6 +88,7 @@ static struct pathattr *locate(struct pathattr_stack *s, const char *name)
 		s->attr = xrealloc(s->attr, sizeof(*a) * s->attr_alloc);
 	}
 	a = &(s->attr[s->attr_nr++]);
+	memset(a, 0, sizeof(*a));
 	a->name = xstrdup(name);
 	return a;
 }
@@ -80,29 +102,57 @@ static void add_match(struct pathattr_stack *s, struct pathattr *a, const char *
 		s->match = xrealloc(s->match, sizeof(*m) * s->match_alloc);
 	}
 	m = &(s->match[s->match_nr++]);
+	memset(m, 0, sizeof(*m));
 	m->pattern = xstrdup(pattern);
 	m->type = strchr(pattern, '/') ? FNM_PATHNAME : 0;
 	m->attr = a;
 }
 
-static convi_fn conv_i_trait(const char *value)
+static int call_convi_crlf(const char *path, char **bufp, unsigned long *sizep,
+			   const char *args)
+{
+	return convi_crlf(path, bufp, sizep);
+}
+
+static int call_convo_crlf(const char *path, char **bufp, unsigned long *sizep,
+			   const char *args)
+{
+	return convo_crlf(path, bufp, sizep);
+}
+
+static int parse_pipe_trait(const char *value, char **args)
+{
+	if (strncmp(value, "pipe ", 5))
+		return 0;
+	free(*args);
+	*args = xstrdup(value + 5);
+	return 1;
+}
+
+static convi_fn conv_i_trait(const char *value, struct pathattr *a)
 {
 	if (!strcmp(value, "crlf"))
-		return convi_crlf;
+		return call_convi_crlf;
+	if (parse_pipe_trait(value, &a->conv_i_args))
+		return convi_pipe;
 	return NULL;
 }
 
-static convo_fn conv_o_trait(const char *value)
+static convo_fn conv_o_trait(const char *value, struct pathattr *a)
 {
 	if (!strcmp(value, "crlf"))
-		return convo_crlf;
+		return call_convo_crlf;
+	if (parse_pipe_trait(value, &a->conv_o_args))
+		return convo_pipe;
 	return NULL;
 }
 
-static pretty_fn pretty_trait(const char *value)
+static pretty_fn pretty_trait(const char *value, struct pathattr *a)
 {
 	if (!strcmp(value, "display"))
-		return show_display;
+		value = "pipe display -";
+	if (parse_pipe_trait(value, &a->pretty_args))
+		return pretty_pipe;
 	return NULL;
 }
 
@@ -133,11 +183,11 @@ static int attr_config(const char *var, const char *value)
 	if (!strcmp(trait, "path"))
 		add_match(stk, a, value);
 	else if (!strcmp(trait, "conv_i"))
-		a->conv_i = conv_i_trait(value);
+		a->conv_i = conv_i_trait(value, a);
 	else if (!strcmp(trait, "conv_o"))
-		a->conv_i = conv_o_trait(value);
+		a->conv_i = conv_o_trait(value, a);
 	else if (!strcmp(trait, "pretty"))
-		a->pretty = pretty_trait(value);
+		a->pretty = pretty_trait(value, a);
 	/*
 	 * Do not barf if the configuration has unknown trait.
 	 * the user might be bisecting git and trying an older
@@ -154,14 +204,13 @@ static void init_stack(void)
 
 	/* A couple of silly example as an illustration */
 	a = locate(stk, "silly");
-	a->conv_i = convi_crlf;
-	a->conv_o = convo_crlf;
+	a->conv_i = call_convi_crlf;
+	a->conv_o = call_convo_crlf;
 	add_match(stk, a, "*.dos-txt");
 
 	a = locate(stk, "image/*");
 	a->conv_i = NULL;
 	a->conv_o = NULL;
-	a->pretty = show_display;
 	add_match(stk, a, "*.png");
 	add_match(stk, a, "*.jpg");
 	add_match(stk, a, "*.gif");
diff --git a/pathattr.h b/pathattr.h
index bfd9ff1..34e8ce4 100644
--- a/pathattr.h
+++ b/pathattr.h
@@ -3,7 +3,9 @@
 
 #include "convert.h"
 
-typedef void (*pretty_fn)(const unsigned char *blobdata, unsigned long size);
+typedef int (*convi_fn)(const char *, char **, unsigned long *, const char *);
+typedef int (*convo_fn)(const char *, char **, unsigned long *, const char *);
+typedef void (*pretty_fn)(const unsigned char *, unsigned long, const char *);
 
 /*
  * Data in one section of [pathattr "name"], except
@@ -14,6 +16,10 @@ struct pathattr {
 	convi_fn conv_i;
 	convo_fn conv_o;
 	pretty_fn pretty;
+
+	char *conv_i_args;
+	char *conv_o_args;
+	char *pretty_args;
 };
 
 const struct pathattr *pathattr_lookup(const char *);
-- 
1.5.0.2.809.g0f936
Junio C Hamano· Mar 1, 2007, 09:37 UTC · re: Junio C Hamano · lore

Re: [PATCH 4/2] pathattr: allow piping to external program.

Junio C Hamano <junkio@cox.net> writes:
Show 7 quoted lines
> This sets up capability for various traits to be an external
> process, accessed via pipe.  conv-i and conv-o need to spawn
> bidirectional pipe, but I have not coded that part yet.
>
> You can try running:
>
>     $ git show HEAD:Documentation/*.txt
... obviously I meant
	$ git show HEAD:Documentation/git.txt
or something a bit more concrete than '*' here.
Show 10 quoted lines
>
> with:
>
>     [pathattr "kludge"]
>         path = Documentation/*.txt
>         pretty = "pipe sed -e 's/^/>> /'"
>
> to see what it does.
>
> Signed-off-by: Junio C Hamano <junkio@cox.net>

← back to recent threads