From abb16b4226db4f5447a544aaacebc3ea1573fdc1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 11 May 2020 10:33:09 +0930 Subject: [PATCH] cli: implement new 'flattened JSON' mode. Much nicer for grepping, since `{ "foo": { "bar": [7] } }` is turned into `foo.bar[0]=7`. Changelog-Added: cli: New `--flat` mode for easy grepping. Signed-off-by: Rusty Russell --- cli/lightning-cli.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ tests/test_misc.py | 11 +++++++++ 2 files changed, 66 insertions(+) diff --git a/cli/lightning-cli.c b/cli/lightning-cli.c index 0f6187049..cc8980c99 100644 --- a/cli/lightning-cli.c +++ b/cli/lightning-cli.c @@ -78,6 +78,49 @@ static size_t human_readable(const char *buffer, const jsmntok_t *t, char term) abort(); } +/* Returns number of tokens digested */ +static size_t flat_json(const char *prefix, + const char *buffer, const jsmntok_t *t) +{ + size_t i, n; + char *p; + + switch (t->type) { + case JSMN_PRIMITIVE: + case JSMN_STRING: + printf("%s=%.*s\n", + prefix, t->end - t->start, buffer + t->start); + return 1; + case JSMN_ARRAY: + n = 1; + for (i = 0; i < t->size; i++) { + p = tal_fmt(NULL, "%s[%zi]", prefix, i); + n += flat_json(p, buffer, t + n); + tal_free(p); + } + return n; + case JSMN_OBJECT: + n = 1; + for (i = 0; i < t->size; i++) { + if (streq(prefix, "")) + p = tal_fmt(NULL, "%.*s", + t[n].end - t[n].start, + buffer + t[n].start); + else + p = tal_fmt(NULL, "%s.%.*s", prefix, + t[n].end - t[n].start, + buffer + t[n].start); + n++; + n += flat_json(p, buffer, t + n); + tal_free(p); + } + return n; + case JSMN_UNDEFINED: + break; + } + abort(); +} + static int compare_tok(const jsmntok_t *a, const jsmntok_t *b, const char *buffer) { @@ -184,6 +227,7 @@ enum format { JSON, HUMAN, HELPLIST, + FLAT, DEFAULT_FORMAT, RAW }; @@ -194,6 +238,12 @@ static char *opt_set_human(enum format *format) return NULL; } +static char *opt_set_flat(enum format *format) +{ + *format = FLAT; + return NULL; +} + static char *opt_set_json(enum format *format) { *format = JSON; @@ -454,6 +504,8 @@ int main(int argc, char *argv[]) " [...]", "Show this message. Use the command help (without hyphens -- \"lightning-cli help\") to get a list of all RPC commands"); opt_register_noarg("-H|--human-readable", opt_set_human, &format, "Human-readable output (default for 'help')"); + opt_register_noarg("-F|--flat", opt_set_flat, &format, + "Flatten output ('x.y.x=' format)"); opt_register_noarg("-J|--json", opt_set_json, &format, "JSON output (default unless 'help')"); opt_register_noarg("-R|--raw", opt_set_raw, &format, @@ -624,6 +676,9 @@ int main(int argc, char *argv[]) case HUMAN: human_readable(resp, result, '\n'); break; + case FLAT: + flat_json("", resp, result); + break; case JSON: print_json(resp, result, ""); printf("\n"); diff --git a/tests/test_misc.py b/tests/test_misc.py index ba584a247..378ebc447 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1063,6 +1063,17 @@ def test_cli(node_factory): assert [l for l in lines if l.startswith('help=')] == [] assert [l for l in lines if l.startswith('format-hint=')] == [] + # Flat format is great for grep. LONG LIVE UNIX! + out = subprocess.check_output(['cli/lightning-cli', + '--network={}'.format(TEST_NETWORK), + '--lightning-dir={}' + .format(l1.daemon.lightning_dir), + '-F', + 'help']).decode('utf-8') + lines = out.splitlines() + # Everything is a help[XX]= line, except format-hint. + assert [l for l in lines if not re.search(r'^help\[[0-9]*\].', l)] == ['format-hint=simple'] + def test_daemon_option(node_factory): """