Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/cmdutil.py @ 3643:b4ad640a3bcf
templates: move changeset templating bits to cmdutils
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 13 Nov 2006 13:26:57 -0600 |
parents | 730ca93ed788 |
children | b984dcb1df71 |
comparison
equal
deleted
inserted
replaced
3642:b2c47652e8e3 | 3643:b4ad640a3bcf |
---|---|
6 # of the GNU General Public License, incorporated herein by reference. | 6 # of the GNU General Public License, incorporated herein by reference. |
7 | 7 |
8 from demandload import demandload | 8 from demandload import demandload |
9 from node import * | 9 from node import * |
10 from i18n import gettext as _ | 10 from i18n import gettext as _ |
11 demandload(globals(), 'mdiff util') | |
12 demandload(globals(), 'os sys') | 11 demandload(globals(), 'os sys') |
12 demandload(globals(), 'mdiff util templater cStringIO') | |
13 | 13 |
14 revrangesep = ':' | 14 revrangesep = ':' |
15 | 15 |
16 def revpair(ui, repo, revs): | 16 def revpair(ui, repo, revs): |
17 '''return pair of nodes, given list of revisions. second item can | 17 '''return pair of nodes, given list of revisions. second item can |
193 repo.ui.status(_('recording removal of %s as rename to %s ' | 193 repo.ui.status(_('recording removal of %s as rename to %s ' |
194 '(%d%% similar)\n') % | 194 '(%d%% similar)\n') % |
195 (oldrel, newrel, score * 100)) | 195 (oldrel, newrel, score * 100)) |
196 if not dry_run: | 196 if not dry_run: |
197 repo.copy(old, new, wlock=wlock) | 197 repo.copy(old, new, wlock=wlock) |
198 | |
199 class changeset_printer(object): | |
200 '''show changeset information when templating not requested.''' | |
201 | |
202 def __init__(self, ui, repo): | |
203 self.ui = ui | |
204 self.repo = repo | |
205 | |
206 def show(self, rev=0, changenode=None, brinfo=None, copies=None): | |
207 '''show a single changeset or file revision''' | |
208 log = self.repo.changelog | |
209 if changenode is None: | |
210 changenode = log.node(rev) | |
211 elif not rev: | |
212 rev = log.rev(changenode) | |
213 | |
214 if self.ui.quiet: | |
215 self.ui.write("%d:%s\n" % (rev, short(changenode))) | |
216 return | |
217 | |
218 changes = log.read(changenode) | |
219 date = util.datestr(changes[2]) | |
220 extra = changes[5] | |
221 branch = extra.get("branch") | |
222 | |
223 hexfunc = self.ui.debugflag and hex or short | |
224 | |
225 parents = log.parentrevs(rev) | |
226 if not self.ui.debugflag: | |
227 if parents[1] == nullrev: | |
228 if parents[0] >= rev - 1: | |
229 parents = [] | |
230 else: | |
231 parents = [parents[0]] | |
232 parents = [(p, hexfunc(log.node(p))) for p in parents] | |
233 | |
234 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode))) | |
235 | |
236 if branch: | |
237 self.ui.write(_("branch: %s\n") % branch) | |
238 for tag in self.repo.nodetags(changenode): | |
239 self.ui.write(_("tag: %s\n") % tag) | |
240 for parent in parents: | |
241 self.ui.write(_("parent: %d:%s\n") % parent) | |
242 | |
243 if brinfo and changenode in brinfo: | |
244 br = brinfo[changenode] | |
245 self.ui.write(_("branch: %s\n") % " ".join(br)) | |
246 | |
247 if self.ui.debugflag: | |
248 self.ui.write(_("manifest: %d:%s\n") % | |
249 (self.repo.manifest.rev(changes[0]), hex(changes[0]))) | |
250 self.ui.write(_("user: %s\n") % changes[1]) | |
251 self.ui.write(_("date: %s\n") % date) | |
252 | |
253 if self.ui.debugflag: | |
254 files = self.repo.status(log.parents(changenode)[0], changenode)[:3] | |
255 for key, value in zip([_("files:"), _("files+:"), _("files-:")], | |
256 files): | |
257 if value: | |
258 self.ui.write("%-12s %s\n" % (key, " ".join(value))) | |
259 elif changes[3] and self.ui.verbose: | |
260 self.ui.write(_("files: %s\n") % " ".join(changes[3])) | |
261 if copies and self.ui.verbose: | |
262 copies = ['%s (%s)' % c for c in copies] | |
263 self.ui.write(_("copies: %s\n") % ' '.join(copies)) | |
264 | |
265 if extra and self.ui.debugflag: | |
266 extraitems = extra.items() | |
267 extraitems.sort() | |
268 for key, value in extraitems: | |
269 self.ui.write(_("extra: %s=%s\n") | |
270 % (key, value.encode('string_escape'))) | |
271 | |
272 description = changes[4].strip() | |
273 if description: | |
274 if self.ui.verbose: | |
275 self.ui.write(_("description:\n")) | |
276 self.ui.write(description) | |
277 self.ui.write("\n\n") | |
278 else: | |
279 self.ui.write(_("summary: %s\n") % | |
280 description.splitlines()[0]) | |
281 self.ui.write("\n") | |
282 | |
283 class changeset_templater(object): | |
284 '''format changeset information.''' | |
285 | |
286 def __init__(self, ui, repo, mapfile, dest=None): | |
287 self.t = templater.templater(mapfile, templater.common_filters, | |
288 cache={'parent': '{rev}:{node|short} ', | |
289 'manifest': '{rev}:{node|short}', | |
290 'filecopy': '{name} ({source})'}) | |
291 self.ui = ui | |
292 self.dest = dest | |
293 self.repo = repo | |
294 | |
295 def use_template(self, t): | |
296 '''set template string to use''' | |
297 self.t.cache['changeset'] = t | |
298 | |
299 def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props): | |
300 '''show a single changeset or file revision''' | |
301 log = self.repo.changelog | |
302 if changenode is None: | |
303 changenode = log.node(rev) | |
304 elif not rev: | |
305 rev = log.rev(changenode) | |
306 | |
307 changes = log.read(changenode) | |
308 | |
309 def showlist(name, values, plural=None, **args): | |
310 '''expand set of values. | |
311 name is name of key in template map. | |
312 values is list of strings or dicts. | |
313 plural is plural of name, if not simply name + 's'. | |
314 | |
315 expansion works like this, given name 'foo'. | |
316 | |
317 if values is empty, expand 'no_foos'. | |
318 | |
319 if 'foo' not in template map, return values as a string, | |
320 joined by space. | |
321 | |
322 expand 'start_foos'. | |
323 | |
324 for each value, expand 'foo'. if 'last_foo' in template | |
325 map, expand it instead of 'foo' for last key. | |
326 | |
327 expand 'end_foos'. | |
328 ''' | |
329 if plural: names = plural | |
330 else: names = name + 's' | |
331 if not values: | |
332 noname = 'no_' + names | |
333 if noname in self.t: | |
334 yield self.t(noname, **args) | |
335 return | |
336 if name not in self.t: | |
337 if isinstance(values[0], str): | |
338 yield ' '.join(values) | |
339 else: | |
340 for v in values: | |
341 yield dict(v, **args) | |
342 return | |
343 startname = 'start_' + names | |
344 if startname in self.t: | |
345 yield self.t(startname, **args) | |
346 vargs = args.copy() | |
347 def one(v, tag=name): | |
348 try: | |
349 vargs.update(v) | |
350 except (AttributeError, ValueError): | |
351 try: | |
352 for a, b in v: | |
353 vargs[a] = b | |
354 except ValueError: | |
355 vargs[name] = v | |
356 return self.t(tag, **vargs) | |
357 lastname = 'last_' + name | |
358 if lastname in self.t: | |
359 last = values.pop() | |
360 else: | |
361 last = None | |
362 for v in values: | |
363 yield one(v) | |
364 if last is not None: | |
365 yield one(last, tag=lastname) | |
366 endname = 'end_' + names | |
367 if endname in self.t: | |
368 yield self.t(endname, **args) | |
369 | |
370 def showbranches(**args): | |
371 branch = changes[5].get("branch") | |
372 if branch: | |
373 yield showlist('branch', [branch], plural='branches', **args) | |
374 # add old style branches if requested | |
375 if brinfo and changenode in brinfo: | |
376 yield showlist('branch', brinfo[changenode], | |
377 plural='branches', **args) | |
378 | |
379 def showparents(**args): | |
380 parents = [[('rev', log.rev(p)), ('node', hex(p))] | |
381 for p in log.parents(changenode) | |
382 if self.ui.debugflag or p != nullid] | |
383 if (not self.ui.debugflag and len(parents) == 1 and | |
384 parents[0][0][1] == rev - 1): | |
385 return | |
386 return showlist('parent', parents, **args) | |
387 | |
388 def showtags(**args): | |
389 return showlist('tag', self.repo.nodetags(changenode), **args) | |
390 | |
391 def showextras(**args): | |
392 extras = changes[5].items() | |
393 extras.sort() | |
394 for key, value in extras: | |
395 args = args.copy() | |
396 args.update(dict(key=key, value=value)) | |
397 yield self.t('extra', **args) | |
398 | |
399 def showcopies(**args): | |
400 c = [{'name': x[0], 'source': x[1]} for x in copies] | |
401 return showlist('file_copy', c, plural='file_copies', **args) | |
402 | |
403 if self.ui.debugflag: | |
404 files = self.repo.status(log.parents(changenode)[0], changenode)[:3] | |
405 def showfiles(**args): | |
406 return showlist('file', files[0], **args) | |
407 def showadds(**args): | |
408 return showlist('file_add', files[1], **args) | |
409 def showdels(**args): | |
410 return showlist('file_del', files[2], **args) | |
411 def showmanifest(**args): | |
412 args = args.copy() | |
413 args.update(dict(rev=self.repo.manifest.rev(changes[0]), | |
414 node=hex(changes[0]))) | |
415 return self.t('manifest', **args) | |
416 else: | |
417 def showfiles(**args): | |
418 yield showlist('file', changes[3], **args) | |
419 showadds = '' | |
420 showdels = '' | |
421 showmanifest = '' | |
422 | |
423 defprops = { | |
424 'author': changes[1], | |
425 'branches': showbranches, | |
426 'date': changes[2], | |
427 'desc': changes[4], | |
428 'file_adds': showadds, | |
429 'file_dels': showdels, | |
430 'files': showfiles, | |
431 'file_copies': showcopies, | |
432 'manifest': showmanifest, | |
433 'node': hex(changenode), | |
434 'parents': showparents, | |
435 'rev': rev, | |
436 'tags': showtags, | |
437 'extras': showextras, | |
438 } | |
439 props = props.copy() | |
440 props.update(defprops) | |
441 | |
442 try: | |
443 dest = self.dest or self.ui | |
444 if self.ui.debugflag and 'header_debug' in self.t: | |
445 key = 'header_debug' | |
446 elif self.ui.quiet and 'header_quiet' in self.t: | |
447 key = 'header_quiet' | |
448 elif self.ui.verbose and 'header_verbose' in self.t: | |
449 key = 'header_verbose' | |
450 elif 'header' in self.t: | |
451 key = 'header' | |
452 else: | |
453 key = '' | |
454 if key: | |
455 dest.write_header(templater.stringify(self.t(key, **props))) | |
456 if self.ui.debugflag and 'changeset_debug' in self.t: | |
457 key = 'changeset_debug' | |
458 elif self.ui.quiet and 'changeset_quiet' in self.t: | |
459 key = 'changeset_quiet' | |
460 elif self.ui.verbose and 'changeset_verbose' in self.t: | |
461 key = 'changeset_verbose' | |
462 else: | |
463 key = 'changeset' | |
464 dest.write(templater.stringify(self.t(key, **props))) | |
465 except KeyError, inst: | |
466 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile, | |
467 inst.args[0])) | |
468 except SyntaxError, inst: | |
469 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0])) | |
470 | |
471 class stringio(object): | |
472 '''wrap cStringIO for use by changeset_templater.''' | |
473 def __init__(self): | |
474 self.fp = cStringIO.StringIO() | |
475 | |
476 def write(self, *args): | |
477 for a in args: | |
478 self.fp.write(a) | |
479 | |
480 write_header = write | |
481 | |
482 def __getattr__(self, key): | |
483 return getattr(self.fp, key) | |
484 | |
485 def show_changeset(ui, repo, opts): | |
486 """show one changeset using template or regular display. | |
487 | |
488 Display format will be the first non-empty hit of: | |
489 1. option 'template' | |
490 2. option 'style' | |
491 3. [ui] setting 'logtemplate' | |
492 4. [ui] setting 'style' | |
493 If all of these values are either the unset or the empty string, | |
494 regular display via changeset_printer() is done. | |
495 """ | |
496 # options | |
497 tmpl = opts.get('template') | |
498 mapfile = None | |
499 if tmpl: | |
500 tmpl = templater.parsestring(tmpl, quoted=False) | |
501 else: | |
502 mapfile = opts.get('style') | |
503 # ui settings | |
504 if not mapfile: | |
505 tmpl = ui.config('ui', 'logtemplate') | |
506 if tmpl: | |
507 tmpl = templater.parsestring(tmpl) | |
508 else: | |
509 mapfile = ui.config('ui', 'style') | |
510 | |
511 if tmpl or mapfile: | |
512 if mapfile: | |
513 if not os.path.split(mapfile)[0]: | |
514 mapname = (templater.templatepath('map-cmdline.' + mapfile) | |
515 or templater.templatepath(mapfile)) | |
516 if mapname: mapfile = mapname | |
517 try: | |
518 t = changeset_templater(ui, repo, mapfile) | |
519 except SyntaxError, inst: | |
520 raise util.Abort(inst.args[0]) | |
521 if tmpl: t.use_template(tmpl) | |
522 return t | |
523 return changeset_printer(ui, repo) | |
524 |