Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-11 Thread Jeff Hostetler




On 6/8/2018 4:07 PM, René Scharfe wrote:

Am 07.06.2018 um 16:12 schrieb g...@jeffhostetler.com:

From: Jeff Hostetler 

[...]

+   if (jw->first_stack.buf[jw->first_stack.len - 1] == '1')
+   jw->first_stack.buf[jw->first_stack.len - 1] = '0';
+   else
+   strbuf_addch(>json, ',');


You only need a binary flag to indicate if a comma is needed, not a
stack.  We need a comma at the current level if and only if we already
wrote a child item.  If we finish a level then we do need a comma at the
previous level because we just wrote a sub-object or sub-array there.
And that should cover all cases.  Am I missing something?

I get a sense of déjà vu, by the way. :)

[...]

Yes, your way is simpler.  I'll update and re-roll.
(And yes, we did discuss this earlier.  I found a problem with
my first version where it wouldn't handle empty sub-items, but
you found the missing piece.)

Thanks
Jeff




Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-11 Thread Jeff Hostetler




On 6/8/2018 2:05 AM, René Scharfe wrote:

Am 07.06.2018 um 16:12 schrieb g...@jeffhostetler.com:

From: Jeff Hostetler 

Add a series of jw_ routines and "struct json_writer" structure to compose

[...]

  TEST_PROGRAMS_NEED_X += test-index-version
+TEST_PROGRAMS_NEED_X += test-json-writer>  TEST_PROGRAMS_NEED_X += 
test-lazy-init-name-hash
  TEST_PROGRAMS_NEED_X += test-line-buffer
  TEST_PROGRAMS_NEED_X += test-match-trees


This doesn't apply cleanly on master, because most test helpers have
been combined into a single binary to reduce their disk footprint and
link times.  See efd71f8913 (t/helper: add an empty test-tool program)
for the overall rationale.

test-json-writer could become a built-in as well, I think.  You can see
e.g. in c932a5ff28 (t/helper: merge test-string-list into test-tool)
what needs to be done to convert a helper.

René



You're right, the test helper framework changed since I started this
patch series.  I was trying to keep the same parent commit as my V1
to make it easier to compare, but that's not working out so well.

I'll move it forward to the current master and fix it up.

Thanks,
Jeff


Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-11 Thread Jeff Hostetler




On 6/8/2018 4:32 PM, René Scharfe wrote:

Am 07.06.2018 um 16:12 schrieb g...@jeffhostetler.com:

   Makefile|   2 +
   json-writer.c   | 419 
   json-writer.h   | 113 +
   t/helper/test-json-writer.c | 572 

   t/t0019-json-writer.sh  | 236 ++
   5 files changed, 1342 insertions(+)
   create mode 100644 json-writer.c
   create mode 100644 json-writer.h
   create mode 100644 t/helper/test-json-writer.c
   create mode 100755 t/t0019-json-writer.sh


