Patchwork [3,of,5] formatter: parse name of built-in formatter templates in standard way

login
register
mail settings
Submitter Yuya Nishihara
Date Oct. 6, 2019, 8 p.m.
Message ID <efda5c5a4fe1a783ad40.1570392014@mimosa>
Download mbox | patch
Permalink /patch/42043/
State Accepted
Headers show

Comments

Yuya Nishihara - Oct. 6, 2019, 8 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1570332035 14400
#      Sat Oct 05 23:20:35 2019 -0400
# Node ID efda5c5a4fe1a783ad40da15d4e52ccfb09554da
# Parent  79c73a7a10457e10fa370fe43b028ce54ca98bb7
formatter: parse name of built-in formatter templates in standard way

This slightly makes it easier to add "-Tjson(...)" handling, which should
be enabled only if the template specifier doesn't look like a literal
template. In other words, it should be handled after "if '{' in tmpl".

This makes "log -Tpickle" and "log -Tdebug" abort, which I think is better
than just printing "picklepicklepickle...".
Augie Fackler - Oct. 8, 2019, 5:26 p.m.
> On Oct 6, 2019, at 16:00, Yuya Nishihara <yuya@tcha.org> wrote:
> 
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1570332035 14400
> #      Sat Oct 05 23:20:35 2019 -0400
> # Node ID efda5c5a4fe1a783ad40da15d4e52ccfb09554da
> # Parent  79c73a7a10457e10fa370fe43b028ce54ca98bb7
> formatter: parse name of built-in formatter templates in standard way
> 
> This slightly makes it easier to add "-Tjson(...)" handling, which should
> be enabled only if the template specifier doesn't look like a literal
> template. In other words, it should be handled after "if '{' in tmpl".
> 
> This makes "log -Tpickle" and "log -Tdebug" abort, which I think is better
> than just printing "picklepicklepickle...".

A clarification via IRC: this only hits special formatters, so things like using -T. to count commits using wc -c will still work.

> 
> diff --git a/mercurial/formatter.py b/mercurial/formatter.py
> --- a/mercurial/formatter.py
> +++ b/mercurial/formatter.py
> @@ -531,6 +531,7 @@ def lookuptemplate(ui, topic, tmpl):
>     'tmpl' can be any of the following:
> 
>      - a literal template (e.g. '{rev}')
> +     - a reference to built-in template (i.e. formatter)
>      - a map-file name or path (e.g. 'changelog')
>      - a reference to [templates] in config file
>      - a path to raw template file
> @@ -544,10 +545,17 @@ def lookuptemplate(ui, topic, tmpl):
>     available as well as aliases in [templatealias].
>     """
> 
> +    if not tmpl:
> +        return templatespec(None, None, None)
> +
>     # looks like a literal template?
>     if b'{' in tmpl:
>         return templatespec(b'', tmpl, None)
> 
> +    # a reference to built-in (formatter) template
> +    if tmpl in {b'cbor', b'json', b'pickle', b'debug'}:
> +        return templatespec(tmpl, None, None)
> +
>     # perhaps a stock style?
>     if not os.path.split(tmpl)[0]:
>         mapname = templater.templatepath(
> @@ -712,17 +720,16 @@ class templateresources(templater.resour
> 
> 
> def formatter(ui, out, topic, opts):
> -    template = opts.get(b"template", b"")
> -    if template == b"cbor":
> +    spec = lookuptemplate(ui, topic, opts.get(b'template', b''))
> +    if spec.ref == b"cbor":
>         return cborformatter(ui, out, topic, opts)
> -    elif template == b"json":
> +    elif spec.ref == b"json":
>         return jsonformatter(ui, out, topic, opts)
> -    elif template == b"pickle":
> +    elif spec.ref == b"pickle":
>         return pickleformatter(ui, out, topic, opts)
> -    elif template == b"debug":
> +    elif spec.ref == b"debug":
>         return debugformatter(ui, out, topic, opts)
> -    elif template != b"":
> -        spec = lookuptemplate(ui, topic, opts.get(b'template', b''))
> +    elif spec.ref or spec.tmpl or spec.mapfile:
>         return templateformatter(ui, out, topic, opts, spec)
>     # developer config: ui.formatdebug
>     elif ui.configbool(b'ui', b'formatdebug'):
> diff --git a/mercurial/logcmdutil.py b/mercurial/logcmdutil.py
> --- a/mercurial/logcmdutil.py
> +++ b/mercurial/logcmdutil.py
> @@ -617,9 +617,6 @@ def _lookuptemplate(ui, tmpl, style):
>                 mapfile = mapname
>         return templatespec(None, mapfile)
> 
> -    if not tmpl:
> -        return templatespec(None, None)
> -
>     return formatter.lookuptemplate(ui, b'changeset', tmpl)
> 
> 
> @@ -642,12 +639,15 @@ def changesetdisplayer(ui, repo, opts, d
>     regular display via changesetprinter() is done.
>     """
>     postargs = (differ, opts, buffered)
> -    if opts.get(b'template') in {b'cbor', b'json'}:
> +    spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
> +
> +    # machine-readable formats have slightly different keyword set than
> +    # plain templates, which are handled by changesetformatter.
> +    # note that {b'pickle', b'debug'} can also be added to the list if needed.
> +    if spec.ref in {b'cbor', b'json'}:
>         fm = ui.formatter(b'log', opts)
>         return changesetformatter(ui, repo, fm, *postargs)
> 
> -    spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
> -
>     if not spec.ref and not spec.tmpl and not spec.mapfile:
>         return changesetprinter(ui, repo, *postargs)
> 
> diff --git a/tests/test-template-map.t b/tests/test-template-map.t
> --- a/tests/test-template-map.t
> +++ b/tests/test-template-map.t
> @@ -1101,6 +1101,15 @@ honor --git but not format-breaking diff
>    }
>   ]
> 
> +Other unsupported formatter styles:
> +
> +  $ hg log -qr . -Tpickle
> +  abort: "pickle" not in template map
> +  [255]
> +  $ hg log -qr . -Tdebug
> +  abort: "debug" not in template map
> +  [255]
> +
> Error if style not readable:
> 
> #if unix-permissions no-root
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Patch

