Issue1164

Title Exception from {files|escape} in log template
Priority bug Status chatting
Superseder Nosy List abuehl, arghman, djc, dougxc, esskov, jwwalker, tonfa
Assigned To Topics patch

Created on 2008-06-05.16:42:22 by jwwalker, last changed 2009-08-15.15:11:07 by esskov.

Messages
msg10337 (view) Author: esskov Date: 2009-08-15.15:11:07
Trying to correctly parse the output of -

hg log --template "{files}\n"

- for filenames containing spaces led me to -

hg log --template "{files|urlescape}\n"

- which gives me "abort: template: no key named 'my-file'", after which I
found this issue. I then tried -

hg log --template "{files|stringify|urlescape}\n"

- as mentioned below. This will run but does not solve the basic problem,
because it produces output such as this (for 2 files):

a%20file%20name%20another_file

So, am I correct in concluding that currently there is no "--template
{files}" filter which can handle filenames containing spaces, such that the
output can be correctly parsed?
msg7696 (view) Author: djc Date: 2008-10-29.10:04:18
That's basically the same issue in reverse, I guess.
msg7695 (view) Author: tonfa Date: 2008-10-29.09:43:10
There's a related issue:
hg tip --template='{files|json}\n'

Will print

["file1 file2"] instead of ["file1", "file2"]
msg7370 (view) Author: dougxc Date: 2008-10-09.21:04:09
I have had a similar issue when trying to use {files|tabindent} in a template.
It crashed hg with:

AttributeError: 'generator' object has no attribute 'splitlines'

To fix this, I added a new filter in templatefilters.py:

    "ws2nl": lambda x: re.sub('\s+', '\n', x),

that simply replaces one or more white spaces with a single newline. Now
I get the effect I want with {files|stringify|ws2nl|tabindent} in my template.
I'd like to propose adding this filter to the official HG sources but am not
sure what the process is.
msg7179 (view) Author: djc Date: 2008-09-22.07:49:48
Right, but that's still problematic for tags|stringescape, for example.
msg7178 (view) Author: tonfa Date: 2008-09-22.07:47:53
I don't stringify everything, just filters that assume they are given a string.
msg7177 (view) Author: djc Date: 2008-09-22.07:43:45
I think I dabbled with a patch like this (adding some stringify calls), but we
decided that it wasn't the best solutions since it can obscure some issues. That
is, some things need commas in between elements of the generator (tags, for
example), or you can't distinguish tags that have a space in them anymore. Just
stringifying everything is not the best solution, I think.
msg7025 (view) Author: tonfa Date: 2008-09-09.16:48:00
It should be split in 2 patches (one to reorder logically the filter table, the
other to stringify the formatting filters).

diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py
--- a/mercurial/templatefilters.py
+++ b/mercurial/templatefilters.py
@@ -152,33 +152,48 @@
     else:
         raise TypeError('cannot encode type %s' % obj.__class__.__name__)
 
+def stringifyfn(fn):
+    '''expand a string before it is passed to a filter.'''
+    return lambda x: fn(templater.stringify(x))
+
 filters = {
-    "addbreaks": nl2br,
-    "basename": os.path.basename,
+    # dates
     "age": age,
     "date": lambda x: util.datestr(x),
-    "domain": domain,
-    "email": util.email,
-    "escape": lambda x: cgi.escape(x, True),
-    "fill68": lambda x: fill(x, width=68),
-    "fill76": lambda x: fill(x, width=76),
-    "firstline": firstline,
-    "tabindent": lambda x: indent(x, '\t'),
     "hgdate": lambda x: "%d %d" % x,
     "isodate": lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2'),
     "isodatesec": lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2'),
-    "obfuscate": obfuscate,
-    "permissions": permissions,
-    "person": person,
     "rfc822date": lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2"),
     "rfc3339date": lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2"),
-    "short": lambda x: x[:12],
     "shortdate": util.shortdate,
+
+    # string formatting
+    "addbreaks": stringifyfn(nl2br),
+    "escape": stringifyfn(lambda x: cgi.escape(x, True)),
+    "fill68": stringifyfn(lambda x: fill(x, width=68)),
+    "fill76": stringifyfn(lambda x: fill(x, width=76)),
+    "firstline": stringifyfn(firstline),
     "stringify": templater.stringify,
-    "strip": lambda x: x.strip(),
-    "urlescape": lambda x: urllib.quote(x),
-    "user": lambda x: util.shortuser(x),
-    "stringescape": lambda x: x.encode('string_escape'),
-    "xmlescape": xmlescape,
+    "strip": stringifyfn(lambda x: x.strip()),
+    "tabindent": stringifyfn(lambda x: indent(x, '\t')),
+
+    # escaping / obfuscating
+    "obfuscate": stringifyfn(obfuscate),
+    "urlescape": stringifyfn(lambda x: urllib.quote(x)),
+    "stringescape": stringifyfn(lambda x: x.encode('string_escape')),
+    "xmlescape": stringifyfn(xmlescape),
+
+    # cset extraction
+    "domain": stringifyfn(domain),
+    "email": stringifyfn(util.email),
+    "permissions": permissions,
+    "person": stringifyfn(person),
+    "short": stringifyfn(lambda x: x[:12]),
+    "user": stringifyfn(lambda x: util.shortuser(x)),
+
+    # filenames
+    "basename": stringifyfn(os.path.basename),
+
+    # serialization
     "json": json,
 }
