##// END OF EJS Templates
formatter: add a method to build a full templater from a -T option
Matt Mackall -
r25512:8463433c default
parent child Browse files
Show More
@@ -1,188 +1,195 b''
1 # formatter.py - generic output formatting for mercurial
1 # formatter.py - generic output formatting for mercurial
2 #
2 #
3 # Copyright 2012 Matt Mackall <mpm@selenic.com>
3 # Copyright 2012 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import cPickle
8 import cPickle
9 from node import hex, short
9 from node import hex, short
10 from i18n import _
10 from i18n import _
11 import encoding, util
11 import encoding, util
12 import templater
12 import templater
13 import os
13 import os
14
14
15 class baseformatter(object):
15 class baseformatter(object):
16 def __init__(self, ui, topic, opts):
16 def __init__(self, ui, topic, opts):
17 self._ui = ui
17 self._ui = ui
18 self._topic = topic
18 self._topic = topic
19 self._style = opts.get("style")
19 self._style = opts.get("style")
20 self._template = opts.get("template")
20 self._template = opts.get("template")
21 self._item = None
21 self._item = None
22 # function to convert node to string suitable for this output
22 # function to convert node to string suitable for this output
23 self.hexfunc = hex
23 self.hexfunc = hex
24 def __nonzero__(self):
24 def __nonzero__(self):
25 '''return False if we're not doing real templating so we can
25 '''return False if we're not doing real templating so we can
26 skip extra work'''
26 skip extra work'''
27 return True
27 return True
28 def _showitem(self):
28 def _showitem(self):
29 '''show a formatted item once all data is collected'''
29 '''show a formatted item once all data is collected'''
30 pass
30 pass
31 def startitem(self):
31 def startitem(self):
32 '''begin an item in the format list'''
32 '''begin an item in the format list'''
33 if self._item is not None:
33 if self._item is not None:
34 self._showitem()
34 self._showitem()
35 self._item = {}
35 self._item = {}
36 def data(self, **data):
36 def data(self, **data):
37 '''insert data into item that's not shown in default output'''
37 '''insert data into item that's not shown in default output'''
38 self._item.update(data)
38 self._item.update(data)
39 def write(self, fields, deftext, *fielddata, **opts):
39 def write(self, fields, deftext, *fielddata, **opts):
40 '''do default text output while assigning data to item'''
40 '''do default text output while assigning data to item'''
41 for k, v in zip(fields.split(), fielddata):
41 for k, v in zip(fields.split(), fielddata):
42 self._item[k] = v
42 self._item[k] = v
43 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
43 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
44 '''do conditional write (primarily for plain formatter)'''
44 '''do conditional write (primarily for plain formatter)'''
45 for k, v in zip(fields.split(), fielddata):
45 for k, v in zip(fields.split(), fielddata):
46 self._item[k] = v
46 self._item[k] = v
47 def plain(self, text, **opts):
47 def plain(self, text, **opts):
48 '''show raw text for non-templated mode'''
48 '''show raw text for non-templated mode'''
49 pass
49 pass
50 def end(self):
50 def end(self):
51 '''end output for the formatter'''
51 '''end output for the formatter'''
52 if self._item is not None:
52 if self._item is not None:
53 self._showitem()
53 self._showitem()
54
54
55 class plainformatter(baseformatter):
55 class plainformatter(baseformatter):
56 '''the default text output scheme'''
56 '''the default text output scheme'''
57 def __init__(self, ui, topic, opts):
57 def __init__(self, ui, topic, opts):
58 baseformatter.__init__(self, ui, topic, opts)
58 baseformatter.__init__(self, ui, topic, opts)
59 if ui.debugflag:
59 if ui.debugflag:
60 self.hexfunc = hex
60 self.hexfunc = hex
61 else:
61 else:
62 self.hexfunc = short
62 self.hexfunc = short
63 def __nonzero__(self):
63 def __nonzero__(self):
64 return False
64 return False
65 def startitem(self):
65 def startitem(self):
66 pass
66 pass
67 def data(self, **data):
67 def data(self, **data):
68 pass
68 pass
69 def write(self, fields, deftext, *fielddata, **opts):
69 def write(self, fields, deftext, *fielddata, **opts):
70 self._ui.write(deftext % fielddata, **opts)
70 self._ui.write(deftext % fielddata, **opts)
71 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
71 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
72 '''do conditional write'''
72 '''do conditional write'''
73 if cond:
73 if cond:
74 self._ui.write(deftext % fielddata, **opts)
74 self._ui.write(deftext % fielddata, **opts)
75 def plain(self, text, **opts):
75 def plain(self, text, **opts):
76 self._ui.write(text, **opts)
76 self._ui.write(text, **opts)
77 def end(self):
77 def end(self):
78 pass
78 pass
79
79
80 class debugformatter(baseformatter):
80 class debugformatter(baseformatter):
81 def __init__(self, ui, topic, opts):
81 def __init__(self, ui, topic, opts):
82 baseformatter.__init__(self, ui, topic, opts)
82 baseformatter.__init__(self, ui, topic, opts)
83 self._ui.write("%s = [\n" % self._topic)
83 self._ui.write("%s = [\n" % self._topic)
84 def _showitem(self):
84 def _showitem(self):
85 self._ui.write(" " + repr(self._item) + ",\n")
85 self._ui.write(" " + repr(self._item) + ",\n")
86 def end(self):
86 def end(self):
87 baseformatter.end(self)
87 baseformatter.end(self)
88 self._ui.write("]\n")
88 self._ui.write("]\n")
89
89
90 class pickleformatter(baseformatter):
90 class pickleformatter(baseformatter):
91 def __init__(self, ui, topic, opts):
91 def __init__(self, ui, topic, opts):
92 baseformatter.__init__(self, ui, topic, opts)
92 baseformatter.__init__(self, ui, topic, opts)
93 self._data = []
93 self._data = []
94 def _showitem(self):
94 def _showitem(self):
95 self._data.append(self._item)
95 self._data.append(self._item)
96 def end(self):
96 def end(self):
97 baseformatter.end(self)
97 baseformatter.end(self)
98 self._ui.write(cPickle.dumps(self._data))
98 self._ui.write(cPickle.dumps(self._data))
99
99
100 def _jsonifyobj(v):
100 def _jsonifyobj(v):
101 if isinstance(v, tuple):
101 if isinstance(v, tuple):
102 return '[' + ', '.join(_jsonifyobj(e) for e in v) + ']'
102 return '[' + ', '.join(_jsonifyobj(e) for e in v) + ']'
103 elif v is None:
103 elif v is None:
104 return 'null'
104 return 'null'
105 elif v is True:
105 elif v is True:
106 return 'true'
106 return 'true'
107 elif v is False:
107 elif v is False:
108 return 'false'
108 return 'false'
109 elif isinstance(v, (int, float)):
109 elif isinstance(v, (int, float)):
110 return str(v)
110 return str(v)
111 else:
111 else:
112 return '"%s"' % encoding.jsonescape(v)
112 return '"%s"' % encoding.jsonescape(v)
113
113
114 class jsonformatter(baseformatter):
114 class jsonformatter(baseformatter):
115 def __init__(self, ui, topic, opts):
115 def __init__(self, ui, topic, opts):
116 baseformatter.__init__(self, ui, topic, opts)
116 baseformatter.__init__(self, ui, topic, opts)
117 self._ui.write("[")
117 self._ui.write("[")
118 self._ui._first = True
118 self._ui._first = True
119 def _showitem(self):
119 def _showitem(self):
120 if self._ui._first:
120 if self._ui._first:
121 self._ui._first = False
121 self._ui._first = False
122 else:
122 else:
123 self._ui.write(",")
123 self._ui.write(",")
124
124
125 self._ui.write("\n {\n")
125 self._ui.write("\n {\n")
126 first = True
126 first = True
127 for k, v in sorted(self._item.items()):
127 for k, v in sorted(self._item.items()):
128 if first:
128 if first:
129 first = False
129 first = False
130 else:
130 else:
131 self._ui.write(",\n")
131 self._ui.write(",\n")
132 self._ui.write(' "%s": %s' % (k, _jsonifyobj(v)))
132 self._ui.write(' "%s": %s' % (k, _jsonifyobj(v)))
133 self._ui.write("\n }")
133 self._ui.write("\n }")
134 def end(self):
134 def end(self):
135 baseformatter.end(self)
135 baseformatter.end(self)
136 self._ui.write("\n]\n")
136 self._ui.write("\n]\n")
137
137
138 def lookuptemplate(ui, topic, tmpl):
138 def lookuptemplate(ui, topic, tmpl):
139 # looks like a literal template?
139 # looks like a literal template?
140 if '{' in tmpl:
140 if '{' in tmpl:
141 return tmpl, None
141 return tmpl, None
142
142
143 # perhaps a stock style?
143 # perhaps a stock style?
144 if not os.path.split(tmpl)[0]:
144 if not os.path.split(tmpl)[0]:
145 mapname = (templater.templatepath('map-cmdline.' + tmpl)
145 mapname = (templater.templatepath('map-cmdline.' + tmpl)
146 or templater.templatepath(tmpl))
146 or templater.templatepath(tmpl))
147 if mapname and os.path.isfile(mapname):
147 if mapname and os.path.isfile(mapname):
148 return None, mapname
148 return None, mapname
149
149
150 # perhaps it's a reference to [templates]
150 # perhaps it's a reference to [templates]
151 t = ui.config('templates', tmpl)
151 t = ui.config('templates', tmpl)
152 if t:
152 if t:
153 try:
153 try:
154 tmpl = templater.unquotestring(t)
154 tmpl = templater.unquotestring(t)
155 except SyntaxError:
155 except SyntaxError:
156 tmpl = t
156 tmpl = t
157 return tmpl, None
157 return tmpl, None
158
158
159 if tmpl == 'list':
159 if tmpl == 'list':
160 ui.write(_("available styles: %s\n") % templater.stylelist())
160 ui.write(_("available styles: %s\n") % templater.stylelist())
161 raise util.Abort(_("specify a template"))
161 raise util.Abort(_("specify a template"))
162
162
163 # perhaps it's a path to a map or a template
163 # perhaps it's a path to a map or a template
164 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
164 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
165 # is it a mapfile for a style?
165 # is it a mapfile for a style?
166 if os.path.basename(tmpl).startswith("map-"):
166 if os.path.basename(tmpl).startswith("map-"):
167 return None, os.path.realpath(tmpl)
167 return None, os.path.realpath(tmpl)
168 tmpl = open(tmpl).read()
168 tmpl = open(tmpl).read()
169 return tmpl, None
169 return tmpl, None
170
170
171 # constant string?
171 # constant string?
172 return tmpl, None
172 return tmpl, None
173
173
174 def gettemplater(ui, topic, spec):
175 tmpl, mapfile = lookuptemplate(ui, topic, spec)
176 t = templater.templater(mapfile, {})
177 if tmpl:
178 t.cache[topic] = tmpl
179 return t
180
174 def formatter(ui, topic, opts):
181 def formatter(ui, topic, opts):
175 template = opts.get("template", "")
182 template = opts.get("template", "")
176 if template == "json":
183 if template == "json":
177 return jsonformatter(ui, topic, opts)
184 return jsonformatter(ui, topic, opts)
178 elif template == "pickle":
185 elif template == "pickle":
179 return pickleformatter(ui, topic, opts)
186 return pickleformatter(ui, topic, opts)
180 elif template == "debug":
187 elif template == "debug":
181 return debugformatter(ui, topic, opts)
188 return debugformatter(ui, topic, opts)
182 elif template != "":
189 elif template != "":
183 raise util.Abort(_("custom templates not yet supported"))
190 raise util.Abort(_("custom templates not yet supported"))
184 elif ui.configbool('ui', 'formatdebug'):
191 elif ui.configbool('ui', 'formatdebug'):
185 return debugformatter(ui, topic, opts)
192 return debugformatter(ui, topic, opts)
186 elif ui.configbool('ui', 'formatjson'):
193 elif ui.configbool('ui', 'formatjson'):
187 return jsonformatter(ui, topic, opts)
194 return jsonformatter(ui, topic, opts)
188 return plainformatter(ui, topic, opts)
195 return plainformatter(ui, topic, opts)
General Comments 0
You need to be logged in to leave comments. Login now