Patchwork [7,of,9] export: port _exportsingle() to formatter

login
register
mail settings
Submitter Yuya Nishihara
Date April 12, 2018, 4:17 p.m.
Message ID <6041c9cdcee8f2532801.1523549830@mimosa>
Download mbox | patch
Permalink /patch/30814/
State Accepted
Headers show

Comments

Yuya Nishihara - April 12, 2018, 4:17 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1523540383 -32400
#      Thu Apr 12 22:39:43 2018 +0900
# Node ID 6041c9cdcee8f25328016f1727055d1bc1677054
# Parent  724b281e9d9b9ebd91d5ab12482f93a25efb1259
export: port _exportsingle() to formatter

Pass 'fm' instead of 'write', and use fm.plain(), fm.write(), etc. instead.
The callers will be updated later.
Gregory Szorc - April 12, 2018, 4:51 p.m.
On Thu, Apr 12, 2018 at 9:17 AM, Yuya Nishihara <yuya@tcha.org> wrote:

> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1523540383 -32400
> #      Thu Apr 12 22:39:43 2018 +0900
> # Node ID 6041c9cdcee8f25328016f1727055d1bc1677054
> # Parent  724b281e9d9b9ebd91d5ab12482f93a25efb1259
> export: port _exportsingle() to formatter
>
> Pass 'fm' instead of 'write', and use fm.plain(), fm.write(), etc. instead.
> The callers will be updated later.
>
> diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
> --- a/mercurial/cmdutil.py
> +++ b/mercurial/cmdutil.py
> @@ -1522,7 +1522,7 @@ extraexport = []
>  # it is given two arguments (sequencenumber, changectx)
>  extraexportmap = {}
>
> -def _exportsingle(repo, ctx, match, switch_parent, seqno, write,
> diffopts):
> +def _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts):
>      node = scmutil.binnode(ctx)
>      parents = [p.node() for p in ctx.parents() if p]
>      branch = ctx.branch()
> @@ -1534,42 +1534,53 @@ def _exportsingle(repo, ctx, match, swit
>      else:
>          prev = nullid
>
> -    write("# HG changeset patch\n")
> -    write("# User %s\n" % ctx.user())
> -    write("# Date %d %d\n" % ctx.date())
> -    write("#      %s\n" % dateutil.datestr(ctx.date()))
> -    if branch and branch != 'default':
> -        write("# Branch %s\n" % branch)
> -    write("# Node ID %s\n" % hex(node))
> -    write("# Parent  %s\n" % hex(prev))
> +    fm.context(ctx=ctx)
> +    fm.plain('# HG changeset patch\n')
> +    fm.write('user', '# User %s\n', ctx.user())
> +    fm.plain('# Date %d %d\n' % ctx.date())
> +    fm.write('date', '#      %s\n', fm.formatdate(ctx.date()))
> +    fm.condwrite(branch and branch != 'default',
> +                 'branch', '# Branch %s\n', branch)
> +    fm.write('node', '# Node ID %s\n', hex(node))
> +    fm.plain('# Parent  %s\n' % hex(prev))
>      if len(parents) > 1:
> -        write("# Parent  %s\n" % hex(parents[1]))
> -
> +        fm.plain('# Parent  %s\n' % hex(parents[1]))
> +    fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents),
> name='node'))
> +
> +    # TODO: redesign extraexportmap function to support formatter
>      for headerid in extraexport:
>          header = extraexportmap[headerid](seqno, ctx)
>          if header is not None:
> -            write('# %s\n' % header)
> -    write(ctx.description().rstrip())
> -    write("\n\n")
> -
> -    for chunk, label in patch.diffui(repo, prev, node, match,
> opts=diffopts):
> -        write(chunk, label=label)
> +            fm.plain('# %s\n' % header)
> +
> +    fm.write('desc', '%s\n', ctx.description().rstrip())
> +    fm.plain('\n')
> +
> +    if fm.isplain():
> +        chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
> +        for chunk, label in chunkiter:
> +            fm.plain(chunk, label=label)
> +    else:
> +        chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
> +        # TODO: make it structured?
> +        fm.data(diff=b''.join(chunkiter))
>

A concern I have is that we'll want to keep the door open for writing the
diff chunks in a structured manner. That would seemingly require a
different key for the templater. But I think "diff" is fine as the key that
means "a textual diff format recognized by most patch tools." We can
introduce a "diffparts" (or similar) and make "diff" lazily evaluate as
follow-ups, when needed.


