comparison mercurial/templater.py @ 3646:b4ad640a3bcf

templates: move changeset templating bits to cmdutils
author Matt Mackall <mpm@selenic.com>
date Mon, 13 Nov 2006 13:26:57 -0600
parents b2c47652e8e3
children 734e337cb816
comparison
equal deleted inserted replaced
3645:b2c47652e8e3 3646: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 i18n import gettext as _ 9 from i18n import gettext as _
10 from node import * 10 from node import *
11 demandload(globals(), "cStringIO cgi re sys os time urllib util textwrap") 11 demandload(globals(), "cgi re sys os time urllib util textwrap")
12 12
13 def parsestring(s, quoted=True): 13 def parsestring(s, quoted=True):
14 '''parse a string using simple c-like syntax. 14 '''parse a string using simple c-like syntax.
15 string must be in quotes if quoted is True.''' 15 string must be in quotes if quoted is True.'''
16 if quoted: 16 if quoted:
288 if name: fl.append(name) 288 if name: fl.append(name)
289 p = os.path.join(os.path.dirname(module), *fl) 289 p = os.path.join(os.path.dirname(module), *fl)
290 if (name and os.path.exists(p)) or os.path.isdir(p): 290 if (name and os.path.exists(p)) or os.path.isdir(p):
291 return os.path.normpath(p) 291 return os.path.normpath(p)
292 292
293 class changeset_templater(object):
294 '''format changeset information.'''
295
296 def __init__(self, ui, repo, mapfile, dest=None):
297 self.t = templater(mapfile, common_filters,
298 cache={'parent': '{rev}:{node|short} ',
299 'manifest': '{rev}:{node|short}',
300 'filecopy': '{name} ({source})'})
301 self.ui = ui
302 self.dest = dest
303 self.repo = repo
304
305 def use_template(self, t):
306 '''set template string to use'''
307 self.t.cache['changeset'] = t
308
309 def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props):
310 '''show a single changeset or file revision'''
311 log = self.repo.changelog
312 if changenode is None:
313 changenode = log.node(rev)
314 elif not rev:
315 rev = log.rev(changenode)
316
317 changes = log.read(changenode)
318
319 def showlist(name, values, plural=None, **args):
320 '''expand set of values.
321 name is name of key in template map.
322 values is list of strings or dicts.
323 plural is plural of name, if not simply name + 's'.
324
325 expansion works like this, given name 'foo'.
326
327 if values is empty, expand 'no_foos'.
328
329 if 'foo' not in template map, return values as a string,
330 joined by space.
331
332 expand 'start_foos'.
333
334 for each value, expand 'foo'. if 'last_foo' in template
335 map, expand it instead of 'foo' for last key.
336
337 expand 'end_foos'.
338 '''
339 if plural: names = plural
340 else: names = name + 's'
341 if not values:
342 noname = 'no_' + names
343 if noname in self.t:
344 yield self.t(noname, **args)
345 return
346 if name not in self.t:
347 if isinstance(values[0], str):
348 yield ' '.join(values)
349 else:
350 for v in values:
351 yield dict(v, **args)
352 return
353 startname = 'start_' + names
354 if startname in self.t:
355 yield self.t(startname, **args)
356 vargs = args.copy()
357 def one(v, tag=name):
358 try:
359 vargs.update(v)
360 except (AttributeError, ValueError):
361 try:
362 for a, b in v:
363 vargs[a] = b
364 except ValueError:
365 vargs[name] = v
366 return self.t(tag, **vargs)
367 lastname = 'last_' + name
368 if lastname in self.t:
369 last = values.pop()
370 else:
371 last = None
372 for v in values:
373 yield one(v)
374 if last is not None:
375 yield one(last, tag=lastname)
376 endname = 'end_' + names
377 if endname in self.t:
378 yield self.t(endname, **args)
379
380 def showbranches(**args):
381 branch = changes[5].get("branch")
382 if branch:
383 yield showlist('branch', [branch], plural='branches', **args)
384 # add old style branches if requested
385 if brinfo and changenode in brinfo:
386 yield showlist('branch', brinfo[changenode],
387 plural='branches', **args)
388
389 def showparents(**args):
390 parents = [[('rev', log.rev(p)), ('node', hex(p))]
391 for p in log.parents(changenode)
392 if self.ui.debugflag or p != nullid]
393 if (not self.ui.debugflag and len(parents) == 1 and
394 parents[0][0][1] == rev - 1):
395 return
396 return showlist('parent', parents, **args)
397
398 def showtags(**args):
399 return showlist('tag', self.repo.nodetags(changenode), **args)
400
401 def showextras(**args):
402 extras = changes[5].items()
403 extras.sort()
404 for key, value in extras:
405 args = args.copy()
406 args.update(dict(key=key, value=value))
407 yield self.t('extra', **args)
408
409 def showcopies(**args):
410 c = [{'name': x[0], 'source': x[1]} for x in copies]
411 return showlist('file_copy', c, plural='file_copies', **args)
412
413 if self.ui.debugflag:
414 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
415 def showfiles(**args):
416 return showlist('file', files[0], **args)
417 def showadds(**args):
418 return showlist('file_add', files[1], **args)
419 def showdels(**args):
420 return showlist('file_del', files[2], **args)
421 def showmanifest(**args):
422 args = args.copy()
423 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
424 node=hex(changes[0])))
425 return self.t('manifest', **args)
426 else:
427 def showfiles(**args):
428 yield showlist('file', changes[3], **args)
429 showadds = ''
430 showdels = ''
431 showmanifest = ''
432
433 defprops = {
434 'author': changes[1],
435 'branches': showbranches,
436 'date': changes[2],
437 'desc': changes[4],
438 'file_adds': showadds,
439 'file_dels': showdels,
440 'files': showfiles,
441 'file_copies': showcopies,
442 'manifest': showmanifest,
443 'node': hex(changenode),
444 'parents': showparents,
445 'rev': rev,
446 'tags': showtags,
447 'extras': showextras,
448 }
449 props = props.copy()
450 props.update(defprops)
451
452 try:
453 dest = self.dest or self.ui
454 if self.ui.debugflag and 'header_debug' in self.t:
455 key = 'header_debug'
456 elif self.ui.quiet and 'header_quiet' in self.t:
457 key = 'header_quiet'
458 elif self.ui.verbose and 'header_verbose' in self.t:
459 key = 'header_verbose'
460 elif 'header' in self.t:
461 key = 'header'
462 else:
463 key = ''
464 if key:
465 dest.write_header(stringify(self.t(key, **props)))
466 if self.ui.debugflag and 'changeset_debug' in self.t:
467 key = 'changeset_debug'
468 elif self.ui.quiet and 'changeset_quiet' in self.t:
469 key = 'changeset_quiet'
470 elif self.ui.verbose and 'changeset_verbose' in self.t:
471 key = 'changeset_verbose'
472 else:
473 key = 'changeset'
474 dest.write(stringify(self.t(key, **props)))
475 except KeyError, inst:
476 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
477 inst.args[0]))
478 except SyntaxError, inst:
479 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
480
481 class stringio(object):
482 '''wrap cStringIO for use by changeset_templater.'''
483 def __init__(self):
484 self.fp = cStringIO.StringIO()
485
486 def write(self, *args):
487 for a in args:
488 self.fp.write(a)
489
490 write_header = write
491
492 def __getattr__(self, key):
493 return getattr(self.fp, key)