Patchwork [1,of,2] archive: use a templater to build the metadata file

login
register
mail settings
Submitter Matt Harbison
Date July 17, 2017, 4:57 a.m.
Message ID <4d37def90ad5e0196dad.1500267458@Envy>
Download mbox | patch
Permalink /patch/22443/
State Accepted
Headers show

Comments

Matt Harbison - July 17, 2017, 4:57 a.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1500241236 14400
#      Sun Jul 16 17:40:36 2017 -0400
# Node ID 4d37def90ad5e0196dadb9bc2c9e62effad63691
# Parent  d09de637cbc88ed2db989298115d0c0cb6cc6f27
archive: use a templater to build the metadata file

There are no visible changes here.

I'm starting to wonder if adding the '+' to the 'node' line instead of a
separate key line in 3047167733dc was the right thing to do.  The '{node}'
keyword never includes '+' elsewhere, and the way setup.py works, it would
truncate it anyway.  Additionally, the file is missing '{p2node}' when 'wdir()'
merges are archived.  I thought about adding an 'identify' line that would
correspond to `hg id -n`.  But the other nodes are the full 40 characters, and
the output most useful for versioning is the short form.  All of this cries out
for customization via templating.  (Although maybe having the short identify
line by default is still a good idea.)
Yuya Nishihara - July 17, 2017, 1:53 p.m.
On Mon, 17 Jul 2017 00:57:38 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison@yahoo.com>
> # Date 1500241236 14400
> #      Sun Jul 16 17:40:36 2017 -0400
> # Node ID 4d37def90ad5e0196dadb9bc2c9e62effad63691
> # Parent  d09de637cbc88ed2db989298115d0c0cb6cc6f27
> archive: use a templater to build the metadata file

Queued, thanks.

> +    default = (
> +        r'repo: {root}\n'
> +        r'node: {ifcontains(rev, revset("wdir()"),'
> +                            r'"{p1node}{dirty}", "{node}")}\n'
> +        r'branch: {branch|utf8}\n'
>  
> -    base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
> -        _rootctx(repo).hex(), hex, encoding.fromlocal(ctx.branch()))
> +        # {tags} on ctx includes local tags and 'tip', with no current way to
> +        # limit that to global tags.  Therefore, use {latesttag} as a substitute
> +        # when the distance is 0, since that will be the list of global tags on
> +        # ctx.
> +        r'{ifeq(latesttagdistance, 0, latesttag % "tag: {tag}\n",'
> +                       r'"{latesttag % "latesttag: {tag}\n"}'
> +                       r'latesttagdistance: {latesttagdistance}\n'
> +                       r'changessincelatesttag: {changessincelatesttag}\n")}'

You could use {separate('', '', ...)} to eliminate these weird indents.
Matt Harbison - July 18, 2017, 3:08 a.m.
On Mon, 17 Jul 2017 09:53:12 -0400, Yuya Nishihara <yuya@tcha.org> wrote:

> On Mon, 17 Jul 2017 00:57:38 -0400, Matt Harbison wrote:
>> # HG changeset patch
>> # User Matt Harbison <matt_harbison@yahoo.com>
>> # Date 1500241236 14400
>> #      Sun Jul 16 17:40:36 2017 -0400
>> # Node ID 4d37def90ad5e0196dadb9bc2c9e62effad63691
>> # Parent  d09de637cbc88ed2db989298115d0c0cb6cc6f27
>> archive: use a templater to build the metadata file
>
> Queued, thanks.
>
>> +    default = (
>> +        r'repo: {root}\n'
>> +        r'node: {ifcontains(rev, revset("wdir()"),'
>> +                            r'"{p1node}{dirty}", "{node}")}\n'
>> +        r'branch: {branch|utf8}\n'
>>
>> -    base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
>> -        _rootctx(repo).hex(), hex, encoding.fromlocal(ctx.branch()))
>> +        # {tags} on ctx includes local tags and 'tip', with no current  
>> way to
>> +        # limit that to global tags.  Therefore, use {latesttag} as a  
>> substitute
>> +        # when the distance is 0, since that will be the list of  
>> global tags on
>> +        # ctx.
>> +        r'{ifeq(latesttagdistance, 0, latesttag % "tag: {tag}\n",'
>> +                       r'"{latesttag % "latesttag: {tag}\n"}'
>> +                       r'latesttagdistance: {latesttagdistance}\n'
>> +                       r'changessincelatesttag:  
>> {changessincelatesttag}\n")}'
>
> You could use {separate('', '', ...)} to eliminate these weird indents.

