# # # patch "README" # from [9312cb3a38deda8784451bcbd150506ab0f919dd] # to [2a60dbf0c1d701c151d177271218d987167c1357] # # patch "tracvc/mtn/backend.py" # from [8c103ca63cb2b42798d7f1609b3fc25aac72451b] # to [fd2148b0ed4e2869570935eb966e9d47369a41c5] # ============================================================ --- README 9312cb3a38deda8784451bcbd150506ab0f919dd +++ README 2a60dbf0c1d701c151d177271218d987167c1357 @@ -67,7 +67,33 @@ trac. The 'prefix' is the common part of all cache files in this directory and can be chosen freely. + * The 'xtracerts' option can be used to specify a (coma-separated) + list of user-defined certs to be displayed as changeset + properties. To control their appearance, an additional section + [mtn-cert-] can be put in the .ini file. There are four + options: + - name: Property name, defaults to the cert's name. + - text: Format string for the property, must contain %s as + placeholder for the cert's value, defaults to "%s". + - wikiflag: Whether the text should be interpreted as wiki text + (True) or not (False), defaults to True. + - htmlclass: Enables to attach special formatting to the displayed + property, e.g. 'author', 'time', 'message' or 'changeset', has + no default. + Example: If you have certs named 'x-bug' that contain the number + of a ticket a revision is related to, you could put this in + your.ini file: + + [mtn] + xtracerts=x-bug + + [mtn-cert-x-bug] + name = X-Bug + text = related to [ticket:%s] + wikiflag = True + + Selecting the Caching Method For better performance you should use a disk-based caching ============================================================ --- tracvc/mtn/backend.py 8c103ca63cb2b42798d7f1609b3fc25aac72451b +++ tracvc/mtn/backend.py fd2148b0ed4e2869570935eb966e9d47369a41c5 @@ -30,7 +30,7 @@ from trac.core import * from trac.wiki import IWikiSyntaxProvider from trac.util import shorten_line, escape from trac.core import * -from trac.config import Option +from trac.config import Option, ListOption from trac import __version__ as trac_version from pkg_resources import parse_version from time import strptime @@ -43,12 +43,15 @@ class MonotoneConnector(Component): implements(IRepositoryConnector, IWikiSyntaxProvider) # Configuration options - mtn_binary = Option('mtn', 'mtn_binary', '/usr/bin/mtn', - '''Full path to the monotone binary.''') + mtn_binary = Option('mtn', 'mtn_binary', default='/usr/bin/mtn', + doc='''Full path to the monotone binary.''') - cachespec = Option('mtn', 'cachespec', 'localmem', - '''Select a caching mechanism.''') + cachespec = Option('mtn', 'cachespec', default='localmem', + doc='''Select a caching mechanism.''') + xtracerts = ListOption('mtn', 'xtracerts', + doc='''List of user certs to be displayed.''') + # IRepositoryConnector methods def __init__(self): self.repos = {} @@ -64,6 +67,19 @@ class MonotoneConnector(Component): """ yield ("mtn", 0) + def get_revprops(self): + revprops = {} + for cert in self.xtracerts: + section = 'mtn-cert-%s' % cert + revprops[cert] = [ + self.config.get(section, 'name', cert), + self.config.get(section, 'text', '%s'), + self.config.getbool(section, 'wikiflag', True), + self.config.get(section, 'htmlclass', None) or None + # Config bug? Returns '' if unset instead of None. + ] + return revprops + def get_repository(self, type, path, authname): """Return a Repository instance for the given repository type and dir. """ @@ -71,7 +87,7 @@ class MonotoneConnector(Component): # return the same Repository object for the same database path if not path in self.repos: self.repos[path] = MonotoneRepository(path, self.log, - self.mtn_binary, self.cachespec) + self.mtn_binary, self.cachespec, self.get_revprops()) return self.repos[path] # IWikiSyntaxProvider methods @@ -145,9 +161,10 @@ class MonotoneRepository(Repository): class MonotoneRepository(Repository): - def __init__(self, path, log, binary, cachespec): + def __init__(self, path, log, binary, cachespec, revpropspec = None): self.mtn = MTN(path, log, binary, cachespec) Repository.__init__(self, 'mtn:%s' % path, None, log) + self.revpropspec = revpropspec or {} def get_changeset(self, rev): """ @@ -155,7 +172,7 @@ class MonotoneRepository(Repository): revision 'rev'. """ rev = self.normalize_rev(rev) - return MonotoneChangeset(self.mtn, rev) + return MonotoneChangeset(self.mtn, rev, self.revpropspec) def get_changesets(self, start, stop): """ @@ -169,7 +186,7 @@ class MonotoneRepository(Repository): if time < start: continue # assume none of the parents is younger elif time < stop: - yield MonotoneChangeset(self.mtn, current) # or self.get_changeset(current) + yield self.get_changeset(current) for parent in self.mtn.parents(current): if parent not in seen: seen.add(parent) @@ -409,7 +426,7 @@ class MonotoneChangeset(Changeset): class MonotoneChangeset(Changeset): - def __init__(self, mtn, rev): + def __init__(self, mtn, rev, revpropspec = None): self.certs = mtn.certs(rev) self.messages = self.certs.get('changelog', ['-']) @@ -425,6 +442,7 @@ class MonotoneChangeset(Changeset): Changeset.__init__(self, rev, message, author, date) self.mtn = mtn + self.revpropspec = revpropspec or {} def get_changes(self): """ @@ -433,7 +451,6 @@ class MonotoneChangeset(Changeset): Changeset.ADD, Changeset.COPY, Changeset.DELETE, Changeset.EDIT or Changeset.MOVE, and kind is one of Node.FILE or Node.DIRECTORY. """ - for cs in self.mtn.changesets(self.rev): oldrev = cs.oldrev @@ -479,3 +496,8 @@ class MonotoneChangeset(Changeset): yield('Tag', '[revtag:%s]' % tag, True, 'changeset') for message in self.messages[1:]: yield('+Message', message, True, 'message') + + # user-defined revision properties to be displayed + for cert, spec in self.revpropspec.iteritems(): + for certvalue in self.certs.get(cert, []): + yield(spec[0], spec[1] % certvalue, spec[2], spec[3])