##// END OF EJS Templates
phases: add a phase template keyword
Pierre-Yves David -
r15422:042e11c4 default
parent child Browse files
Show More
@@ -1,320 +1,325 b''
1 1 # templatekw.py - common changeset template keywords
2 2 #
3 3 # Copyright 2005-2009 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 from node import hex
9 9 import patch, util, error
10 10 import hbisect
11 11
12 12 def showlist(name, values, plural=None, **args):
13 13 '''expand set of values.
14 14 name is name of key in template map.
15 15 values is list of strings or dicts.
16 16 plural is plural of name, if not simply name + 's'.
17 17
18 18 expansion works like this, given name 'foo'.
19 19
20 20 if values is empty, expand 'no_foos'.
21 21
22 22 if 'foo' not in template map, return values as a string,
23 23 joined by space.
24 24
25 25 expand 'start_foos'.
26 26
27 27 for each value, expand 'foo'. if 'last_foo' in template
28 28 map, expand it instead of 'foo' for last key.
29 29
30 30 expand 'end_foos'.
31 31 '''
32 32 templ = args['templ']
33 33 if plural:
34 34 names = plural
35 35 else: names = name + 's'
36 36 if not values:
37 37 noname = 'no_' + names
38 38 if noname in templ:
39 39 yield templ(noname, **args)
40 40 return
41 41 if name not in templ:
42 42 if isinstance(values[0], str):
43 43 yield ' '.join(values)
44 44 else:
45 45 for v in values:
46 46 yield dict(v, **args)
47 47 return
48 48 startname = 'start_' + names
49 49 if startname in templ:
50 50 yield templ(startname, **args)
51 51 vargs = args.copy()
52 52 def one(v, tag=name):
53 53 try:
54 54 vargs.update(v)
55 55 except (AttributeError, ValueError):
56 56 try:
57 57 for a, b in v:
58 58 vargs[a] = b
59 59 except ValueError:
60 60 vargs[name] = v
61 61 return templ(tag, **vargs)
62 62 lastname = 'last_' + name
63 63 if lastname in templ:
64 64 last = values.pop()
65 65 else:
66 66 last = None
67 67 for v in values:
68 68 yield one(v)
69 69 if last is not None:
70 70 yield one(last, tag=lastname)
71 71 endname = 'end_' + names
72 72 if endname in templ:
73 73 yield templ(endname, **args)
74 74
75 75 def getfiles(repo, ctx, revcache):
76 76 if 'files' not in revcache:
77 77 revcache['files'] = repo.status(ctx.p1().node(), ctx.node())[:3]
78 78 return revcache['files']
79 79
80 80 def getlatesttags(repo, ctx, cache):
81 81 '''return date, distance and name for the latest tag of rev'''
82 82
83 83 if 'latesttags' not in cache:
84 84 # Cache mapping from rev to a tuple with tag date, tag
85 85 # distance and tag name
86 86 cache['latesttags'] = {-1: (0, 0, 'null')}
87 87 latesttags = cache['latesttags']
88 88
89 89 rev = ctx.rev()
90 90 todo = [rev]
91 91 while todo:
92 92 rev = todo.pop()
93 93 if rev in latesttags:
94 94 continue
95 95 ctx = repo[rev]
96 96 tags = [t for t in ctx.tags() if repo.tagtype(t) == 'global']
97 97 if tags:
98 98 latesttags[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
99 99 continue
100 100 try:
101 101 # The tuples are laid out so the right one can be found by
102 102 # comparison.
103 103 pdate, pdist, ptag = max(
104 104 latesttags[p.rev()] for p in ctx.parents())
105 105 except KeyError:
106 106 # Cache miss - recurse
107 107 todo.append(rev)
108 108 todo.extend(p.rev() for p in ctx.parents())
109 109 continue
110 110 latesttags[rev] = pdate, pdist + 1, ptag
111 111 return latesttags[rev]
112 112
113 113 def getrenamedfn(repo, endrev=None):
114 114 rcache = {}
115 115 if endrev is None:
116 116 endrev = len(repo)
117 117
118 118 def getrenamed(fn, rev):
119 119 '''looks up all renames for a file (up to endrev) the first
120 120 time the file is given. It indexes on the changerev and only
121 121 parses the manifest if linkrev != changerev.
122 122 Returns rename info for fn at changerev rev.'''
123 123 if fn not in rcache:
124 124 rcache[fn] = {}
125 125 fl = repo.file(fn)
126 126 for i in fl:
127 127 lr = fl.linkrev(i)
128 128 renamed = fl.renamed(fl.node(i))
129 129 rcache[fn][lr] = renamed
130 130 if lr >= endrev:
131 131 break
132 132 if rev in rcache[fn]:
133 133 return rcache[fn][rev]
134 134
135 135 # If linkrev != rev (i.e. rev not found in rcache) fallback to
136 136 # filectx logic.
137 137 try:
138 138 return repo[rev][fn].renamed()
139 139 except error.LookupError:
140 140 return None
141 141
142 142 return getrenamed
143 143
144 144
145 145 def showauthor(repo, ctx, templ, **args):
146 146 """:author: String. The unmodified author of the changeset."""
147 147 return ctx.user()
148 148
149 149 def showbisect(repo, ctx, templ, **args):
150 150 """:bisect: String. The changeset bisection status."""
151 151 return hbisect.label(repo, ctx.node())
152 152
153 153 def showbranch(**args):
154 154 """:branch: String. The name of the branch on which the changeset was
155 155 committed.
156 156 """
157 157 return args['ctx'].branch()
158 158
159 159 def showbranches(**args):
160 160 """:branches: List of strings. The name of the branch on which the
161 161 changeset was committed. Will be empty if the branch name was
162 162 default.
163 163 """
164 164 branch = args['ctx'].branch()
165 165 if branch != 'default':
166 166 return showlist('branch', [branch], plural='branches', **args)
167 167
168 168 def showbookmarks(**args):
169 169 """:bookmarks: List of strings. Any bookmarks associated with the
170 170 changeset.
171 171 """
172 172 bookmarks = args['ctx'].bookmarks()
173 173 return showlist('bookmark', bookmarks, **args)
174 174
175 175 def showchildren(**args):
176 176 """:children: List of strings. The children of the changeset."""
177 177 ctx = args['ctx']
178 178 childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
179 179 return showlist('children', childrevs, **args)
180 180
181 181 def showdate(repo, ctx, templ, **args):
182 182 """:date: Date information. The date when the changeset was committed."""
183 183 return ctx.date()
184 184
185 185 def showdescription(repo, ctx, templ, **args):
186 186 """:desc: String. The text of the changeset description."""
187 187 return ctx.description().strip()
188 188
189 189 def showdiffstat(repo, ctx, templ, **args):
190 190 """:diffstat: String. Statistics of changes with the following format:
191 191 "modified files: +added/-removed lines"
192 192 """
193 193 stats = patch.diffstatdata(util.iterlines(ctx.diff()))
194 194 maxname, maxtotal, adds, removes, binary = patch.diffstatsum(stats)
195 195 return '%s: +%s/-%s' % (len(stats), adds, removes)
196 196
197 197 def showextras(**args):
198 198 templ = args['templ']
199 199 for key, value in sorted(args['ctx'].extra().items()):
200 200 args = args.copy()
201 201 args.update(dict(key=key, value=value))
202 202 yield templ('extra', **args)
203 203
204 204 def showfileadds(**args):
205 205 """:file_adds: List of strings. Files added by this changeset."""
206 206 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
207 207 return showlist('file_add', getfiles(repo, ctx, revcache)[1], **args)
208 208
209 209 def showfilecopies(**args):
210 210 """:file_copies: List of strings. Files copied in this changeset with
211 211 their sources.
212 212 """
213 213 cache, ctx = args['cache'], args['ctx']
214 214 copies = args['revcache'].get('copies')
215 215 if copies is None:
216 216 if 'getrenamed' not in cache:
217 217 cache['getrenamed'] = getrenamedfn(args['repo'])
218 218 copies = []
219 219 getrenamed = cache['getrenamed']
220 220 for fn in ctx.files():
221 221 rename = getrenamed(fn, ctx.rev())
222 222 if rename:
223 223 copies.append((fn, rename[0]))
224 224
225 225 c = [{'name': x[0], 'source': x[1]} for x in copies]
226 226 return showlist('file_copy', c, plural='file_copies', **args)
227 227
228 228 # showfilecopiesswitch() displays file copies only if copy records are
229 229 # provided before calling the templater, usually with a --copies
230 230 # command line switch.
231 231 def showfilecopiesswitch(**args):
232 232 """:file_copies_switch: List of strings. Like "file_copies" but displayed
233 233 only if the --copied switch is set.
234 234 """
235 235 copies = args['revcache'].get('copies') or []
236 236 c = [{'name': x[0], 'source': x[1]} for x in copies]
237 237 return showlist('file_copy', c, plural='file_copies', **args)
238 238
239 239 def showfiledels(**args):
240 240 """:file_dels: List of strings. Files removed by this changeset."""
241 241 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
242 242 return showlist('file_del', getfiles(repo, ctx, revcache)[2], **args)
243 243
244 244 def showfilemods(**args):
245 245 """:file_mods: List of strings. Files modified by this changeset."""
246 246 repo, ctx, revcache = args['repo'], args['ctx'], args['revcache']
247 247 return showlist('file_mod', getfiles(repo, ctx, revcache)[0], **args)
248 248
249 249 def showfiles(**args):
250 250 """:files: List of strings. All files modified, added, or removed by this
251 251 changeset.
252 252 """
253 253 return showlist('file', args['ctx'].files(), **args)
254 254
255 255 def showlatesttag(repo, ctx, templ, cache, **args):
256 256 """:latesttag: String. Most recent global tag in the ancestors of this
257 257 changeset.
258 258 """
259 259 return getlatesttags(repo, ctx, cache)[2]
260 260
261 261 def showlatesttagdistance(repo, ctx, templ, cache, **args):
262 262 """:latesttagdistance: Integer. Longest path to the latest tag."""
263 263 return getlatesttags(repo, ctx, cache)[1]
264 264
265 265 def showmanifest(**args):
266 266 repo, ctx, templ = args['repo'], args['ctx'], args['templ']
267 267 args = args.copy()
268 268 args.update(dict(rev=repo.manifest.rev(ctx.changeset()[0]),
269 269 node=hex(ctx.changeset()[0])))
270 270 return templ('manifest', **args)
271 271
272 272 def shownode(repo, ctx, templ, **args):
273 273 """:node: String. The changeset identification hash, as a 40 hexadecimal
274 274 digit string.
275 275 """
276 276 return ctx.hex()
277 277
278 def showphase(repo, ctx, templ, **args):
279 """:rev: Integer. The changeset phase."""
280 return ctx.phase()
281
278 282 def showrev(repo, ctx, templ, **args):
279 283 """:rev: Integer. The repository-local changeset revision number."""
280 284 return ctx.rev()
281 285
282 286 def showtags(**args):
283 287 """:tags: List of strings. Any tags associated with the changeset."""
284 288 return showlist('tag', args['ctx'].tags(), **args)
285 289
286 290 # keywords are callables like:
287 291 # fn(repo, ctx, templ, cache, revcache, **args)
288 292 # with:
289 293 # repo - current repository instance
290 294 # ctx - the changectx being displayed
291 295 # templ - the templater instance
292 296 # cache - a cache dictionary for the whole templater run
293 297 # revcache - a cache dictionary for the current revision
294 298 keywords = {
295 299 'author': showauthor,
296 300 'bisect': showbisect,
297 301 'branch': showbranch,
298 302 'branches': showbranches,
299 303 'bookmarks': showbookmarks,
300 304 'children': showchildren,
301 305 'date': showdate,
302 306 'desc': showdescription,
303 307 'diffstat': showdiffstat,
304 308 'extras': showextras,
305 309 'file_adds': showfileadds,
306 310 'file_copies': showfilecopies,
307 311 'file_copies_switch': showfilecopiesswitch,
308 312 'file_dels': showfiledels,
309 313 'file_mods': showfilemods,
310 314 'files': showfiles,
311 315 'latesttag': showlatesttag,
312 316 'latesttagdistance': showlatesttagdistance,
313 317 'manifest': showmanifest,
314 318 'node': shownode,
319 'phase': showphase,
315 320 'rev': showrev,
316 321 'tags': showtags,
317 322 }
318 323
319 324 # tell hggettext to extract docstrings from these functions:
320 325 i18nfunctions = keywords.values()
General Comments 0
You need to be logged in to leave comments. Login now