$ git grep 'static inline' '*json*'
json-writer.c:static inline void indent_pretty(struct json_writer *jw)
json-writer.c:static inline void begin(struct json_writer *jw, char ch_open, 
int pretty)
json-writer.c:static inline void assert_in_object(const struct json_writer *jw, 
const char *key)
json-writer.c:static inline void assert_in_array(const struct json_writer *jw)
json-writer.c:static inline void maybe_add_comma(struct json_writer *jw)
json-writer.c:static inline void fmt_double(struct json_writer *jw, int 
precision,
json-writer.c:static inline void object_common(struct json_writer *jw, const 
char *key)
json-writer.c:static inline void array_common(struct json_writer *jw)
json-writer.c:static inline void assert_is_terminated(const struct json_writer 
*jw)
t/helper/test-json-writer.c:static inline int scripted(int argc, const char 
**argv)
t/helper/test-json-writer.c:static inline int my_usage(void)

Do you need all those inline keywords?  I'd rather leave the decision
about inlining to the compiler and (via optimization flags) the user
as much as possible.  Not a biggie, but the high frequency of that
word made me blink..

René



I was just trying to match the patterns I found elsewhere in the code.

$ grep "static inline" *.c builtin/*.c | wc -l
111

But yeah, it's no big deal.  I can remove them.

Jeff


Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-08 Thread René Scharfe
Am 07.06.2018 um 16:12 schrieb g...@jeffhostetler.com:
>   Makefile|   2 +
>   json-writer.c   | 419 
>   json-writer.h   | 113 +
>   t/helper/test-json-writer.c | 572 
> 
>   t/t0019-json-writer.sh  | 236 ++
>   5 files changed, 1342 insertions(+)
>   create mode 100644 json-writer.c
>   create mode 100644 json-writer.h
>   create mode 100644 t/helper/test-json-writer.c
>   create mode 100755 t/t0019-json-writer.sh

$ git grep 'static inline' '*json*'
json-writer.c:static inline void indent_pretty(struct json_writer *jw)
json-writer.c:static inline void begin(struct json_writer *jw, char ch_open, 
int pretty)
json-writer.c:static inline void assert_in_object(const struct json_writer *jw, 
const char *key)
json-writer.c:static inline void assert_in_array(const struct json_writer *jw)
json-writer.c:static inline void maybe_add_comma(struct json_writer *jw)
json-writer.c:static inline void fmt_double(struct json_writer *jw, int 
precision,
json-writer.c:static inline void object_common(struct json_writer *jw, const 
char *key)
json-writer.c:static inline void array_common(struct json_writer *jw)
json-writer.c:static inline void assert_is_terminated(const struct json_writer 
*jw)
t/helper/test-json-writer.c:static inline int scripted(int argc, const char 
**argv)
t/helper/test-json-writer.c:static inline int my_usage(void)

Do you need all those inline keywords?  I'd rather leave the decision
about inlining to the compiler and (via optimization flags) the user
as much as possible.  Not a biggie, but the high frequency of that
word made me blink..

René


Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-08 Thread Jeff Hostetler




On 6/7/2018 1:24 PM, Eric Sunshine wrote:

On Thu, Jun 7, 2018 at 10:12 AM,   wrote:

Add a series of jw_ routines and "struct json_writer" structure to compose
JSON data.  The resulting string data can then be output by commands wanting
to support a JSON output format.
[...]
Signed-off-by: Jeff Hostetler 
---
diff --git a/t/t0019-json-writer.sh b/t/t0019-json-writer.sh
@@ -0,0 +1,236 @@
+test_expect_success 'simple object' '
+   cat >expect <<-\EOF &&
+   {"a":"abc","b":42,"c":3.14,"d":true,"e":false,"f":null}
+   EOF
+   test-json-writer >actual \
+   @object \
+   @object-string a abc \
+   @object-int b 42 \
+   @object-double c 2 3.140 \
+   @object-true d \
+   @object-false e \
+   @object-null f \
+   @end &&
+   test_cmp expect actual
+'


To make it easier on people writing these tests, it might be nice for
this to be less noisy by getting rid of "@" and "\". To get rid of
"\", the test program could grab its script commands from stdin (one
instruction per line) rather than from argv[]. For instance:

 test-json-writer >actual <<-\EOF &&
 object
 object-string a abc
 ...
 end
 EOF

Not a big deal, and certainly not worth a re-roll.



I hadn't thought about doing it that way.  Might be a little easier
to use.  Let me take a look and see if it would be much work to switch.

Thanks
Jeff


Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-08 Thread René Scharfe
Am 07.06.2018 um 16:12 schrieb g...@jeffhostetler.com:
> From: Jeff Hostetler 
> +/*
> + * Add comma if we have already seen a member at this level.
> + */
> +static inline void maybe_add_comma(struct json_writer *jw)
> +{
> + if (!jw->open_stack.len)
> + return;

This is impossible.  maybe_add_comma() is only called directly after
assert_in_object() and assert_in_object(), which abort if open_stack 
is empty.

> + if (jw->first_stack.buf[jw->first_stack.len - 1] == '1')
> + jw->first_stack.buf[jw->first_stack.len - 1] = '0';
> + else
> + strbuf_addch(>json, ',');

You only need a binary flag to indicate if a comma is needed, not a
stack.  We need a comma at the current level if and only if we already
wrote a child item.  If we finish a level then we do need a comma at the
previous level because we just wrote a sub-object or sub-array there.
And that should cover all cases.  Am I missing something?

I get a sense of déjà vu, by the way. :)

Here's what I mean:
---
 json-writer.c | 17 ++---
 json-writer.h | 13 +
 2 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/json-writer.c b/json-writer.c
index f35ce1912a..14a4e89188 100644
--- a/json-writer.c
+++ b/json-writer.c
@@ -5,7 +5,7 @@ void jw_init(struct json_writer *jw)
 {
strbuf_reset(>json);
strbuf_reset(>open_stack);
-   strbuf_reset(>first_stack);
+   jw->need_comma = 0;
jw->pretty = 0;
 }
 
@@ -13,7 +13,6 @@ void jw_release(struct json_writer *jw)
 {
strbuf_release(>json);
strbuf_release(>open_stack);
-   strbuf_release(>first_stack);
 }
 
 /*
@@ -69,7 +68,7 @@ static inline void begin(struct json_writer *jw, char 
ch_open, int pretty)
strbuf_addch(>json, ch_open);
 
strbuf_addch(>open_stack, ch_open);
-   strbuf_addch(>first_stack, '1');
+   jw->need_comma = 0;
 }
 
 /*
@@ -99,12 +98,10 @@ static inline void assert_in_array(const struct json_writer 
*jw)
  */
 static inline void maybe_add_comma(struct json_writer *jw)
 {
-   if (!jw->open_stack.len)
-   return;
-   if (jw->first_stack.buf[jw->first_stack.len - 1] == '1')
-   jw->first_stack.buf[jw->first_stack.len - 1] = '0';
-   else
+   if (jw->need_comma)
strbuf_addch(>json, ',');
+   else
+   jw->need_comma = 1;
 }
 
 static inline void fmt_double(struct json_writer *jw, int precision,
@@ -397,8 +394,6 @@ void jw_end(struct json_writer *jw)
char ch_open;
int len;
 
-   if (jw->open_stack.len != jw->first_stack.len)
-   BUG("jwon-writer: open_ and first_ stacks out of sync");
if (!jw->open_stack.len)
BUG("json-writer: too many jw_end(): '%s'", jw->json.buf);
 
@@ -406,7 +401,7 @@ void jw_end(struct json_writer *jw)
ch_open = jw->open_stack.buf[len];
 
strbuf_setlen(>open_stack, len);
-   strbuf_setlen(>first_stack, len);
+   jw->need_comma = 1;
 
if (jw->pretty)
strbuf_addch(>json, '\n');
diff --git a/json-writer.h b/json-writer.h
index af9c2612f8..c437462ba8 100644
--- a/json-writer.h
+++ b/json-writer.h
@@ -59,18 +59,15 @@ struct json_writer
struct strbuf open_stack;
 
/*
-* Another simple stack of the currently open array and object
-* forms.  This is used in parallel to "open_stack" (same length).
-* It contains a string of '1' and '0' where '1' indicates that
-* the next child-element seen will be the first child (and does
-* not need a leading comma).
+* Indicates if the next child item needs a leading comma.
+* Only the first item of arrays and objects doesn't need one.
 */
-   struct strbuf first_stack;
+   unsigned int need_comma:1;
 
-   int pretty;
+   unsigned int pretty:1;
 };
 
-#define JSON_WRITER_INIT { STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, 0 }
+#define JSON_WRITER_INIT { STRBUF_INIT, STRBUF_INIT, 0, 0 }
 
 void jw_init(struct json_writer *jw);
 void jw_release(struct json_writer *jw);
-- 
2.17.1


Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-08 Thread René Scharfe
Am 07.06.2018 um 16:12 schrieb g...@jeffhostetler.com:
> From: Jeff Hostetler 
> 
> Add a series of jw_ routines and "struct json_writer" structure to compose
> JSON data.  The resulting string data can then be output by commands wanting
> to support a JSON output format.
> 
> The json-writer routines can be used to generate structured data in a
> JSON-like format.  We say "JSON-like" because we do not enforce the Unicode
> (usually UTF-8) requirement on string fields.  Internally, Git does not
> necessarily have Unicode/UTF-8 data for most fields, so it is currently
> unclear the best way to enforce that requirement.  For example, on Linx
> pathnames can contain arbitrary 8-bit character data, so a command like
> "status" would not know how to encode the reported pathnames.  We may want
> to revisit this (or double encode such strings) in the future.
> 
> The initial use for the json-writer routines is for generating telemetry
> data for executed Git commands.  Later, we may want to use them in other
> commands, such as status.
> 
> Helped-by: René Scharfe 
> Helped-by: Wink Saville 
> Helped-by: Ramsay Jones 
> Signed-off-by: Jeff Hostetler 
> ---
>   Makefile|   2 +
>   json-writer.c   | 419 
>   json-writer.h   | 113 +
>   t/helper/test-json-writer.c | 572 
> 
>   t/t0019-json-writer.sh  | 236 ++
>   5 files changed, 1342 insertions(+)
>   create mode 100644 json-writer.c
>   create mode 100644 json-writer.h
>   create mode 100644 t/helper/test-json-writer.c
>   create mode 100755 t/t0019-json-writer.sh
> 
> diff --git a/Makefile b/Makefile
> index a1d8775..4ae6946 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -666,6 +666,7 @@ TEST_PROGRAMS_NEED_X += test-fake-ssh
>  TEST_PROGRAMS_NEED_X += test-genrandom
>  TEST_PROGRAMS_NEED_X += test-hashmap
>  TEST_PROGRAMS_NEED_X += test-index-version
> +TEST_PROGRAMS_NEED_X += test-json-writer>  TEST_PROGRAMS_NEED_X += 
> test-lazy-init-name-hash
>  TEST_PROGRAMS_NEED_X += test-line-buffer
>  TEST_PROGRAMS_NEED_X += test-match-trees

This doesn't apply cleanly on master, because most test helpers have
been combined into a single binary to reduce their disk footprint and
link times.  See efd71f8913 (t/helper: add an empty test-tool program)
for the overall rationale.

test-json-writer could become a built-in as well, I think.  You can see
e.g. in c932a5ff28 (t/helper: merge test-string-list into test-tool)
what needs to be done to convert a helper.

René


Re: [PATCH v8 1/2] json_writer: new routines to create data in JSON format

2018-06-07 Thread Eric Sunshine
On Thu, Jun 7, 2018 at 10:12 AM,   wrote:
> Add a series of jw_ routines and "struct json_writer" structure to compose
> JSON data.  The resulting string data can then be output by commands wanting
> to support a JSON output format.
> [...]
> Signed-off-by: Jeff Hostetler 
> ---
> diff --git a/t/t0019-json-writer.sh b/t/t0019-json-writer.sh
> @@ -0,0 +1,236 @@
> +test_expect_success 'simple object' '
> +   cat >expect <<-\EOF &&
> +   {"a":"abc","b":42,"c":3.14,"d":true,"e":false,"f":null}
> +   EOF
> +   test-json-writer >actual \
> +   @object \
> +   @object-string a abc \
> +   @object-int b 42 \
> +   @object-double c 2 3.140 \
> +   @object-true d \
> +   @object-false e \
> +   @object-null f \
> +   @end &&
> +   test_cmp expect actual
> +'

To make it easier on people writing these tests, it might be nice for
this to be less noisy by getting rid of "@" and "\". To get rid of
"\", the test program could grab its script commands from stdin (one
instruction per line) rather than from argv[]. For instance:

test-json-writer >actual <<-\EOF &&
object
object-string a abc
...
end
EOF

Not a big deal, and certainly not worth a re-roll.