[PATCH] formatter: allow json to handle more levels of depth

Yuya Nishihara yuya at tcha.org
Sun Mar 13 07:50:26 EDT 2016


On Tue, 08 Mar 2016 15:43:23 -0600, Matt Mackall wrote:
> On Wed, 2016-03-09 at 00:56 +0900, Yuya Nishihara wrote:
> > I meant multi-level data could be used by another command, and it could render
> > unfortunate JSON and force us to tackle on the compatibility hell.
> 
> A good example of such a command is "hg summary". It fits pretty poorly into the
> the formatter's list of dicts of simple values model.
> 
> One idea I've considered is to have non-uniform list elements. So, something
> like:
> 
> $ hg sum
> parent: 34812:b9296b330a54 tip
>  convert: darcs use absolute_import
> branch: default
> commit: 28 unknown (clean)
> update: 61 new changesets, 13 branch heads (merge)
> phases: 54 draft, 38 secret
> unstable: 20 changesets
> divergent: 2 changesets
> unstable: 20 changesets
> divergent: 2 changesets

I think a sub formatter or something can help this case. For example,

  fm = ui.formatter('summary', opts)
  f = fm.sub()
  f.write('rev node desc', '%d:%s\n %s', rev, node, desc)
  fm.startitem()
  fm.write('parent', 'parent: %s\n', f.end())
  ...
  fm.end()

For plain output, a sub formatter 'f' uses ui.push/popbuffer().

  f.write('rev node desc', '%d:%s\n %s', rev, node, desc)
  # write to ui._buffer
  f.end()
  # return '{rev}:{node}\n {desc}'

For json output, a sub formatter 'f' just keeps raw data.

  f.write('rev node desc', '%d:%s\n %s', rev, node, desc)
  # _data = {'rev': rev, 'node': node, 'desc': desc}
  f.end()
  # return _data

So, the output will be like:

  [
   {
    "parent": {"node": "deadbeef1234", "rev": 10, "desc": "foo"},
    ...
   }
  ]


> > > > For example, "log -Tjson" renders "tags" as follows:
> > > > 
> > > >  "tags": ["tip"],
> > > > 
> > > > We can't do that with the current formatter API. To make it compatible
> > > > with
> > > > the template functions, we would have to render it as follows:
> > > > 
> > > >  "tags": [{"tag": "tip"}]

I have no idea how to handle this cleanly. Maybe fm.writelist() or something
will be simple and can handle common cases.

  fm.writelist('tags', '%s', ['tip'], sep=' ', templatename='tag')
  # plain output: ' '.join('%s' % v for v in ['tip'])
  # json: "tags": ["tip"]
  # templater: 'tags': [{'tag': v} for v in ['tip']]


More information about the Mercurial-devel mailing list