>
>  def _exportfile(repo, revs, fp, switch_parent, diffopts, match):
>      """Export changesets to stdout or a single file"""
>      dest = '<unnamed>'
>      if fp:
>          dest = getattr(fp, 'name', dest)
> -        def write(s, **kw):
> -            fp.write(s)
> +        fm = formatter.formatter(repo.ui, fp, 'export', {})
>      else:
> -        write = repo.ui.write
> +        fm = repo.ui.formatter('export', {})
>
>      for seqno, rev in enumerate(revs, 1):
>          ctx = repo[rev]
>          if not dest.startswith('<'):
>              repo.ui.note("%s\n" % dest)
> -        _exportsingle(repo, ctx, match, switch_parent, seqno, write,
> diffopts)
> +        fm.startitem()
> +        _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
> diffopts)
> +    fm.end()
>
>  def _exportfntemplate(repo, revs, fntemplate, switch_parent, diffopts,
> match):
>      """Export changesets to possibly multiple files"""
> @@ -1584,13 +1595,12 @@ def _exportfntemplate(repo, revs, fntemp
>          filemap.setdefault(dest, []).append((seqno, rev))
>
>      for dest in filemap:
> -        with open(dest, 'wb') as fo:
> +        with formatter.openformatter(repo.ui, dest, 'export', {}) as fm:
>              repo.ui.note("%s\n" % dest)
> -            def write(s, **kw):
> -                fo.write(s)
>              for seqno, rev in filemap[dest]:
> +                fm.startitem()
>                  ctx = repo[rev]
> -                _exportsingle(repo, ctx, match, switch_parent, seqno,
> write,
> +                _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
>                                diffopts)
>
>  def export(repo, revs, fntemplate='hg-%h.patch', fp=None,
> switch_parent=False,
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
Yuya Nishihara - April 13, 2018, 12:26 p.m.
On Thu, 12 Apr 2018 09:51:53 -0700, Gregory Szorc wrote:
> > +    if fm.isplain():
> > +        chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
> > +        for chunk, label in chunkiter:
> > +            fm.plain(chunk, label=label)
> > +    else:
> > +        chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
> > +        # TODO: make it structured?
> > +        fm.data(diff=b''.join(chunkiter))
> >
> 
> A concern I have is that we'll want to keep the door open for writing the
> diff chunks in a structured manner. That would seemingly require a
> different key for the templater. But I think "diff" is fine as the key that
> means "a textual diff format recognized by most patch tools." We can
> introduce a "diffparts" (or similar) and make "diff" lazily evaluate as
> follow-ups, when needed.

Yes. Since the key "diff" is used by 'log -Tjson -p', we'll have to leave it
as a textual diff.

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1522,7 +1522,7 @@  extraexport = []
 # it is given two arguments (sequencenumber, changectx)
 extraexportmap = {}
 
-def _exportsingle(repo, ctx, match, switch_parent, seqno, write, diffopts):
+def _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts):
     node = scmutil.binnode(ctx)
     parents = [p.node() for p in ctx.parents() if p]
     branch = ctx.branch()
@@ -1534,42 +1534,53 @@  def _exportsingle(repo, ctx, match, swit
     else:
         prev = nullid
 
-    write("# HG changeset patch\n")
-    write("# User %s\n" % ctx.user())
-    write("# Date %d %d\n" % ctx.date())
-    write("#      %s\n" % dateutil.datestr(ctx.date()))
-    if branch and branch != 'default':
-        write("# Branch %s\n" % branch)
-    write("# Node ID %s\n" % hex(node))
-    write("# Parent  %s\n" % hex(prev))
+    fm.context(ctx=ctx)
+    fm.plain('# HG changeset patch\n')
+    fm.write('user', '# User %s\n', ctx.user())
+    fm.plain('# Date %d %d\n' % ctx.date())
+    fm.write('date', '#      %s\n', fm.formatdate(ctx.date()))
+    fm.condwrite(branch and branch != 'default',
+                 'branch', '# Branch %s\n', branch)
+    fm.write('node', '# Node ID %s\n', hex(node))
+    fm.plain('# Parent  %s\n' % hex(prev))
     if len(parents) > 1:
-        write("# Parent  %s\n" % hex(parents[1]))
-
+        fm.plain('# Parent  %s\n' % hex(parents[1]))
+    fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name='node'))
+
+    # TODO: redesign extraexportmap function to support formatter
     for headerid in extraexport:
         header = extraexportmap[headerid](seqno, ctx)
         if header is not None:
-            write('# %s\n' % header)
-    write(ctx.description().rstrip())
-    write("\n\n")
-
-    for chunk, label in patch.diffui(repo, prev, node, match, opts=diffopts):
-        write(chunk, label=label)
+            fm.plain('# %s\n' % header)
+
+    fm.write('desc', '%s\n', ctx.description().rstrip())
+    fm.plain('\n')
+
+    if fm.isplain():
+        chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
+        for chunk, label in chunkiter:
+            fm.plain(chunk, label=label)
+    else:
+        chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
+        # TODO: make it structured?
+        fm.data(diff=b''.join(chunkiter))
 
 def _exportfile(repo, revs, fp, switch_parent, diffopts, match):
     """Export changesets to stdout or a single file"""
     dest = '<unnamed>'
     if fp:
         dest = getattr(fp, 'name', dest)
-        def write(s, **kw):
-            fp.write(s)
+        fm = formatter.formatter(repo.ui, fp, 'export', {})
     else:
-        write = repo.ui.write
+        fm = repo.ui.formatter('export', {})
 
     for seqno, rev in enumerate(revs, 1):
         ctx = repo[rev]
         if not dest.startswith('<'):
             repo.ui.note("%s\n" % dest)
-        _exportsingle(repo, ctx, match, switch_parent, seqno, write, diffopts)
+        fm.startitem()
+        _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts)
+    fm.end()
 
 def _exportfntemplate(repo, revs, fntemplate, switch_parent, diffopts, match):
     """Export changesets to possibly multiple files"""
@@ -1584,13 +1595,12 @@  def _exportfntemplate(repo, revs, fntemp
         filemap.setdefault(dest, []).append((seqno, rev))
 
     for dest in filemap:
-        with open(dest, 'wb') as fo:
+        with formatter.openformatter(repo.ui, dest, 'export', {}) as fm:
             repo.ui.note("%s\n" % dest)
-            def write(s, **kw):
-                fo.write(s)
             for seqno, rev in filemap[dest]:
+                fm.startitem()
                 ctx = repo[rev]
-                _exportsingle(repo, ctx, match, switch_parent, seqno, write,
+                _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
                               diffopts)
 
 def export(repo, revs, fntemplate='hg-%h.patch', fp=None, switch_parent=False,