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