mercurial/templater.py
changeset 3643 b4ad640a3bcf
parent 3642 b2c47652e8e3
child 3647 734e337cb816
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 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)