msg6218 (view) Author: jwwalker Date: 2008-06-07.19:58:02
I'm certainly willing to write for the wiki when I feel knowledgeable on a topic, 
as with the HandlingMacResourceFiles page I wrote.  However, I don't speak Python, 
so if the only way to find out about something is to read the source code, then 
I'm not your guy.
msg6196 (view) Author: abuehl Date: 2008-06-07.08:36:15
On 07.06.2008 09:42, James Walker wrote:
> OK, I guess that works, but stringify isn't mentioned in the book, or anywhere on 
> the wiki, so how would anyone know about it?

Hi James

If you could help writing to the wiki on this topic (or others), that
would be fantastic! Contributions to the wiki are most welcome (note that
I'm not "chef de cusine" there, I just happen to have edited a lot over
the last couple of months, mostly doing small tweaks/refactorings).

Adrian Buehlmann
msg6194 (view) Author: jwwalker Date: 2008-06-07.07:42:39
OK, I guess that works, but stringify isn't mentioned in the book, or anywhere on 
the wiki, so how would anyone know about it?
msg6181 (view) Author: djc Date: 2008-06-06.07:28:53
Ah yes, I think I remember this one. Files is a generator, and so you can't
escape it without explicitly stringifying it, I think.

You should try files|stringify|escape as a workaround.

On the other hand, we need a better error message, I guess.
msg6180 (view) Author: jwwalker Date: 2008-06-05.16:42:20
When I tried
  hg log --template "files: {files|escape}\n"
I got this:


** unknown exception encountered, details follow
** report bug details to http://www.selenic.com/mercurial/bts
** or mercurial@selenic.com
** Mercurial Distributed SCM (version 1.0.1)
Traceback (most recent call last):
  File "/usr/local/bin/hg", line 20, in <module>
    mercurial.dispatch.run()
  File "/Library/Python/2.5/site-packages/mercurial/dispatch.py", line 20, in 
run
    sys.exit(dispatch(sys.argv[1:]))
  File "/Library/Python/2.5/site-packages/mercurial/dispatch.py", line 29, in 
dispatch
    return _runcatch(u, args)
  File "/Library/Python/2.5/site-packages/mercurial/dispatch.py", line 45, in 
_runcatch
    return _dispatch(ui, args)
  File "/Library/Python/2.5/site-packages/mercurial/dispatch.py", line 364, in 
_dispatch
    ret = _runcommand(ui, options, cmd, d)
  File "/Library/Python/2.5/site-packages/mercurial/dispatch.py", line 417, in 
_runcommand
    return checkargs()
  File "/Library/Python/2.5/site-packages/mercurial/dispatch.py", line 373, in 
checkargs
    return cmdfunc()
  File "/Library/Python/2.5/site-packages/mercurial/dispatch.py", line 356, in 
<lambda>
    d = lambda: func(ui, repo, *args, **cmdoptions)
  File "/Library/Python/2.5/site-packages/mercurial/commands.py", line 1816, in 
log
    displayer.show(rev, changenode, copies=copies)
  File "/Library/Python/2.5/site-packages/mercurial/cmdutil.py", line 585, in 
show
    self._show(rev, changenode, copies, props)
  File "/Library/Python/2.5/site-packages/mercurial/cmdutil.py", line 864, in 
_show
    self.ui.write(templater.stringify(self.t(key, **props)))
  File "/Library/Python/2.5/site-packages/mercurial/templater.py", line 148, in 
stringify
    return "".join([stringify(t) for t in thing if t is not None])
  File "/Library/Python/2.5/site-packages/mercurial/templater.py", line 126, in 
__call__
    v = self.filters[f](v)
  File "/Library/Python/2.5/site-packages/mercurial/templatefilters.py", line 
132, in <lambda>
    "escape": lambda x: cgi.escape(x, True),
  File 
"/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/cgi.py", 
line 1046, in escape
    s = s.replace("&", "&amp;") # Must be done first!
AttributeError: 'generator' object has no attribute 'replace'
History
Date User Action Args
2009-08-15 15:11:07esskovsetnosy: + esskov
messages: + msg10337
2009-01-24 00:48:52arghmansetnosy: + arghman
2008-10-29 10:04:19djcsetnosy: tonfa, djc, abuehl, jwwalker, dougxc
messages: + msg7696
2008-10-29 09:43:10tonfasetnosy: tonfa, djc, abuehl, jwwalker, dougxc
messages: + msg7695
2008-10-09 21:04:09dougxcsetnosy: + dougxc
messages: + msg7370
2008-09-22 07:49:48djcsetnosy: tonfa, djc, abuehl, jwwalker
messages: + msg7179
2008-09-22 07:47:53tonfasetnosy: tonfa, djc, abuehl, jwwalker
messages: + msg7178
2008-09-22 07:43:46djcsetnosy: tonfa, djc, abuehl, jwwalker
messages: + msg7177
2008-09-20 14:19:17tonfasettopic: + patch
nosy: tonfa, djc, abuehl, jwwalker
2008-09-09 16:48:01tonfasetnosy: + tonfa
messages: + msg7025
2008-06-07 19:58:03jwwalkersetnosy: djc, abuehl, jwwalker
messages: + msg6218
2008-06-07 08:36:15abuehlsetnosy: djc, abuehl, jwwalker
messages: + msg6196
2008-06-07 07:42:39jwwalkersetnosy: djc, abuehl, jwwalker
messages: + msg6194
2008-06-06 07:28:54djcsetstatus: unread -> chatting
nosy: + djc
messages: + msg6181
2008-06-05 16:46:26abuehlsetnosy: + abuehl
2008-06-05 16:42:22jwwalkercreate