{"thread":{"id":"23420","subject":"[RFC/PATCH 1/3] strbuf: Add strbuf_vaddf function","startedAt":"2010-04-11T11:37:29Z","lastAt":"2010-04-11T23:30:33Z","messageCount":24,"participants":["Julian Phillips","Erik Faye-Lund","Jakub Narebski","Sverre Rabbelier","Junio C Hamano","Eric Raymond","Jon Seymour"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"139246","messageId":"20100411112928.80010.1786.julian@quantumfyre.co.uk","threadId":"23420","inReplyTo":null,"subject":"[RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T11:37:29Z","receivedAt":"2010-04-11T11:37:29Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"Here is an attempt at making a format agnostic structured output library.  The\nidea being that the command doing the output doesn't have to care what the\nactual output format is, it just uses the abstract notion of objects and arrays.\n\nThe current backend/frontend interface probably needs expanding so that a less\nnoddy XML output can be used, but it's a start.\n\nRather than building an in-memory structure and then writing it out I've gone\nfor the approach of writing out immediately.  The thought behind this was that I\ndidn't really want to force commands like log to have to wait 'til the end to\nstart outputting information.\n\nThe JSON output is formatted differently from my previous JSON-only status\nmodification, but the actual information output is the same (i.e. the output of\na json parser should be identical ignoring item ordering in objects).\n\nJulian Phillips (3):\n  strbuf: Add strbuf_vaddf function\n  add a library of code for producing structured output\n  status: add support for structured output\n\n Makefile         |    3 +\n builtin/commit.c |   12 +++\n output-json.c    |  128 ++++++++++++++++++++++++++++++++\n output-xml.c     |   68 +++++++++++++++++\n output.c         |  212 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n output.h         |   71 ++++++++++++++++++\n strbuf.c         |   13 +++-\n strbuf.h         |    1 +\n wt-status.c      |   73 +++++++++++++++++++\n wt-status.h      |    2 +\n 10 files changed, 581 insertions(+), 2 deletions(-)\n create mode 100644 output-json.c\n create mode 100644 output-xml.c\n create mode 100644 output.c\n create mode 100644 output.h\n"},{"id":"139244","messageId":"20100411113733.80010.78232.julian@quantumfyre.co.uk","threadId":"23420","inReplyTo":"20100411112928.80010.1786.julian@quantumfyre.co.uk","subject":"[RFC/PATCH 1/3] strbuf: Add strbuf_vaddf function","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T11:37:30Z","receivedAt":"2010-04-11T11:37:30Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"Add strbuf_vaddf which is to strbuf_addf as vprintf is to printf.\n\nSigned-off-by: Julian Phillips <julian@quantumfyre.co.uk>\n---\n strbuf.c |   13 +++++++++++--\n strbuf.h |    1 +\n 2 files changed, 12 insertions(+), 2 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex bc3a080..8f312f8 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -194,19 +194,28 @@ void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)\n \n void strbuf_addf(struct strbuf *sb, const char *fmt, ...)\n {\n+\tva_list ap;\n+\n+\tva_start(ap, fmt);\n+        strbuf_vaddf(sb, fmt, ap);\n+\tva_end(ap);\n+}\n+\n+void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list args)\n+{\n \tint len;\n \tva_list ap;\n \n \tif (!strbuf_avail(sb))\n \t\tstrbuf_grow(sb, 64);\n-\tva_start(ap, fmt);\n+\tva_copy(ap, args);\n \tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n \tva_end(ap);\n \tif (len < 0)\n \t\tdie(\"your vsnprintf is broken\");\n \tif (len > strbuf_avail(sb)) {\n \t\tstrbuf_grow(sb, len);\n-\t\tva_start(ap, fmt);\n+\t\tva_copy(ap, args);\n \t\tlen = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);\n \t\tva_end(ap);\n \t\tif (len > strbuf_avail(sb)) {\ndiff --git a/strbuf.h b/strbuf.h\nindex fac2dbc..ac52834 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -120,6 +120,7 @@ extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *\n \n __attribute__((format (printf,2,3)))\n extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n+extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list args);\n \n extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n /* XXX: if read fails, any partial read is undone */\n-- \n1.7.0.4\n"},{"id":"139247","messageId":"20100411113733.80010.3767.julian@quantumfyre.co.uk","threadId":"23420","inReplyTo":"20100411112928.80010.1786.julian@quantumfyre.co.uk","subject":"[RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T11:37:31Z","receivedAt":"2010-04-11T11:37:31Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"Add a library that allows commands to produce structured output in any\nof a range of formats using a single API.\n\nThe API includes an OPT_OUTPUT and handle_output_arg so that the\noption handling for different commands will be as similar as possible.\n\nAt the moment JSON and XML output options are available - though the\nXML output is _very_ rudimentary.\n\nSigned-off-by: Julian Phillips <julian@quantumfyre.co.uk>\n---\n Makefile      |    3 +\n output-json.c |  128 ++++++++++++++++++++++++++++++++++\n output-xml.c  |   68 ++++++++++++++++++\n output.c      |  212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n output.h      |   71 +++++++++++++++++++\n 5 files changed, 482 insertions(+), 0 deletions(-)\n create mode 100644 output-json.c\n create mode 100644 output-xml.c\n create mode 100644 output.c\n create mode 100644 output.h\n\ndiff --git a/Makefile b/Makefile\nindex 910f471..4ba2a4f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -576,6 +576,9 @@ LIB_OBJS += merge-recursive.o\n LIB_OBJS += name-hash.o\n LIB_OBJS += notes.o\n LIB_OBJS += object.o\n+LIB_OBJS += output.o\n+LIB_OBJS += output-json.o\n+LIB_OBJS += output-xml.o\n LIB_OBJS += pack-check.o\n LIB_OBJS += pack-refs.o\n LIB_OBJS += pack-revindex.o\ndiff --git a/output-json.c b/output-json.c\nnew file mode 100644\nindex 0000000..0eb66b2\n--- /dev/null\n+++ b/output-json.c\n@@ -0,0 +1,128 @@\n+#include \"git-compat-util.h\"\n+#include \"output.h\"\n+#include \"strbuf.h\"\n+\n+static char *json_quote(char *s)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\twhile (*s) {\n+\t\tswitch (*s) {\n+\t\tcase '\"':\n+\t\t\tstrbuf_addstr(&buf, \"\\\\\\\"\");\n+\t\t\tbreak;\n+\t\tcase '\\\\':\n+\t\t\tstrbuf_addstr(&buf, \"\\\\\\\\\");\n+\t\t\tbreak;\n+\t\tcase '\\b':\n+\t\t\tstrbuf_addstr(&buf, \"\\\\b\");\n+\t\t\tbreak;\n+\t\tcase '\\f':\n+\t\t\tstrbuf_addstr(&buf, \"\\\\f\");\n+\t\t\tbreak;\n+\t\tcase '\\n':\n+\t\t\tstrbuf_addstr(&buf, \"\\\\n\");\n+\t\t\tbreak;\n+\t\tcase '\\r':\n+\t\t\tstrbuf_addstr(&buf, \"\\\\r\");\n+\t\t\tbreak;\n+\t\tcase '\\t':\n+\t\t\tstrbuf_addstr(&buf, \"\\\\t\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\t/* All control characters must be encode, even if they\n+\t\t\t * don't have a specific escape character of their own */\n+\t\t\tif (*s < 0x20)\n+\t\t\t\tstrbuf_addf(&buf, \"\\\\u%04x\", *s);\n+\t\t\telse\n+\t\t\t\tstrbuf_addch(&buf, *s);\n+\t\t\tbreak;\n+\t\t}\n+\t\ts++;\n+\t}\n+\n+\treturn strbuf_detach(&buf, NULL);\n+}\n+\n+static void json_obj_start(FILE *file, char *name)\n+{\n+\tfprintf(file, \"{\\n\");\n+}\n+\n+static void json_obj_end(FILE *file, char *name)\n+{\n+\tfprintf(file, \"\\n}\");\n+}\n+\n+static void json_obj_item_start(FILE *file, char *name, int first)\n+{\n+\tchar *quoted = json_quote(name);\n+\tif (!first)\n+\t\tfprintf(file, \",\\n\");\n+\tfprintf(file, \"\\\"%s\\\" : \", quoted);\n+\tfree(quoted);\n+}\n+\n+static void json_array_start(FILE *file, char *name)\n+{\n+\tfprintf(file, \"[\\n\");\n+}\n+\n+static void json_array_end(FILE *file, char *name)\n+{\n+\tfprintf(file, \"\\n]\");\n+}\n+\n+static void json_array_item_start(FILE *file, char *name, int first)\n+{\n+\tif (!first)\n+\t\tfprintf(file, \",\\n\");\n+}\n+\n+static void json_bool(FILE *file, int value)\n+{\n+\tif (value)\n+\t\tfprintf(file, \"true\");\n+\telse\n+\t\tfprintf(file, \"false\");\n+}\n+\n+static void json_str(FILE *file, char *value)\n+{\n+\tchar *quoted = json_quote(value);\n+\tfprintf(file, \"\\\"%s\\\"\", quoted);\n+\tfree(quoted);\n+}\n+\n+static void json_int(FILE *file, int64_t value)\n+{\n+\tfprintf(file, \"%lld\", value);\n+}\n+\n+static void json_uint(FILE *file, uint64_t value)\n+{\n+\tfprintf(file, \"%llu\", value);\n+}\n+\n+static void json_double(FILE *file, double value, int precision)\n+{\n+\tfprintf(file, \"%.*f\", precision, value);\n+}\n+\n+struct output_ops output_json_ops = {\n+\tjson_obj_start,\n+\tjson_obj_end,\n+\tjson_obj_item_start,\n+\tNULL,\n+\n+\tjson_array_start,\n+\tjson_array_end,\n+\tjson_array_item_start,\n+\tNULL,\n+\n+\tjson_bool,\n+\tjson_str,\n+\tjson_int,\n+\tjson_uint,\n+\tjson_double,\n+};\ndiff --git a/output-xml.c b/output-xml.c\nnew file mode 100644\nindex 0000000..50dd7d6\n--- /dev/null\n+++ b/output-xml.c\n@@ -0,0 +1,68 @@\n+#include \"git-compat-util.h\"\n+#include \"output.h\"\n+\n+static void xml_obj_start(FILE *file, char *name)\n+{\n+\tfprintf(file, \"<object name=\\\"%s\\\">\\n\", name);\n+}\n+\n+static void xml_obj_end(FILE *file, char *name)\n+{\n+\tfprintf(file, \"</object>\\n\");\n+}\n+\n+static void xml_obj_item_start(FILE *file, char *name, int first)\n+{\n+\tfprintf(file, \"<%s>\", name);\n+}\n+\n+static void xml_obj_item_end(FILE *file, char *name, int first)\n+{\n+\tfprintf(file, \"</%s>\\n\", name);\n+}\n+\n+static void xml_bool(FILE *file, int value)\n+{\n+\tif (value)\n+\t\tfprintf(file, \"true\");\n+\telse\n+\t\tfprintf(file, \"false\");\n+}\n+\n+static void xml_str(FILE *file, char *value)\n+{\n+\tfprintf(file, \"\\\"%s\\\"\", value);\n+}\n+\n+static void xml_int(FILE *file, int64_t value)\n+{\n+\tfprintf(file, \"%lld\", value);\n+}\n+\n+static void xml_uint(FILE *file, uint64_t value)\n+{\n+\tfprintf(file, \"%llu\", value);\n+}\n+\n+static void xml_double(FILE *file, double value, int precision)\n+{\n+\tfprintf(file, \"%.*f\", precision, value);\n+}\n+\n+struct output_ops output_xml_ops = {\n+\txml_obj_start,\n+\txml_obj_end,\n+\txml_obj_item_start,\n+\txml_obj_item_end,\n+\n+\tNULL,\n+\tNULL,\n+\tNULL,\n+\tNULL,\n+\n+\txml_bool,\n+\txml_str,\n+\txml_int,\n+\txml_uint,\n+\txml_double,\n+};\ndiff --git a/output.c b/output.c\nnew file mode 100644\nindex 0000000..305428c\n--- /dev/null\n+++ b/output.c\n@@ -0,0 +1,212 @@\n+#include \"git-compat-util.h\"\n+#include \"output.h\"\n+#include \"strbuf.h\"\n+\n+#define DEFAULT_OUTPUT_FORMAT OUTPUT_JSON\n+\n+extern struct output_ops output_json_ops;\n+extern struct output_ops output_xml_ops;\n+\n+struct output_ops *output_ops[] = {\n+\tNULL, /* OUTPUT_NORMAL */\n+\t&output_json_ops,\n+\t&output_xml_ops,\n+};\n+\n+enum output_style handle_output_arg(char *s)\n+{\n+\tif (!s)\n+\t\treturn OUTPUT_NORMAL;\n+\telse if (!strcmp(s, \"no\"))\n+\t\treturn OUTPUT_NORMAL;\n+\telse if (!strcmp(s, \"json\"))\n+\t\treturn OUTPUT_JSON;\n+\telse if (!strcmp(s, \"xml\"))\n+\t\treturn OUTPUT_XML;\n+\telse\n+\t\tdie(\"Invalid output style '%s'\", s);\n+}\n+\n+char *output_supported_styles()\n+{\n+\treturn \"\";\n+}\n+\n+struct output_context *output_start(enum output_style style)\n+{\n+\tstruct output_context *context = xmallocz(sizeof(*context));\n+\n+\tcontext->style = style;\n+\tcontext->file = stdout;\n+\tcontext->ops = output_ops[style];\n+\n+\toutput_start_object(context, \"git\");\n+\n+\treturn context;\n+}\n+\n+void output_end(struct output_context *context)\n+{\n+\twhile(context->current)\n+\t\toutput_end_current(context);\n+\n+\tfprintf(context->file, \"\\n\");\n+\n+\tfree(context);\n+}\n+\n+\n+static void item_start(struct output_context *context, char *name)\n+{\n+\tif (!context->current)\n+\t\treturn;\n+\n+\tswitch (context->current->type) {\n+\tcase OUTPUT_ITEM_OBJECT:\n+\t\tif (context->ops->obj_item_start)\n+\t\t\tcontext->ops->obj_item_start(context->file, name,\n+\t\t\t\t\t\t     context->current->first);\n+\t\tbreak;\n+\tcase OUTPUT_ITEM_ARRAY:\n+\t\tif (context->ops->array_item_start)\n+\t\t\tcontext->ops->array_item_start(context->file, name,\n+\t\t\t\t\t\t       context->current->first);\n+\t\tbreak;\n+\t}\n+}\n+\n+static void item_end(struct output_context *context, char *name)\n+{\n+\tif (!context->current)\n+\t\treturn;\n+\n+\tswitch (context->current->type) {\n+\tcase OUTPUT_ITEM_OBJECT:\n+\t\tif (context->ops->obj_item_end)\n+\t\t\tcontext->ops->obj_item_end(context->file, name,\n+\t\t\t\t\t\t   context->current->first);\n+\t\tbreak;\n+\tcase OUTPUT_ITEM_ARRAY:\n+\t\tif (context->ops->array_item_end)\n+\t\t\tcontext->ops->array_item_end(context->file, name,\n+\t\t\t\t\t\t     context->current->first);\n+\t\tbreak;\n+\t}\n+\n+\tcontext->current->first = 0;\n+}\n+\n+\n+void output_new_current(struct output_context *context, char *name,\n+\t\t\tenum output_item_type type)\n+{\n+\tstruct output_item *item = xmallocz(sizeof(*item));\n+\n+\titem->name = xstrdup(name);\n+\titem->type = type;\n+\titem->first = 1;\n+\n+\titem->prev = context->current;\n+\tcontext->current = item;\n+}\n+\n+void output_start_object(struct output_context *context, char *name)\n+{\n+\titem_start(context, name);\n+\n+\toutput_new_current(context, name, OUTPUT_ITEM_OBJECT);\n+\n+\tif (context->ops->obj_start)\n+\t\tcontext->ops->obj_start(context->file, name);\n+}\n+\n+void output_start_array(struct output_context *context, char *name)\n+{\n+\titem_start(context, name);\n+\n+\toutput_new_current(context, name, OUTPUT_ITEM_ARRAY);\n+\n+\tif (context->ops->array_start)\n+\t\tcontext->ops->array_start(context->file, name);\n+}\n+\n+void output_end_current(struct output_context *context)\n+{\n+\tstruct output_item *item = context->current;\n+\n+\tswitch (item->type) {\n+\tcase OUTPUT_ITEM_OBJECT:\n+\t\tif (context->ops->obj_end)\n+\t\t\tcontext->ops->obj_end(context->file, item->name);\n+\t\tbreak;\n+\tcase OUTPUT_ITEM_ARRAY:\n+\t\tif (context->ops->array_end)\n+\t\t\tcontext->ops->array_end(context->file, item->name);\n+\t\tbreak;\n+\t}\n+\n+\titem = context->current;\n+\tcontext->current = context->current->prev;\n+\n+\titem_end(context, item->name);\n+\n+\tfree(item->name);\n+\tfree(item);\n+}\n+\n+\n+void output_bool(struct output_context *context, char *name, int value)\n+{\n+\titem_start(context, name);\n+\tif (context->ops->bool)\n+\t\tcontext->ops->bool(context->file, value);\n+\titem_end(context, name);\n+}\n+\n+void output_str(struct output_context *context, char *name, char *value)\n+{\n+\titem_start(context, name);\n+\tif (context->ops->str)\n+\t\tcontext->ops->str(context->file, value);\n+\titem_end(context, name);\n+}\n+\n+void output_strf(struct output_context *context, char *name, char *fmt, ...)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tva_list ap;\n+\n+\tva_start(ap, fmt);\n+\tstrbuf_vaddf(&buf, fmt, ap);\n+\tva_end(ap);\n+\n+\toutput_str(context, name, buf.buf);\n+\n+\tstrbuf_release(&buf);\n+}\n+\n+void output_int(struct output_context *context, char *name, int64_t value)\n+{\n+\titem_start(context, name);\n+\tif (context->ops->int_)\n+\t\tcontext->ops->int_(context->file, value);\n+\titem_end(context, name);\n+}\n+\n+void output_uint(struct output_context *context, char *name, uint64_t value)\n+{\n+\titem_start(context, name);\n+\tif (context->ops->uint)\n+\t\tcontext->ops->uint(context->file, value);\n+\titem_end(context, name);\n+}\n+\n+void output_double(struct output_context *context, char *name, double value,\n+\t\t   int precision)\n+{\n+\titem_start(context, name);\n+\tif (context->ops->double_)\n+\t\tcontext->ops->double_(context->file, value, precision);\n+\titem_end(context, name);\n+}\n+\ndiff --git a/output.h b/output.h\nnew file mode 100644\nindex 0000000..9472ae4\n--- /dev/null\n+++ b/output.h\n@@ -0,0 +1,71 @@\n+#ifndef OUTPUT_H\n+#define OUTPUT_H\n+\n+enum output_style {\n+\tOUTPUT_NORMAL,\n+\tOUTPUT_JSON,\n+\tOUTPUT_XML,\n+};\n+\n+struct output_ops {\n+\tvoid (*obj_start)(FILE *file, char *name);\n+\tvoid (*obj_end)(FILE *file, char *name);\n+\tvoid (*obj_item_start)(FILE *file, char *name, int first);\n+\tvoid (*obj_item_end)(FILE *file, char *name, int first);\n+\n+\tvoid (*array_start)(FILE *file, char *name);\n+\tvoid (*array_end)(FILE *file, char *name);\n+\tvoid (*array_item_start)(FILE *file, char *name, int first);\n+\tvoid (*array_item_end)(FILE *file, char *name, int first);\n+\n+\tvoid (*bool)(FILE *file, int value);\n+\tvoid (*str)(FILE *file, char *value);\n+\tvoid (*int_)(FILE *file, int64_t value);\n+\tvoid (*uint)(FILE *file, uint64_t value);\n+\tvoid (*double_)(FILE *file, double value, int precision);\n+};\n+\n+enum output_item_type {\n+\tOUTPUT_ITEM_OBJECT,\n+\tOUTPUT_ITEM_ARRAY,\n+};\n+\n+struct output_item {\n+\tstruct output_item *prev;\n+\tchar *name;\n+\tenum output_item_type type;\n+\tint first;\n+};\n+\n+struct output_context {\n+\tenum output_style style;\n+\tFILE *file;\n+\tstruct output_ops *ops;\n+\tstruct output_item *current;\n+};\n+\n+extern struct option OUTPUT_OPTION;\n+\n+#define OPT_OUTPUT(s, l, v) { OPTION_STRING, (s), (l), (v), \"style\",     \\\n+\t\t\t      \"Use a structured output style, options: \" \\\n+\t\t\t      \"no, json, xml (Default: no)\",             \\\n+\t\t\t      PARSE_OPT_OPTARG, NULL, (intptr_t)\"no\" }\n+\n+enum output_style handle_output_arg(char *s);\n+\n+struct output_context *output_start(enum output_style style);\n+void output_end(struct output_context *context);\n+\n+void output_start_object(struct output_context *context, char *name);\n+void output_start_array(struct output_context *context, char *name);\n+void output_end_current(struct output_context *context);\n+\n+void output_bool(struct output_context *context, char *name, int value);\n+void output_str(struct output_context *context, char *name, char *value);\n+void output_strf(struct output_context *context, char *name, char *fmt, ...);\n+void output_int(struct output_context *context, char *name, int64_t value);\n+void output_uint(struct output_context *context, char *name, uint64_t value);\n+void output_double(struct output_context *context, char *name, double value,\n+\t\t   int precision);\n+\n+#endif /* OUTPUT_H */\n-- \n1.7.0.4\n"},{"id":"139245","messageId":"20100411113733.80010.87627.julian@quantumfyre.co.uk","threadId":"23420","inReplyTo":"20100411112928.80010.1786.julian@quantumfyre.co.uk","subject":"[RFC/PATCH 3/3] status: add support for structured output","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T11:37:32Z","receivedAt":"2010-04-11T11:37:32Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"Add support for using the new structured output modes for outputting\nstatus information.\n\nSigned-off-by: Julian Phillips <julian@quantumfyre.co.uk>\n---\n builtin/commit.c |   12 +++++++++\n wt-status.c      |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n wt-status.h      |    2 +\n 3 files changed, 87 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex c5ab683..77464d3 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -25,6 +25,7 @@\n #include \"rerere.h\"\n #include \"unpack-trees.h\"\n #include \"quote.h\"\n+#include \"output.h\"\n \n static const char * const builtin_commit_usage[] = {\n \t\"git commit [options] [--] <filepattern>...\",\n@@ -68,6 +69,7 @@ static int all, edit_flag, also, interactive, only, amend, signoff;\n static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n static int no_post_rewrite;\n static char *untracked_files_arg, *force_date;\n+static char *structured_output_arg;\n /*\n  * The default commit message cleanup mode will remove the lines\n  * beginning with # (shell comments) and leading and trailing\n@@ -91,6 +93,7 @@ static enum {\n \tSTATUS_FORMAT_LONG,\n \tSTATUS_FORMAT_SHORT,\n \tSTATUS_FORMAT_PORCELAIN,\n+\tSTATUS_FORMAT_STRUCTURED,\n } status_format = STATUS_FORMAT_LONG;\n \n static int opt_parse_m(const struct option *opt, const char *arg, int unset)\n@@ -1018,6 +1021,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n {\n \tstruct wt_status s;\n \tunsigned char sha1[20];\n+\tenum output_style output_style;\n \tstatic struct option builtin_status_options[] = {\n \t\tOPT__VERBOSE(&verbose),\n \t\tOPT_SET_INT('s', \"short\", &status_format,\n@@ -1031,6 +1035,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\t  \"mode\",\n \t\t  \"show untracked files, optional modes: all, normal, no. (Default: all)\",\n \t\t  PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n+\t\tOPT_OUTPUT(0, \"structured-output\", &structured_output_arg),\n \t\tOPT_END(),\n \t};\n \n@@ -1045,6 +1050,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t\t\t     builtin_status_usage, 0);\n \thandle_untracked_files_arg(&s);\n \n+\toutput_style = handle_output_arg(structured_output_arg);\n+\tif (output_style != OUTPUT_NORMAL)\n+\t\tstatus_format = STATUS_FORMAT_STRUCTURED;\n+\n \tif (*argv)\n \t\ts.pathspec = get_pathspec(prefix, argv);\n \n@@ -1068,6 +1077,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \tcase STATUS_FORMAT_PORCELAIN:\n \t\twt_porcelain_print(&s, null_termination);\n \t\tbreak;\n+\tcase STATUS_FORMAT_STRUCTURED:\n+\t\twt_structured_print(&s, output_style);\n+\t\tbreak;\n \tcase STATUS_FORMAT_LONG:\n \t\ts.verbose = verbose;\n \t\twt_status_print(&s);\ndiff --git a/wt-status.c b/wt-status.c\nindex 8ca59a2..162f719 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -750,3 +750,76 @@ void wt_porcelain_print(struct wt_status *s, int null_termination)\n \ts->prefix = NULL;\n \twt_shortstatus_print(s, null_termination);\n }\n+\n+static void wt_structured_unmerged(struct string_list_item *it,\n+\t\t\t\t   struct output_context *oc)\n+{\n+\tstruct wt_status_change_data *d = it->util;\n+\tchar *ours = \"?\", *theirs = \"?\";\n+\n+\tswitch (d->stagemask) {\n+\tcase 1: ours = \"D\"; theirs = \"D\"; break; /* both deleted */\n+\tcase 2: ours = \"A\"; theirs = \"U\"; break; /* added by us */\n+\tcase 3: ours = \"U\"; theirs = \"D\"; break; /* deleted by them */\n+\tcase 4: ours = \"U\"; theirs = \"A\"; break; /* added by them */\n+\tcase 5: ours = \"D\"; theirs = \"U\"; break; /* deleted by us */\n+\tcase 6: ours = \"A\"; theirs = \"A\"; break; /* both added */\n+\tcase 7: ours = \"U\"; theirs = \"U\"; break; /* both modified */\n+\t}\n+\n+\toutput_start_object(oc, \"entry\");\n+\toutput_str(oc, \"name\", it->string);\n+\toutput_str(oc, \"ours\", ours);\n+\toutput_str(oc, \"theirs\", theirs);\n+\toutput_end_current(oc);\n+}\n+\n+static void wt_structured_status(struct string_list_item *it,\n+\t\t\t\t struct output_context *oc)\n+{\n+\tstruct wt_status_change_data *d = it->util;\n+\tchar index = '-', worktree = '-';\n+\n+\tif (d->index_status)\n+\t\tindex = d->index_status;\n+\tif (d->worktree_status)\n+\t\tworktree = d->worktree_status;\n+\n+\toutput_start_object(oc, \"entry\");\n+\toutput_str(oc, \"name\", it->string);\n+\tif (d->head_path)\n+\t\toutput_str(oc, \"orig_name\", d->head_path);\n+\toutput_strf(oc, \"index\", \"%c\", index);\n+\toutput_strf(oc, \"worktree\", \"%c\", worktree);\n+\toutput_end_current(oc);\n+}\n+\n+void wt_structured_print(struct wt_status *s, enum output_style style)\n+{\n+\tint i;\n+\tstruct output_context *oc = output_start(style);\n+\n+\toutput_start_array(oc, \"entries\");\n+\n+\tfor (i = 0; i < s->change.nr; i++) {\n+\t\tstruct wt_status_change_data *d;\n+\t\tstruct string_list_item *it;\n+\n+\t\tit = &(s->change.items[i]);\n+\t\td = it->util;\n+\t\tif (d->stagemask)\n+\t\t\twt_structured_unmerged(it, oc);\n+\t\telse\n+\t\t\twt_structured_status(it, oc);\n+\t}\n+\n+\tfor (i = 0; i < s->untracked.nr; i++) {\n+\t\toutput_start_object(oc, \"entry\");\n+\t\toutput_str(oc, \"name\", s->untracked.items[i].string);\n+\t\toutput_str(oc, \"index\", \"?\");\n+\t\toutput_str(oc, \"worktree\", \"?\");\n+\t\toutput_end_current(oc);\n+\t}\n+\n+\toutput_end(oc);\n+}\ndiff --git a/wt-status.h b/wt-status.h\nindex 9120673..d5b1342 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -4,6 +4,7 @@\n #include <stdio.h>\n #include \"string-list.h\"\n #include \"color.h\"\n+#include \"output.h\"\n \n enum color_wt_status {\n \tWT_STATUS_HEADER = 0,\n@@ -61,5 +62,6 @@ void wt_status_collect(struct wt_status *s);\n \n void wt_shortstatus_print(struct wt_status *s, int null_termination);\n void wt_porcelain_print(struct wt_status *s, int null_termination);\n+void wt_structured_print(struct wt_status *s, enum output_style style);\n \n #endif /* STATUS_H */\n-- \n1.7.0.4\n"},{"id":"139248","messageId":"n2i40aa078e1004110542kcfba8b6dw8848cd8f5647fda7@mail.gmail.com","threadId":"23420","inReplyTo":"20100411113733.80010.78232.julian@quantumfyre.co.uk","subject":"Re: [RFC/PATCH 1/3] strbuf: Add strbuf_vaddf function","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@googlemail.com","sentAt":"2010-04-11T12:42:29Z","receivedAt":"2010-04-11T12:42:29Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Sun, Apr 11, 2010 at 1:37 PM, Julian Phillips\n<julian@quantumfyre.co.uk> wrote:\n> Add strbuf_vaddf which is to strbuf_addf as vprintf is to printf.\n>\n> Signed-off-by: Julian Phillips <julian@quantumfyre.co.uk>\n> ---\n>  strbuf.c |   13 +++++++++++--\n>  strbuf.h |    1 +\n>  2 files changed, 12 insertions(+), 2 deletions(-)\n>\n> diff --git a/strbuf.c b/strbuf.c\n> index bc3a080..8f312f8 100644\n> --- a/strbuf.c\n> +++ b/strbuf.c\n> @@ -194,19 +194,28 @@ void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)\n>\n>  void strbuf_addf(struct strbuf *sb, const char *fmt, ...)\n>  {\n> +       va_list ap;\n> +\n> +       va_start(ap, fmt);\n> +        strbuf_vaddf(sb, fmt, ap);\n> +       va_end(ap);\n> +}\n> +\n> +void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list args)\n> +{\n>        int len;\n>        va_list ap;\n>\n>        if (!strbuf_avail(sb))\n>                strbuf_grow(sb, 64);\n> -       va_start(ap, fmt);\n> +       va_copy(ap, args);\n\nIsn't va_copy C99? The only other place we use this is in\ncompat/winansi.c, but that file is only compiled on Windows. Both\ncompilers we support on Windows supports va_copy (or some way of\nemulating it).\n\nIIRC, strbuf_vaddf() has been attempted added multiple times before\n(by me, for one), and the efforts have always ended up being scrapped\ndue to the lack of a portable va_copy.\n\n-- \nErik \"kusma\" Faye-Lund\n"},{"id":"139249","messageId":"g2z40aa078e1004110551s98e34b74w66c5bcc49538ca45@mail.gmail.com","threadId":"23420","inReplyTo":"20100411113733.80010.3767.julian@quantumfyre.co.uk","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Erik Faye-Lund","fromEmail":"kusmabite@googlemail.com","sentAt":"2010-04-11T12:51:37Z","receivedAt":"2010-04-11T12:51:37Z","isPatch":true,"sender":{"key":"kusmabite@gmail.com","avatar":"https://avatars.githubusercontent.com/u/47073?v=4"},"body":"On Sun, Apr 11, 2010 at 1:37 PM, Julian Phillips\n<julian@quantumfyre.co.uk> wrote:\n> Add a library that allows commands to produce structured output in any\n> of a range of formats using a single API.\n>\n> The API includes an OPT_OUTPUT and handle_output_arg so that the\n> option handling for different commands will be as similar as possible.\n>\n> At the moment JSON and XML output options are available - though the\n> XML output is _very_ rudimentary.\n>\n> Signed-off-by: Julian Phillips <julian@quantumfyre.co.uk>\n> ---\n>  Makefile      |    3 +\n>  output-json.c |  128 ++++++++++++++++++++++++++++++++++\n>  output-xml.c  |   68 ++++++++++++++++++\n>  output.c      |  212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  output.h      |   71 +++++++++++++++++++\n>  5 files changed, 482 insertions(+), 0 deletions(-)\n>  create mode 100644 output-json.c\n>  create mode 100644 output-xml.c\n>  create mode 100644 output.c\n>  create mode 100644 output.h\n>\n> diff --git a/Makefile b/Makefile\n> index 910f471..4ba2a4f 100644\n> --- a/Makefile\n> +++ b/Makefile\n> @@ -576,6 +576,9 @@ LIB_OBJS += merge-recursive.o\n>  LIB_OBJS += name-hash.o\n>  LIB_OBJS += notes.o\n>  LIB_OBJS += object.o\n> +LIB_OBJS += output.o\n> +LIB_OBJS += output-json.o\n> +LIB_OBJS += output-xml.o\n>  LIB_OBJS += pack-check.o\n>  LIB_OBJS += pack-refs.o\n>  LIB_OBJS += pack-revindex.o\n> diff --git a/output-json.c b/output-json.c\n> new file mode 100644\n> index 0000000..0eb66b2\n> --- /dev/null\n> +++ b/output-json.c\n> @@ -0,0 +1,128 @@\n> <snip>\n> +\n> +static void json_str(FILE *file, char *value)\n> +{\n> +       char *quoted = json_quote(value);\n> +       fprintf(file, \"\\\"%s\\\"\", quoted);\n> +       free(quoted);\n> +}\n> +\n> <snip>\n> diff --git a/output-xml.c b/output-xml.c\n> new file mode 100644\n> index 0000000..50dd7d6\n> --- /dev/null\n> +++ b/output-xml.c\n> @@ -0,0 +1,68 @@\n> <snip>\n> +\n> +static void xml_str(FILE *file, char *value)\n> +{\n> +       fprintf(file, \"\\\"%s\\\"\", value);\n> +}\n> +\n\nDon't you need to quote this one, like you did in json_str()?\n\n-- \nErik \"kusma\" Faye-Lund\n"},{"id":"139250","messageId":"2668f8f72053fad18f62033e82767b75@212.159.54.234","threadId":"23420","inReplyTo":"n2i40aa078e1004110542kcfba8b6dw8848cd8f5647fda7@mail.gmail.com","subject":"Re: [RFC/PATCH 1/3] strbuf: Add strbuf_vaddf function","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T12:59:15Z","receivedAt":"2010-04-11T12:59:15Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"On Sun, 11 Apr 2010 14:42:29 +0200, Erik Faye-Lund\n<kusmabite@googlemail.com> wrote:\n> On Sun, Apr 11, 2010 at 1:37 PM, Julian Phillips\n> <julian@quantumfyre.co.uk> wrote:\n>> +void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list args)\n>> +{\n>>        int len;\n>>        va_list ap;\n>>\n>>        if (!strbuf_avail(sb))\n>>                strbuf_grow(sb, 64);\n>> -       va_start(ap, fmt);\n>> +       va_copy(ap, args);\n> \n> Isn't va_copy C99?\n\nIndeed.\n\nHi ho, hi ho, It's off to a custom implementation I go ...\n\nHo hum.  \n\n-- \nJulian\n"},{"id":"139251","messageId":"df8300572068e1da19ac8905a3ecaee4@212.159.54.234","threadId":"23420","inReplyTo":"g2z40aa078e1004110551s98e34b74w66c5bcc49538ca45@mail.gmail.com","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T13:03:38Z","receivedAt":"2010-04-11T13:03:38Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"On Sun, 11 Apr 2010 14:51:37 +0200, Erik Faye-Lund\n<kusmabite@googlemail.com> wrote:\n> On Sun, Apr 11, 2010 at 1:37 PM, Julian Phillips\n> <julian@quantumfyre.co.uk> wrote:\n>> Add a library that allows commands to produce structured output in any\n>> of a range of formats using a single API.\n>>\n>> The API includes an OPT_OUTPUT and handle_output_arg so that the\n>> option handling for different commands will be as similar as possible.\n>>\n>> At the moment JSON and XML output options are available - though the\n>> XML output is _very_ rudimentary.\n>>\n>> Signed-off-by: Julian Phillips <julian@quantumfyre.co.uk>\n>> ---\n>>  Makefile      |    3 +\n>>  output-json.c |  128 ++++++++++++++++++++++++++++++++++\n>>  output-xml.c  |   68 ++++++++++++++++++\n>>  output.c      |  212\n>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>>  output.h      |   71 +++++++++++++++++++\n>>  5 files changed, 482 insertions(+), 0 deletions(-)\n>>  create mode 100644 output-json.c\n>>  create mode 100644 output-xml.c\n>>  create mode 100644 output.c\n>>  create mode 100644 output.h\n>>\n>> diff --git a/Makefile b/Makefile\n>> index 910f471..4ba2a4f 100644\n>> --- a/Makefile\n>> +++ b/Makefile\n>> @@ -576,6 +576,9 @@ LIB_OBJS += merge-recursive.o\n>>  LIB_OBJS += name-hash.o\n>>  LIB_OBJS += notes.o\n>>  LIB_OBJS += object.o\n>> +LIB_OBJS += output.o\n>> +LIB_OBJS += output-json.o\n>> +LIB_OBJS += output-xml.o\n>>  LIB_OBJS += pack-check.o\n>>  LIB_OBJS += pack-refs.o\n>>  LIB_OBJS += pack-revindex.o\n>> diff --git a/output-json.c b/output-json.c\n>> new file mode 100644\n>> index 0000000..0eb66b2\n>> --- /dev/null\n>> +++ b/output-json.c\n>> @@ -0,0 +1,128 @@\n>> <snip>\n>> +\n>> +static void json_str(FILE *file, char *value)\n>> +{\n>> +       char *quoted = json_quote(value);\n>> +       fprintf(file, \"\\\"%s\\\"\", quoted);\n>> +       free(quoted);\n>> +}\n>> +\n>> <snip>\n>> diff --git a/output-xml.c b/output-xml.c\n>> new file mode 100644\n>> index 0000000..50dd7d6\n>> --- /dev/null\n>> +++ b/output-xml.c\n>> @@ -0,0 +1,68 @@\n>> <snip>\n>> +\n>> +static void xml_str(FILE *file, char *value)\n>> +{\n>> +       fprintf(file, \"\\\"%s\\\"\", value);\n>> +}\n>> +\n> \n> Don't you need to quote this one, like you did in json_str()?\n\nYes.  That would be part of the reason for the \"_very_\" in the comment ...\n\nAs it stands the XML code is more of an example of a second output format\nthan actually usable.  However, since I envision that the frontend/backend\nAPI probably needs tweaking to accommodate backends other than JSON I\nwanted to get at least one other backend going ...\n\n-- \nJulian\n"},{"id":"139255","messageId":"m3bpdqgfha.fsf@localhost.localdomain","threadId":"23420","inReplyTo":"20100411113733.80010.3767.julian@quantumfyre.co.uk","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2010-04-11T15:46:46Z","receivedAt":"2010-04-11T15:46:46Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Julian Phillips <julian@quantumfyre.co.uk> writes:\n\n> Add a library that allows commands to produce structured output in any\n> of a range of formats using a single API.\n> \n> The API includes an OPT_OUTPUT and handle_output_arg so that the\n> option handling for different commands will be as similar as possible.\n> \n> At the moment JSON and XML output options are available - though the\n> XML output is _very_ rudimentary.\n> \n> Signed-off-by: Julian Phillips <julian@quantumfyre.co.uk>\n> ---\n>  Makefile      |    3 +\n>  output-json.c |  128 ++++++++++++++++++++++++++++++++++\n>  output-xml.c  |   68 ++++++++++++++++++\n>  output.c      |  212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n>  output.h      |   71 +++++++++++++++++++\n>  5 files changed, 482 insertions(+), 0 deletions(-)\n>  create mode 100644 output-json.c\n>  create mode 100644 output-xml.c\n>  create mode 100644 output.c\n>  create mode 100644 output.h\n\nHow about some technical documentation, in the form of\nDocumentation/technical/api-structured-output.txt (or something like\nthat), describing how this API should be used.\n\nHow about some tests?  Note that you need to take care of commits that\nare encoded in encoding other than utf-8 (but with 'encoding' header,\nso you know what encoding it is), and of filenames that are invalid\nUTF-8 (and their encoding is unknown in general: they are raw binary\ndata).  You need to take care of non-ASCII characters, and of special\ncharacters (like '\"', SPC, TAB, LF, '\\') in commits and in filenames.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"139256","messageId":"k2pfabb9a1e1004110848u15859465qf14e3d40eb4ba877@mail.gmail.com","threadId":"23420","inReplyTo":"20100411112928.80010.1786.julian@quantumfyre.co.uk","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-04-11T15:48:28Z","receivedAt":"2010-04-11T15:48:28Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sun, Apr 11, 2010 at 13:37, Julian Phillips <julian@quantumfyre.co.uk> wrote:\n> Here is an attempt at making a format agnostic structured output library.  The\n> idea being that the command doing the output doesn't have to care what the\n> actual output format is, it just uses the abstract notion of objects and arrays.\n\nHow easy is it to add support for this to other commands using the\ninfrastructure this command adds? I assume that we'd want to do this\nfor all/most plumbing commands, so I think it's important that we make\nsure it's easy to add for other commands other than 'git status', no?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"139264","messageId":"cb4ed5763e71bd84b4e80109923494ca@212.159.54.234","threadId":"23420","inReplyTo":"k2pfabb9a1e1004110848u15859465qf14e3d40eb4ba877@mail.gmail.com","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T17:30:58Z","receivedAt":"2010-04-11T17:30:58Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"On Sun, 11 Apr 2010 17:48:28 +0200, Sverre Rabbelier\n<srabbelier@gmail.com>\nwrote:\n> Heya,\n> \n> On Sun, Apr 11, 2010 at 13:37, Julian Phillips\n<julian@quantumfyre.co.uk>\n> wrote:\n>> Here is an attempt at making a format agnostic structured output\n>> library.  The\n>> idea being that the command doing the output doesn't have to care what\n>> the\n>> actual output format is, it just uses the abstract notion of objects\nand\n>> arrays.\n> \n> How easy is it to add support for this to other commands using the\n> infrastructure this command adds? I assume that we'd want to do this\n> for all/most plumbing commands, so I think it's important that we make\n> sure it's easy to add for other commands other than 'git status', no?\n\nIt's intended to be easy, as the intention was to make the structured\noutput available from all plumbing commands (and maybe even some porcelain\ncommands, if they are often scripted?).  Easy is in the eye of the beholder\nthough.  I've done ls-tree as an example below (I expect my MUA will\nprobably mangle the patch - sorry).  I didn't think it was too hard, but\nthat's not really surprising since I wrote the API ... you'll have to tell\nme what you think.\n\ndiff --git a/builtin/ls-tree.c b/builtin/ls-tree.c\nindex dc86b0d..7b5a5e8 100644\n--- a/builtin/ls-tree.c\n+++ b/builtin/ls-tree.c\n@@ -10,6 +10,7 @@\n #include \"quote.h\"\n #include \"builtin.h\"\n #include \"parse-options.h\"\n+#include \"output.h\"\n \n static int line_termination = '\\n';\n #define LS_RECURSIVE 1\n@@ -22,6 +23,7 @@ static int ls_options;\n static const char **pathspec;\n static int chomp_prefix;\n static const char *ls_tree_prefix;\n+static struct output_context *oc;\n \n static const  char * const ls_tree_usage[] = {\n \t\"git ls-tree [<options>] <tree-ish> [path...]\",\n@@ -90,6 +92,25 @@ static int show_tree(const unsigned char *sha1, const\nchar *base, int baselen,\n \t    (baselen < chomp_prefix || memcmp(ls_tree_prefix, base,\nchomp_prefix)))\n \t\treturn 0;\n \n+\tif (oc != NULL) {\n+\t\toutput_start_object(oc, \"entry\");\n+\t\toutput_strf(oc, \"path\", \"%s%s\", base + chomp_prefix, pathname);\n+\t\tif (!(ls_options & LS_NAME_ONLY)) {\n+\t\t\toutput_strf(oc, \"mode\", \"%06o\", mode);\n+\t\t\toutput_str(oc, \"type\", type);\n+\t\t\toutput_str(oc, \"hash\", sha1_to_hex(sha1));\n+\t\t\tif ((ls_options & LS_SHOW_SIZE) && !strcmp(type, blob_type)) {\n+\t\t\t\tunsigned long size;\n+\t\t\t\tif (sha1_object_info(sha1, &size) == OBJ_BAD)\n+\t\t\t\t\toutput_str(oc, \"size\", \"bad\");\n+\t\t\t\telse\n+\t\t\t\t\toutput_uint(oc, \"size\", size);\n+\t\t\t}\n+\t\t}\n+\t\toutput_end_current(oc);\n+\t\treturn retval;\n+\t}\n+\n \tif (!(ls_options & LS_NAME_ONLY)) {\n \t\tif (ls_options & LS_SHOW_SIZE) {\n \t\t\tchar size_text[24];\n@@ -119,6 +140,8 @@ int cmd_ls_tree(int argc, const char **argv, const\nchar *prefix)\n \tunsigned char sha1[20];\n \tstruct tree *tree;\n \tint full_tree = 0;\n+\tchar *structured_output_arg = NULL;\n+\tenum output_style output_style;\n \tconst struct option ls_tree_options[] = {\n \t\tOPT_BIT('d', NULL, &ls_options, \"only show trees\",\n \t\t\tLS_TREE_ONLY),\n@@ -140,6 +163,7 @@ int cmd_ls_tree(int argc, const char **argv, const\nchar *prefix)\n \t\t\t    \"list entire tree; not just current directory \"\n \t\t\t    \"(implies --full-name)\"),\n \t\tOPT__ABBREV(&abbrev),\n+\t\tOPT_OUTPUT(0, \"structured-output\", &structured_output_arg),\n \t\tOPT_END()\n \t};\n \n@@ -159,6 +183,8 @@ int cmd_ls_tree(int argc, const char **argv, const\nchar *prefix)\n \t    ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))\n \t\tls_options |= LS_SHOW_TREES;\n \n+\toutput_style = handle_output_arg(structured_output_arg);\n+\n \tif (argc < 1)\n \t\tusage_with_options(ls_tree_usage, ls_tree_options);\n \tif (get_sha1(argv[0], sha1))\n@@ -168,7 +194,16 @@ int cmd_ls_tree(int argc, const char **argv, const\nchar *prefix)\n \ttree = parse_tree_indirect(sha1);\n \tif (!tree)\n \t\tdie(\"not a tree object\");\n+\n+\tif (output_style != OUTPUT_NORMAL) {\n+\t\toc = output_start(output_style);\n+\t\toutput_start_array(oc, \"entries\");\n+\t}\n+\n \tread_tree_recursive(tree, \"\", 0, 0, pathspec, show_tree, NULL);\n \n+\tif (output_style != OUTPUT_NORMAL)\n+\t\toutput_end(oc);\n+\n \treturn 0;\n }\n\n\n-- \nJulian\n"},{"id":"139266","messageId":"w2lfabb9a1e1004111034n1aec73f2h3cf5f1d8468b6036@mail.gmail.com","threadId":"23420","inReplyTo":"cb4ed5763e71bd84b4e80109923494ca@212.159.54.234","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-04-11T17:34:13Z","receivedAt":"2010-04-11T17:34:13Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sun, Apr 11, 2010 at 19:30, Julian Phillips <julian@quantumfyre.co.uk> wrote:\n> you'll have to tell me what you think.\n\nThe patch does look fairly simple, but I worry that not all commands\nwill be so simple, that is, they might not all have such an easy point\nwhere you can hook in a different output method? Or am I seeing bears\nwhere there are none?\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"139268","messageId":"d0869259b375a26df46ef92a2b973615@212.159.54.234","threadId":"23420","inReplyTo":"w2lfabb9a1e1004111034n1aec73f2h3cf5f1d8468b6036@mail.gmail.com","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T17:45:52Z","receivedAt":"2010-04-11T17:45:52Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"On Sun, 11 Apr 2010 19:34:13 +0200, Sverre Rabbelier\n<srabbelier@gmail.com>\nwrote:\n> Heya,\n> \n> On Sun, Apr 11, 2010 at 19:30, Julian Phillips\n<julian@quantumfyre.co.uk>\n> wrote:\n>> you'll have to tell me what you think.\n> \n> The patch does look fairly simple, but I worry that not all commands\n> will be so simple, that is, they might not all have such an easy point\n> where you can hook in a different output method? Or am I seeing bears\n> where there are none?\n\nI think that there probably are commands where it will be more work to\nintegrate the output - but I think that is probably more to do with the\nstructure of the current code than the API of the new.  Does it make a\ndifference what the API of the new output code is if there isn't currently\na sensible hook-in point?\n\nIf code has been written without the expectation that the output format\ncould be changed then the effort to add a new output format could be\nconsiderably more than for status or ls-tree.  However, with the\nfrontend/backend design hopefully we only have to endure the effort once to\nget multiple output formats.\n\n-- \nJulian\n"},{"id":"139271","messageId":"p2ofabb9a1e1004111050x660c37fdke4d5316baaa0cfbe@mail.gmail.com","threadId":"23420","inReplyTo":"d0869259b375a26df46ef92a2b973615@212.159.54.234","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-04-11T17:50:29Z","receivedAt":"2010-04-11T17:50:29Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sun, Apr 11, 2010 at 19:45, Julian Phillips <julian@quantumfyre.co.uk> wrote:\n> I think that there probably are commands where it will be more work to\n> integrate the output - but I think that is probably more to do with the\n> structure of the current code than the API of the new.  Does it make a\n> difference what the API of the new output code is if there isn't currently\n> a sensible hook-in point?\n\nNo you are right, the existance of such hard-to-change commands does\nnot really affect the API design in this case, although I think it\nmight be a good idea to try out at least one such command before\ncommitting to using this API. For example, it might turn out that\nthere's an elegant way to hook in, or that adding all those if\n(output_style != OUTPUT_NORMAL)  statements gets cluttery and there\nshould be a different way to do things instead.\n\n> If code has been written without the expectation that the output format\n> could be changed then the effort to add a new output format could be\n> considerably more than for status or ls-tree.  However, with the\n> frontend/backend design hopefully we only have to endure the effort once to\n> get multiple output formats.\n\nI'm curious to see where this will lead us :).\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"139277","messageId":"7vy6gtonwt.fsf@alter.siamese.dyndns.org","threadId":"23420","inReplyTo":"20100411113733.80010.3767.julian@quantumfyre.co.uk","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-04-11T18:16:18Z","receivedAt":"2010-04-11T18:16:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Julian Phillips <julian@quantumfyre.co.uk> writes:\n\n> Add a library that allows commands to produce structured output in any\n> of a range of formats using a single API.\n>\n> The API includes an OPT_OUTPUT and handle_output_arg so that the\n> option handling for different commands will be as similar as possible.\n\nI was hoping that the existing low-level -z routines (e.g. \"diff-* -z\")\nfollow similar enough patterns to have a corresponding output-z.c and be\nhandled inside output.c library.  But that is not a requirement, just\n\"would have been nicer if the original were written that way\".\n\n> diff --git a/output-json.c b/output-json.c\n> new file mode 100644\n> index 0000000..0eb66b2\n> --- /dev/null\n> +++ b/output-json.c\n> @@ -0,0 +1,128 @@\n> +#include \"git-compat-util.h\"\n> +#include \"output.h\"\n> +#include \"strbuf.h\"\n> +\n> +static char *json_quote(char *s)\n> +{\n> +\tstruct strbuf buf = STRBUF_INIT;\n> +\n> +\twhile (*s) {\n> +\t\tswitch (*s) {\n> +...\n> +\t\tdefault:\n> +\t\t\t/* All control characters must be encode, even if they\n> +\t\t\t * don't have a specific escape character of their own */\n> +\t\t\tif (*s < 0x20)\n> +\t\t\t\tstrbuf_addf(&buf, \"\\\\u%04x\", *s);\n\nAs you didn't say your \"char\" is either signed or unsigned upfront, this\nwill behave differently when you are fed a UTF-8 string.  If it is signed,\nyou will end up showing bytes in a single letter separately at wrong\ncodepoint, and if it is unsigned, you will give UTF-8 string unquoted,\nwhich probably is what you meant to do.\n\nWhat is your design intention regarding legacy encoding?  This code does\nnot yet declare \"dear user, if you plan to use json/xml output, your\nrepository metadata (notably the pathnames) has to be in UTF-8\", as the\ncaller _could_ transliterate legacy data before feeding it to output.c\nlayer.  An alternative would be for the output.c layer to know about the\nencoding of incoming data and transliterate when the output format\nrequires a particular encoding.\n\n> +static void json_obj_item_start(FILE *file, char *name, int first)\n> +{\n> +\tchar *quoted = json_quote(name);\n> +\tif (!first)\n> +\t\tfprintf(file, \",\\n\");\n> +\tfprintf(file, \"\\\"%s\\\" : \", quoted);\n> +\tfree(quoted);\n> +}\n> + ...\n> +static void json_str(FILE *file, char *value)\n> +{\n> +\tchar *quoted = json_quote(value);\n> +\tfprintf(file, \"\\\"%s\\\"\", quoted);\n> +\tfree(quoted);\n> +}\n\nAn obvious improvement would be to make json_quote() to take FILE * to\navoid wasteful allocation and copy, as it doesn't do anything but addstr\nand addch, and all of its callers don't do anything but spitting the\nresult out to FILE *.\n\n> diff --git a/output-xml.c b/output-xml.c\n> new file mode 100644\n> index 0000000..50dd7d6\n> --- /dev/null\n> +++ b/output-xml.c\n> @@ -0,0 +1,68 @@\n> +#include \"git-compat-util.h\"\n> +#include \"output.h\"\n\nThis seems to totally lack quoting of any metacharacters for \"name\" and\nstring \"value\".\n"},{"id":"139278","messageId":"s2hfabb9a1e1004111126i6822abc1ne0e0e5bad6f4ac7@mail.gmail.com","threadId":"23420","inReplyTo":"7vy6gtonwt.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Sverre Rabbelier","fromEmail":"srabbelier@gmail.com","sentAt":"2010-04-11T18:26:00Z","receivedAt":"2010-04-11T18:26:00Z","isPatch":true,"sender":{"key":"srabbelier@gmail.com","avatar":"https://avatars.githubusercontent.com/u/3098?v=4"},"body":"Heya,\n\nOn Sun, Apr 11, 2010 at 20:16, Junio C Hamano <gitster@pobox.com> wrote:\n> I was hoping that the existing low-level -z routines (e.g. \"diff-* -z\")\n> follow similar enough patterns to have a corresponding output-z.c and be\n> handled inside output.c library.  But that is not a requirement, just\n> \"would have been nicer if the original were written that way\".\n\nI like that idea, I think it would make our plumbing interface more\nconsistent, and further validate the API design. Any plumbing command\n(once converted) can then be used with -z (or --format=zero or\nwhatever it is) and give a similar output format, very nice.\n\n-- \nCheers,\n\nSverre Rabbelier\n"},{"id":"139281","messageId":"91d4c9c4ecdd32166bedb6dc0bd007d6@212.159.54.234","threadId":"23420","inReplyTo":"7vy6gtonwt.fsf@alter.siamese.dyndns.org","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T19:21:10Z","receivedAt":"2010-04-11T19:21:10Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"On Sun, 11 Apr 2010 11:16:18 -0700, Junio C Hamano <gitster@pobox.com>\nwrote:\n> Julian Phillips <julian@quantumfyre.co.uk> writes:\n> \n>> Add a library that allows commands to produce structured output in any\n>> of a range of formats using a single API.\n>>\n>> The API includes an OPT_OUTPUT and handle_output_arg so that the\n>> option handling for different commands will be as similar as possible.\n> \n> I was hoping that the existing low-level -z routines (e.g. \"diff-* -z\")\n> follow similar enough patterns to have a corresponding output-z.c and be\n> handled inside output.c library.  But that is not a requirement, just\n> \"would have been nicer if the original were written that way\".\n\nAs the API currently stands, I don't think it would be possible to\nrecreate the existing output of -z, as the separator between values is not\nconstant.  I haven't really looked into whether the output is completely\nincompatible with structured output though (i.e. could -z be supported by\nadding one or two functions to the API?).\n\n>> diff --git a/output-json.c b/output-json.c\n>> new file mode 100644\n>> index 0000000..0eb66b2\n>> --- /dev/null\n>> +++ b/output-json.c\n>> @@ -0,0 +1,128 @@\n>> +#include \"git-compat-util.h\"\n>> +#include \"output.h\"\n>> +#include \"strbuf.h\"\n>> +\n>> +static char *json_quote(char *s)\n>> +{\n>> +\tstruct strbuf buf = STRBUF_INIT;\n>> +\n>> +\twhile (*s) {\n>> +\t\tswitch (*s) {\n>> +...\n>> +\t\tdefault:\n>> +\t\t\t/* All control characters must be encode, even if they\n>> +\t\t\t * don't have a specific escape character of their own */\n>> +\t\t\tif (*s < 0x20)\n>> +\t\t\t\tstrbuf_addf(&buf, \"\\\\u%04x\", *s);\n> \n> As you didn't say your \"char\" is either signed or unsigned upfront, this\n> will behave differently when you are fed a UTF-8 string.  If it is\nsigned,\n> you will end up showing bytes in a single letter separately at wrong\n> codepoint, and if it is unsigned, you will give UTF-8 string unquoted,\n> which probably is what you meant to do.\n\nOops. :(\nYep, unsigned it should have been.\n\n> What is your design intention regarding legacy encoding?  This code does\n> not yet declare \"dear user, if you plan to use json/xml output, your\n> repository metadata (notably the pathnames) has to be in UTF-8\", as the\n> caller _could_ transliterate legacy data before feeding it to output.c\n> layer.  An alternative would be for the output.c layer to know about the\n> encoding of incoming data and transliterate when the output format\n> requires a particular encoding.\n\nTo be perfectly honest I had forgotten about encodings.  The code was\nwritten with the thought that strings would be UTF-8 (except that even that\ndidn't work as you pointed out above).  Having English as your first\nlanguage doesn't help with this sort of thing.  I'm not even sure how to\ncreate a file that has accented letters ... :$\n\nProbably having the output_str function take UTF-8, and then having a\nseparate output_encoded_str that also takes an encoding might make sense? \nUnfortunately I have no idea how to convert an encoded string in git - a\nquick grep suggests reenocde_string from utf8.h?\n\n>> +static void json_obj_item_start(FILE *file, char *name, int first)\n>> +{\n>> +\tchar *quoted = json_quote(name);\n>> +\tif (!first)\n>> +\t\tfprintf(file, \",\\n\");\n>> +\tfprintf(file, \"\\\"%s\\\" : \", quoted);\n>> +\tfree(quoted);\n>> +}\n>> + ...\n>> +static void json_str(FILE *file, char *value)\n>> +{\n>> +\tchar *quoted = json_quote(value);\n>> +\tfprintf(file, \"\\\"%s\\\"\", quoted);\n>> +\tfree(quoted);\n>> +}\n> \n> An obvious improvement would be to make json_quote() to take FILE * to\n> avoid wasteful allocation and copy, as it doesn't do anything but addstr\n> and addch, and all of its callers don't do anything but spitting the\n> result out to FILE *.\n\nYep, makes sense, thanks.\n\n>> diff --git a/output-xml.c b/output-xml.c\n>> new file mode 100644\n>> index 0000000..50dd7d6\n>> --- /dev/null\n>> +++ b/output-xml.c\n>> @@ -0,0 +1,68 @@\n>> +#include \"git-compat-util.h\"\n>> +#include \"output.h\"\n> \n> This seems to totally lack quoting of any metacharacters for \"name\" and\n> string \"value\".\n\nYep.  The XML output is still a long way from usable.  As I said in\nanother email, I mainly added it to see what different demands it placed on\nthe frontend/backend interface.  In future versions, I'll split out the XML\nbackend and try to make it clear that it's incomplete and only included in\nthe hope that someone who wants XML output takes it over ;).\n\n-- \nJulian\n"},{"id":"139284","messageId":"m3y6gtg24x.fsf@localhost.localdomain","threadId":"23420","inReplyTo":"91d4c9c4ecdd32166bedb6dc0bd007d6@212.159.54.234","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2010-04-11T20:34:59Z","receivedAt":"2010-04-11T20:34:59Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Julian Phillips <julian@quantumfyre.co.uk> writes:\n> On Sun, 11 Apr 2010 11:16:18 -0700, Junio C Hamano <gitster@pobox.com>\n> wrote:\n>> Julian Phillips <julian@quantumfyre.co.uk> writes:\n>> \n>>> Add a library that allows commands to produce structured output in any\n>>> of a range of formats using a single API.\n>>>\n>>> The API includes an OPT_OUTPUT and handle_output_arg so that the\n>>> option handling for different commands will be as similar as possible.\n>> \n>> I was hoping that the existing low-level -z routines (e.g. \"diff-* -z\")\n>> follow similar enough patterns to have a corresponding output-z.c and be\n>> handled inside output.c library.  But that is not a requirement, just\n>> \"would have been nicer if the original were written that way\".\n> \n> As the API currently stands, I don't think it would be possible to\n> recreate the existing output of -z, as the separator between values is not\n> constant.  I haven't really looked into whether the output is completely\n> incompatible with structured output though (i.e. could -z be supported by\n> adding one or two functions to the API?).\n\nWhat about the new(ly) proposed -Z output in one of its variants,\nnamely with single NUL (\"\\0\") as field separator, and double NUL (\"\\0\\0\")\nas a record terminator?\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"139286","messageId":"aae50060001ba0a214ed71ceff3fa480@212.159.54.234","threadId":"23420","inReplyTo":"m3y6gtg24x.fsf@localhost.localdomain","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T20:46:18Z","receivedAt":"2010-04-11T20:46:18Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"On Sun, 11 Apr 2010 13:34:59 -0700 (PDT), Jakub Narebski\n<jnareb@gmail.com>\nwrote:\n> Julian Phillips <julian@quantumfyre.co.uk> writes:\n>> On Sun, 11 Apr 2010 11:16:18 -0700, Junio C Hamano <gitster@pobox.com>\n>> wrote:\n>>> Julian Phillips <julian@quantumfyre.co.uk> writes:\n>>> \n>>>> Add a library that allows commands to produce structured output in\nany\n>>>> of a range of formats using a single API.\n>>>>\n>>>> The API includes an OPT_OUTPUT and handle_output_arg so that the\n>>>> option handling for different commands will be as similar as\npossible.\n>>> \n>>> I was hoping that the existing low-level -z routines (e.g. \"diff-*\n-z\")\n>>> follow similar enough patterns to have a corresponding output-z.c and\nbe\n>>> handled inside output.c library.  But that is not a requirement, just\n>>> \"would have been nicer if the original were written that way\".\n>> \n>> As the API currently stands, I don't think it would be possible to\n>> recreate the existing output of -z, as the separator between values is\n>> not\n>> constant.  I haven't really looked into whether the output is\ncompletely\n>> incompatible with structured output though (i.e. could -z be supported\nby\n>> adding one or two functions to the API?).\n> \n> What about the new(ly) proposed -Z output in one of its variants,\n> namely with single NUL (\"\\0\") as field separator, and double NUL\n(\"\\0\\0\")\n> as a record terminator?\n\nThat should be much easier.  Though actually I am fairly close to getting\n_all_ output from ls-tree going through the output library ... (i.e. even\nthe normal no-option output).  I don't know what people's opinion on this\napproach is, but I thought it was worth a try anyway.\n\n-- \nJulian\n"},{"id":"139287","messageId":"20100411205704.GA16098@thyrsus.com","threadId":"23420","inReplyTo":"aae50060001ba0a214ed71ceff3fa480@212.159.54.234","subject":"Re: [RFC/PATCH 2/3] add a library of code for producing structured output","fromName":"Eric Raymond","fromEmail":"esr@thyrsus.com","sentAt":"2010-04-11T20:57:04Z","receivedAt":"2010-04-11T20:57:04Z","isPatch":true,"sender":{"key":"esr@thyrsus.com","avatar":"https://avatars.githubusercontent.com/u/727961?v=4"},"body":"Julian Phillips <julian@quantumfyre.co.uk>:\n> That should be much easier.  Though actually I am fairly close to getting\n> _all_ output from ls-tree going through the output library ... (i.e. even\n> the normal no-option output).  I don't know what people's opinion on this\n> approach is, but I thought it was worth a try anyway.\n\nI make encouraging noises in your direction.  This approach sounds\nlike an orthogonality and consistency win.\n-- \n\t\t<a href=\"http://www.catb.org/~esr/\">Eric S. Raymond</a>\n"},{"id":"139293","messageId":"q2i2cfc40321004111522kd177fb89k6b9265c641d7deec@mail.gmail.com","threadId":"23420","inReplyTo":"p2ofabb9a1e1004111050x660c37fdke4d5316baaa0cfbe@mail.gmail.com","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-04-11T22:22:41Z","receivedAt":"2010-04-11T22:22:41Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"I can see that retrofitting this more widely would add quite a lot of\nconditional logic to a lot of places.\n\nIf one was designing for both line-oriented and structured outputs\nfrom the start, I imagine one would build a map for each record, and\nthen hand that to the output context when it is complete, allowing the\nconsiderations of both line orientation and structured output to be\nencapsulated within the backend. Self-describing output formats can\nuse a simple map without needing to know the record type, but line\noriented outputs, of course, would need to know the type of record in\norder to select the correct line formatter.\n\nSo, would it be worth providing a hint as to record type in the\noutput_start_object call so that if it was later desired to subsume\nline-oriented formats under the same framework, there is enough\ninformation available to the backend to do that?\n\n[ And, yes, I understand that to making line-oriented formats a\nbackend would be a reasonably invasive change to existing code that\nwould involve a level of indirection and abstraction that may not be\nto everyone's taste. ]\n\njon.\n\nOn Mon, Apr 12, 2010 at 3:50 AM, Sverre Rabbelier <srabbelier@gmail.com> wrote:\n> Heya,\n>\n> On Sun, Apr 11, 2010 at 19:45, Julian Phillips <julian@quantumfyre.co.uk> wrote:\n>> I think that there probably are commands where it will be more work to\n>> integrate the output - but I think that is probably more to do with the\n>> structure of the current code than the API of the new.  Does it make a\n>> difference what the API of the new output code is if there isn't currently\n>> a sensible hook-in point?\n>\n> No you are right, the existance of such hard-to-change commands does\n> not really affect the API design in this case, although I think it\n> might be a good idea to try out at least one such command before\n> committing to using this API. For example, it might turn out that\n> there's an elegant way to hook in, or that adding all those if\n> (output_style != OUTPUT_NORMAL)  statements gets cluttery and there\n> should be a different way to do things instead.\n>\n>> If code has been written without the expectation that the output format\n>> could be changed then the effort to add a new output format could be\n>> considerably more than for status or ls-tree.  However, with the\n>> frontend/backend design hopefully we only have to endure the effort once to\n>> get multiple output formats.\n>\n> I'm curious to see where this will lead us :).\n>\n> --\n> Cheers,\n>\n> Sverre Rabbelier\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n>\n"},{"id":"139294","messageId":"20100411223455.GA16622@thyrsus.com","threadId":"23420","inReplyTo":"q2i2cfc40321004111522kd177fb89k6b9265c641d7deec@mail.gmail.com","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Eric Raymond","fromEmail":"esr@thyrsus.com","sentAt":"2010-04-11T22:34:55Z","receivedAt":"2010-04-11T22:34:55Z","isPatch":true,"sender":{"key":"esr@thyrsus.com","avatar":"https://avatars.githubusercontent.com/u/727961?v=4"},"body":"Jon Seymour <jon.seymour@gmail.com>:\n> [ And, yes, I understand that to making line-oriented formats a\n> backend would be a reasonably invasive change to existing code that\n> would involve a level of indirection and abstraction that may not be\n> to everyone's taste. ]\n\nFor whatever my opinion is worth I think this is a good direction to\ngo in.  I think it fits the well-established git design philosophy of\nseparating content manipulation (plumbing) from presentation\n(porcelain).\n-- \n\t\t<a href=\"http://www.catb.org/~esr/\">Eric S. Raymond</a>\n"},{"id":"139300","messageId":"776480BE-3652-489A-96C9-9312321E49C0@gmail.com","threadId":"23420","inReplyTo":"q2i2cfc40321004111522kd177fb89k6b9265c641d7deec@mail.gmail.com","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Jon Seymour","fromEmail":"jon.seymour@gmail.com","sentAt":"2010-04-11T23:25:04Z","receivedAt":"2010-04-11T23:25:04Z","isPatch":true,"sender":{"key":"jon.seymour@gmail.com","avatar":"https://avatars.githubusercontent.com/u/207131?v=4"},"body":"\n\nOn 12/04/2010, at 8:22, Jon Seymour <jon.seymour@gmail.com> wrote:\n>\n> So, would it be worth providing a hint as to record type in the\n> output_start_object call so that if it was later desired to subsume\n> line-oriented formats under the same framework, there is enough\n> information available to the backend to do that?\n\nOf course, one way to do this would be to use a more descriptive  \nrecord name than \"entry\". This would make the record itself (as  \nopposed to just it's fields) self-describing.\n\nThe point is, you would want to start using descriptive record names  \nnow so that you don't end up locked into a partially context sensitive  \nbase of consumers who are expecting their JSON records to be called  \n\"entry\" and using context hints to infer the actual record type.\n\njon.\n"},{"id":"139301","messageId":"61c2a556d3b557df82cc5da764b5d0f2@212.159.54.234","threadId":"23420","inReplyTo":"776480BE-3652-489A-96C9-9312321E49C0@gmail.com","subject":"Re: [RFC/PATCH 0/3] JSON/XML output for scripting interface","fromName":"Julian Phillips","fromEmail":"julian@quantumfyre.co.uk","sentAt":"2010-04-11T23:30:33Z","receivedAt":"2010-04-11T23:30:33Z","isPatch":true,"sender":{"key":"julian@quantumfyre.co.uk","avatar":"https://avatars.githubusercontent.com/u/948888?v=4"},"body":"On Mon, 12 Apr 2010 09:25:04 +1000, Jon Seymour <jon.seymour@gmail.com>\nwrote:\n> On 12/04/2010, at 8:22, Jon Seymour <jon.seymour@gmail.com> wrote:\n>>\n>> So, would it be worth providing a hint as to record type in the\n>> output_start_object call so that if it was later desired to subsume\n>> line-oriented formats under the same framework, there is enough\n>> information available to the backend to do that?\n> \n> Of course, one way to do this would be to use a more descriptive  \n> record name than \"entry\". This would make the record itself (as  \n> opposed to just it's fields) self-describing.\n> \n> The point is, you would want to start using descriptive record names  \n> now so that you don't end up locked into a partially context sensitive  \n> base of consumers who are expecting their JSON records to be called  \n> \"entry\" and using context hints to infer the actual record type.\n\nI have to admit that most of the names were just \"first idea out of the\nhat\" - not really something I was paying too much attention to.  It's\nfairly easy to tweak them later, provided it's done before they get\npublished.\n\nHaving said that, I've just mailed out v2 patches, which already include\nline-based output (using a different approach). ;)\n\nMore descriptive names are probably something that should be done anyway\nthough.\n\n-- \nJulian\n"}]}