diff --git a/mercurial/formatter.py b/mercurial/formatter.py
--- a/mercurial/formatter.py
+++ b/mercurial/formatter.py
@@ -531,6 +531,7 @@  def lookuptemplate(ui, topic, tmpl):
     'tmpl' can be any of the following:
 
      - a literal template (e.g. '{rev}')
+     - a reference to built-in template (i.e. formatter)
      - a map-file name or path (e.g. 'changelog')
      - a reference to [templates] in config file
      - a path to raw template file
@@ -544,10 +545,17 @@  def lookuptemplate(ui, topic, tmpl):
     available as well as aliases in [templatealias].
     """
 
+    if not tmpl:
+        return templatespec(None, None, None)
+
     # looks like a literal template?
     if b'{' in tmpl:
         return templatespec(b'', tmpl, None)
 
+    # a reference to built-in (formatter) template
+    if tmpl in {b'cbor', b'json', b'pickle', b'debug'}:
+        return templatespec(tmpl, None, None)
+
     # perhaps a stock style?
     if not os.path.split(tmpl)[0]:
         mapname = templater.templatepath(
@@ -712,17 +720,16 @@  class templateresources(templater.resour
 
 
 def formatter(ui, out, topic, opts):
-    template = opts.get(b"template", b"")
-    if template == b"cbor":
+    spec = lookuptemplate(ui, topic, opts.get(b'template', b''))
+    if spec.ref == b"cbor":
         return cborformatter(ui, out, topic, opts)
-    elif template == b"json":
+    elif spec.ref == b"json":
         return jsonformatter(ui, out, topic, opts)
-    elif template == b"pickle":
+    elif spec.ref == b"pickle":
         return pickleformatter(ui, out, topic, opts)
-    elif template == b"debug":
+    elif spec.ref == b"debug":
         return debugformatter(ui, out, topic, opts)
-    elif template != b"":
-        spec = lookuptemplate(ui, topic, opts.get(b'template', b''))
+    elif spec.ref or spec.tmpl or spec.mapfile:
         return templateformatter(ui, out, topic, opts, spec)
     # developer config: ui.formatdebug
     elif ui.configbool(b'ui', b'formatdebug'):
diff --git a/mercurial/logcmdutil.py b/mercurial/logcmdutil.py
--- a/mercurial/logcmdutil.py
+++ b/mercurial/logcmdutil.py
@@ -617,9 +617,6 @@  def _lookuptemplate(ui, tmpl, style):
                 mapfile = mapname
         return templatespec(None, mapfile)
 
-    if not tmpl:
-        return templatespec(None, None)
-
     return formatter.lookuptemplate(ui, b'changeset', tmpl)
 
 
@@ -642,12 +639,15 @@  def changesetdisplayer(ui, repo, opts, d
     regular display via changesetprinter() is done.
     """
     postargs = (differ, opts, buffered)
-    if opts.get(b'template') in {b'cbor', b'json'}:
+    spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
+
+    # machine-readable formats have slightly different keyword set than
+    # plain templates, which are handled by changesetformatter.
+    # note that {b'pickle', b'debug'} can also be added to the list if needed.
+    if spec.ref in {b'cbor', b'json'}:
         fm = ui.formatter(b'log', opts)
         return changesetformatter(ui, repo, fm, *postargs)
 
-    spec = _lookuptemplate(ui, opts.get(b'template'), opts.get(b'style'))
-
     if not spec.ref and not spec.tmpl and not spec.mapfile:
         return changesetprinter(ui, repo, *postargs)
 
diff --git a/tests/test-template-map.t b/tests/test-template-map.t
--- a/tests/test-template-map.t
+++ b/tests/test-template-map.t
@@ -1101,6 +1101,15 @@  honor --git but not format-breaking diff
    }
   ]
 
+Other unsupported formatter styles:
+
+  $ hg log -qr . -Tpickle
+  abort: "pickle" not in template map
+  [255]
+  $ hg log -qr . -Tdebug
+  abort: "debug" not in template map
+  [255]
+
 Error if style not readable:
 
 #if unix-permissions no-root