I'm not sure what you mean.  I indented like this to vertically line up  
the true and false args to ifeq() for readability.  (Originally I used  
'tags' as the first arg, and it all lined up until I figured out how to  
hack around local tags in the {tags} keyword.  So that was a failure.)
Yuya Nishihara - July 18, 2017, 12:39 p.m.
On Mon, 17 Jul 2017 23:08:25 -0400, Matt Harbison wrote:
> On Mon, 17 Jul 2017 09:53:12 -0400, Yuya Nishihara <yuya@tcha.org> wrote:
> 
> > On Mon, 17 Jul 2017 00:57:38 -0400, Matt Harbison wrote:
> >> # HG changeset patch
> >> # User Matt Harbison <matt_harbison@yahoo.com>
> >> # Date 1500241236 14400
> >> #      Sun Jul 16 17:40:36 2017 -0400
> >> # Node ID 4d37def90ad5e0196dadb9bc2c9e62effad63691
> >> # Parent  d09de637cbc88ed2db989298115d0c0cb6cc6f27
> >> archive: use a templater to build the metadata file
> >
> > Queued, thanks.
> >
> >> +    default = (
> >> +        r'repo: {root}\n'
> >> +        r'node: {ifcontains(rev, revset("wdir()"),'
> >> +                            r'"{p1node}{dirty}", "{node}")}\n'
> >> +        r'branch: {branch|utf8}\n'
> >>
> >> -    base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
> >> -        _rootctx(repo).hex(), hex, encoding.fromlocal(ctx.branch()))
> >> +        # {tags} on ctx includes local tags and 'tip', with no current  
> >> way to
> >> +        # limit that to global tags.  Therefore, use {latesttag} as a  
> >> substitute
> >> +        # when the distance is 0, since that will be the list of  
> >> global tags on
> >> +        # ctx.
> >> +        r'{ifeq(latesttagdistance, 0, latesttag % "tag: {tag}\n",'
> >> +                       r'"{latesttag % "latesttag: {tag}\n"}'
> >> +                       r'latesttagdistance: {latesttagdistance}\n'
> >> +                       r'changessincelatesttag:  
> >> {changessincelatesttag}\n")}'
> >
> > You could use {separate('', '', ...)} to eliminate these weird indents.
> 
> I'm not sure what you mean.  I indented like this to vertically line up  
> the true and false args to ifeq() for readability.  (Originally I used  
> 'tags' as the first arg, and it all lined up until I figured out how to  
> hack around local tags in the {tags} keyword.  So that was a failure.)

separate() could be used to indent template fragments in string.

  r'{ifeq(...,
  r'      separate("",'
  r'               "{latesttag % "latesttag: {tag}\n"}",'
  r'               "latesttagdistance: {latesttagdistance}\n",'
  ...

Patch

diff --git a/mercurial/archival.py b/mercurial/archival.py
--- a/mercurial/archival.py
+++ b/mercurial/archival.py
@@ -21,6 +21,7 @@ 
     cmdutil,
     encoding,
     error,
+    formatter,
     match as matchmod,
     util,
     vfs as vfsmod,
@@ -80,30 +81,42 @@ 
 def buildmetadata(ctx):
     '''build content of .hg_archival.txt'''
     repo = ctx.repo()
-    hex = ctx.hex()
-    if ctx.rev() is None:
-        hex = ctx.p1().hex()
-        if ctx.dirty(missing=True):
-            hex += '+'
+
+    default = (
+        r'repo: {root}\n'
+        r'node: {ifcontains(rev, revset("wdir()"),'
+                            r'"{p1node}{dirty}", "{node}")}\n'
+        r'branch: {branch|utf8}\n'
 
-    base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
-        _rootctx(repo).hex(), hex, encoding.fromlocal(ctx.branch()))
+        # {tags} on ctx includes local tags and 'tip', with no current way to
+        # limit that to global tags.  Therefore, use {latesttag} as a substitute
+        # when the distance is 0, since that will be the list of global tags on
+        # ctx.
+        r'{ifeq(latesttagdistance, 0, latesttag % "tag: {tag}\n",'
+                       r'"{latesttag % "latesttag: {tag}\n"}'
+                       r'latesttagdistance: {latesttagdistance}\n'
+                       r'changessincelatesttag: {changessincelatesttag}\n")}'
+    )
 
-    tags = ''.join('tag: %s\n' % t for t in ctx.tags()
-                   if repo.tagtype(t) == 'global')
-    if not tags:
-        repo.ui.pushbuffer()
-        opts = {'template': '{latesttag}\n{latesttagdistance}\n'
-                            '{changessincelatesttag}',
-                'style': '', 'patch': None, 'git': None}
-        cmdutil.show_changeset(repo.ui, repo, opts).show(ctx)
-        ltags, dist, changessince = repo.ui.popbuffer().split('\n')
-        ltags = ltags.split(':')
-        tags = ''.join('latesttag: %s\n' % t for t in ltags)
-        tags += 'latesttagdistance: %s\n' % dist
-        tags += 'changessincelatesttag: %s\n' % changessince
+    opts = {
+        'template': default
+    }
+
+    out = util.stringio()
 
-    return base + tags
+    fm = formatter.formatter(repo.ui, out, 'archive', opts)
+    fm.startitem()
+    fm.context(ctx=ctx)
+    fm.data(root=_rootctx(repo).hex())
+
+    if ctx.rev() is None:
+        dirty = ''
+        if ctx.dirty(missing=True):
+            dirty = '+'
+        fm.data(dirty=dirty)
+    fm.end()
+
+    return out.getvalue()
 
 class tarit(object):
     '''write archive to tar file or stream.  can write uncompressed,