Changeset 4024

Show
Ignore:
Timestamp:
07/16/08 18:45:50 (4 months ago)
Author:
eblot
Message:

Refs #1405. Introduce tag support in RevtreePlugin

Bumping version to v0.6.0: API for enhancers have been reworked and are no
longer compatible with previous releases of the plugin.

Please note that this version is in early development stage.

It is therefore recommended to stick with the previous series for the plugin (0.5.x)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • revtreeplugin/0.11/enhancers/logenhancer/logenhancer/enhancer.py

    r3578 r4024  
    11# -*- coding: utf-8 -*- 
    22# 
    3 # Copyright (C) 2006-2007 Emmanuel Blot <emmanuel.blot@free.fr> 
     3# Copyright (C) 2006-2008 Emmanuel Blot <emmanuel.blot@free.fr> 
    44# All rights reserved. 
    55# 
     
    1313# 
    1414 
    15 from revtree import IRevtreeEnhancer 
     15from revtree import IRevtreeEnhancer, RevtreeEnhancer 
    1616from revtree.svgview import SvgOperation, SvgGroup 
    1717from trac.core import * 
    1818 
    19 __all__ = ['LogEnhancer'] 
    20  
    21 class SimpleContainer(object): 
    22     """Simple container for enhancer parameters""" 
    23      
    24     def __init__(self): 
    25         pass 
     19__all__ = ['LogEnhancerModule'] 
    2620 
    2721 
    28 class LogEnhancer(Component): 
     22class LogEnhancer(RevtreeEnhancer): 
    2923    """Revtree enhancer based on specific log messages and custom properties 
    3024    This class is provided as-is, as an example 
     
    3428    """ 
    3529     
    36     implements(IRevtreeEnhancer)     
    37      
    38     def create(self, env, req, repos, svgrevtree): 
     30    def __init__(self, env, req, repos, svgrevtree): 
    3931        """Creates the internal data from the repository""" 
    40         enhancer = SimpleContainer() 
    41         enhancer._repos = repos 
    42         enhancer._creations = [] 
    43         enhancer._deliveries = [] 
    44         enhancer._brings = [] 
    45         enhancer._groups = [] 
    46         enhancer._svgrevtree = svgrevtree 
    47         # z-depth indexed widgets: back=1, fore=2 
    48         enhancer._widgets = ([], [], []) 
    49         for branch in enhancer._repos.branches().values(): 
    50             svgbranch = enhancer._svgrevtree.svgbranch(branch=branch) 
     32        self.env = env 
     33        self._repos = repos 
     34        self._creations = [] 
     35        self._deliveries = [] 
     36        self._brings = [] 
     37        self._groups = [] 
     38        self._svgrevtree = svgrevtree 
     39        # z-depth indexed widgets 
     40        self._widgets = [[] for l in IRevtreeEnhancer.ZLEVELS] 
     41        for branch in self._repos.branches().values(): 
     42            svgbranch = self._svgrevtree.svgbranch(branch=branch) 
    5143            if not svgbranch: 
    5244                continue 
     
    5850                    if branch.source(): 
    5951                        (rev, path) = branch.source() 
    60                         srcchg = enhancer._repos.changeset(rev) 
     52                        srcchg = self._repos.changeset(rev) 
    6153                        if srcchg is None: 
    6254                            continue 
    63                         enhancer._creations.append((srcchg, firstchgset)) 
     55                        self._creations.append((srcchg, firstchgset)) 
    6456            lastchgset = branch.youngest() 
    6557            if lastchgset: 
     
    6860                    svgbranch.svgchangeset(lastchgset).mark_last() 
    6961         
    70         for branch in enhancer._repos.branches().values(): 
    71             svgbranch = enhancer._svgrevtree.svgbranch(branch=branch) 
     62        for branch in self._repos.branches().values(): 
     63            svgbranch = self._svgrevtree.svgbranch(branch=branch) 
    7264            if not svgbranch: 
    7365                continue 
     
    8476                        revisions = [int(c) for c in deliver.split(',')] 
    8577                        revisions.sort() 
    86                         ychg = enhancer._repos.changeset(revisions[-1]) 
     78                        ychg = self._repos.changeset(revisions[-1]) 
    8779                        if not ychg: 
    8880                            continue 
    8981                        brname = ychg.branchname 
    90                         srcbranch = enhancer._repos.branch(brname) 
     82                        srcbranch = self._repos.branch(brname) 
    9183                        if not srcbranch: 
    9284                            continue 
    9385                        brrevs = [c.rev for c in srcbranch.changesets()] 
    9486                        valrevs = [r for r in revisions if r in brrevs] 
    95                         fchg = enhancer._repos.changeset(valrevs[0]) 
    96                         lchg = enhancer._repos.changeset(valrevs[-1]) 
    97                         enhancer._groups.append((fchg,lchg)) 
    98                         enhancer._deliveries.append((lchg,chgset)) 
     87                        fchg = self._repos.changeset(valrevs[0]) 
     88                        lchg = self._repos.changeset(valrevs[-1]) 
     89                        self._groups.append((fchg,lchg)) 
     90                        self._deliveries.append((lchg,chgset)) 
    9991                    except ValueError: 
    10092                        pass 
     
    111103                        revisions = [int(c) for c in bring.split(',')] 
    112104                        revisions.sort() 
    113                         ychg = enhancer._repos.changeset(revisions[-1]) 
     105                        ychg = self._repos.changeset(revisions[-1]) 
    114106                        if not ychg: 
    115107                            continue 
    116108                        brname = ychg.branchname 
    117                         srcbranch = enhancer._repos.branch(brname) 
     109                        srcbranch = self._repos.branch(brname) 
    118110                        if not srcbranch: 
    119111                            continue 
    120112                        brrevs = [c.rev for c in srcbranch.changesets()] 
    121113                        valrevs = [r for r in revisions if r in brrevs] 
    122                         fchg = enhancer._repos.changeset(valrevs[0]) 
    123                         lchg = enhancer._repos.changeset(valrevs[-1]) 
    124                         enhancer._groups.append((fchg,lchg)) 
    125                         enhancer._brings.append((lchg,chgset)) 
     114                        fchg = self._repos.changeset(valrevs[0]) 
     115                        lchg = self._repos.changeset(valrevs[-1]) 
     116                        self._groups.append((fchg,lchg)) 
     117                        self._brings.append((lchg,chgset)) 
    126118                    except ValueError: 
    127119                        pass 
    128120                    except IndexError: 
    129121                        pass 
    130  
    131         return enhancer 
    132                  
    133     def build(self, enhancer): 
     122         
     123    def build(self): 
    134124        """Build the enhanced widgets""" 
    135         for (srcchg, dstchg) in enhancer._creations: 
     125        for (srcchg, dstchg) in self._creations: 
    136126            svgsrcbr = \ 
    137                 enhancer._svgrevtree.svgbranch(branchname=srcchg.branchname) 
     127                self._svgrevtree.svgbranch(branchname=srcchg.branchname) 
    138128            svgdstbr = \ 
    139                 enhancer._svgrevtree.svgbranch(branchname=dstchg.branchname) 
     129                self._svgrevtree.svgbranch(branchname=dstchg.branchname) 
    140130            if not svgsrcbr or not svgdstbr: 
    141131                continue 
    142132            svgsrcchg = svgsrcbr.svgchangeset(srcchg) 
    143133            svgdstchg = svgdstbr.svgchangeset(dstchg) 
    144             op = SvgOperation(enhancer._svgrevtree, svgsrcchg, svgdstchg,  
     134            op = SvgOperation(self._svgrevtree, svgsrcchg, svgdstchg,  
    145135                              '#5faf5f') 
    146             enhancer._widgets[2].append(op) 
     136            self._widgets[IRevtreeEnhancer.ZMID].append(op) 
    147137         
    148         for (first, last) in enhancer._groups: 
     138        for (first, last) in self._groups: 
    149139            svgbranch = \ 
    150                 enhancer._svgrevtree.svgbranch(branchname=first.branchname) 
     140                self._svgrevtree.svgbranch(branchname=first.branchname) 
    151141            if not svgbranch: 
    152142                continue 
    153143            fsvg = svgbranch.svgchangeset(first) 
    154144            lsvg = svgbranch.svgchangeset(last) 
    155             group = SvgGroup(enhancer._svgrevtree, fsvg, lsvg) 
    156             enhancer._widgets[1].append(group) 
     145            group = SvgGroup(self._svgrevtree, fsvg, lsvg) 
     146            self._widgets[IRevtreeEnhancer.ZBACK].append(group) 
    157147         
    158         for (srcchg, dstchg) in enhancer._deliveries: 
     148        for (srcchg, dstchg) in self._deliveries: 
    159149            svgsrcbr = \ 
    160                 enhancer._svgrevtree.svgbranch(branchname=srcchg.branchname) 
     150                self._svgrevtree.svgbranch(branchname=srcchg.branchname) 
    161151            svgdstbr = \ 
    162                 enhancer._svgrevtree.svgbranch(branchname=dstchg.branchname) 
     152                self._svgrevtree.svgbranch(branchname=dstchg.branchname) 
    163153            if not svgsrcbr or not svgdstbr: 
    164154                continue 
    165155            svgsrcchg = svgsrcbr.svgchangeset(srcchg) 
    166156            svgdstchg = svgdstbr.svgchangeset(dstchg) 
    167             op = SvgOperation(enhancer._svgrevtree, svgsrcchg, svgdstchg,  
     157            op = SvgOperation(self._svgrevtree, svgsrcchg, svgdstchg,  
    168158                              'blue') 
    169             enhancer._widgets[2].append(op) 
     159            self._widgets[IRevtreeEnhancer.ZMID].append(op) 
    170160 
    171         for (srcchg, dstchg) in enhancer._brings: 
     161        for (srcchg, dstchg) in self._brings: 
    172162            svgsrcbr = \ 
    173                 enhancer._svgrevtree.svgbranch(branchname=srcchg.branchname) 
     163                self._svgrevtree.svgbranch(branchname=srcchg.branchname) 
    174164            svgdstbr = \ 
    175                 enhancer._svgrevtree.svgbranch(branchname=dstchg.branchname) 
     165                self._svgrevtree.svgbranch(branchname=dstchg.branchname) 
    176166            if not svgsrcbr or not svgdstbr: 
    177167                continue 
    178168            svgsrcchg = svgsrcbr.svgchangeset(srcchg) 
    179169            svgdstchg = svgdstbr.svgchangeset(dstchg) 
    180             op = SvgOperation(enhancer._svgrevtree, svgsrcchg, svgdstchg, 
    181                               'orange') 
    182             enhancer._widgets[2].append(op) 
     170            op = SvgOperation(self._svgrevtree, svgsrcchg, svgdstchg, 'orange') 
     171            self._widgets[IRevtreeEnhancer.ZMID].append(op) 
    183172             
    184         for wl in enhancer._widgets: 
     173        for wl in self._widgets: 
    185174            map(lambda w: w.build(), wl) 
    186175         
    187     def render(self, enhancer, level): 
     176    def render(self, level): 
    188177        """Renders the widgets, from background plane to foreground plane""" 
    189         if level < len(enhancer._widgets): 
    190             map(lambda w: w.render(), enhancer._widgets[level]) 
     178        if level < len(IRevtreeEnhancer.ZLEVELS): 
     179            map(lambda w: w.render(), self._widgets[level]) 
     180 
     181 
     182class LogEnhancerModule(Component): 
     183    """Revtree enhancer based on specific log messages and custom properties 
     184    """ 
     185     
     186    implements(IRevtreeEnhancer)     
     187     
     188    def create(self, env, req, repos, svgrevtree): 
     189        return LogEnhancer(env, req, repos, svgrevtree) 
     190 
  • revtreeplugin/0.11/enhancers/logenhancer/setup.py

    r3578 r4024  
    1616 
    1717PACKAGE = 'TracRevtreeLogEnhancer' 
    18 VERSION = '0.1.4
     18VERSION = '0.2.0
    1919 
    2020setup ( 
     
    2727    url='http://trac-hacks.org/wiki/RevtreePlugin/LogEnhancer', 
    2828    keywords = "trac revision svg graphical tree browser log", 
    29     install_requires = [ 'TracRevtreePlugin >= 0.5dev',  
    30                          'TracRevtreePlugin < 0.6 '], 
     29    install_requires = [ 'TracRevtreePlugin >= 0.6dev',  
     30                         'TracRevtreePlugin < 0.7 '], 
    3131    packages = find_packages(exclude=['ez_setup', '*.tests*']), 
    3232    entry_points = { 
  • revtreeplugin/0.11/enhancers/mergeenhancer/mergeenhancer/enhancer.py

    r3578 r4024  
    120120            color = svgdstbr.fillcolor().lighten() 
    121121            group = SvgGroup(svgrt, fsvg, lsvg, color, 40) 
    122             enhancer._widgets[1].append(group) 
     122            enhancer._widgets[IRevtreeEnhancer.ZBACK].append(group) 
    123123 
    124124        # create inter-branch operations 
     
    132132            op = SvgOperation(svgrt, svgsrcchg, svgdstchg,  
    133133                              svgdstbr.strokecolor()) 
    134             enhancer._widgets[2].append(op) 
     134            enhancer._widgets[IRevtreeEnhancer.ZMID].append(op) 
    135135 
    136136        # build widgets 
  • revtreeplugin/0.11/enhancers/mergeenhancer/setup.py

    r3578 r4024  
    1616 
    1717PACKAGE = 'TracRevtreeMergeEnhancer' 
    18 VERSION = '0.1.1
     18VERSION = '0.2.0
    1919 
    2020setup ( 
     
    2727    url='http://trac-hacks.org/wiki/RevtreePlugin/MergeEnhancer', 
    2828    keywords = "trac revision svg graphical tree browser log", 
    29     install_requires = [ 'TracRevtreePlugin >= 0.5.7',  
    30                          'TracRevtreePlugin < 0.6 '], 
     29    install_requires = [ 'TracRevtreePlugin >= 0.6dev',  
     30                         'TracRevtreePlugin < 0.7 '], 
    3131    packages = find_packages(exclude=['ez_setup', '*.tests*']), 
    3232    entry_points = { 
  • revtreeplugin/0.11/enhancers/mergeinfoenhancer/mergeinfoenhancer/enhancer.py

    r3579 r4024  
    1313# 
    1414 
    15 from revtree import IRevtreeEnhancer 
     15from revtree import IRevtreeEnhancer, RevtreeEnhancer 
    1616from revtree.svgview import SvgOperation, SvgGroup 
    1717from trac.core import * 
    1818from trac.util.text import to_unicode 
    1919 
    20 # debug 
    21 import sys 
    22  
    23 __all__ = ['MergeInfoEnhancer'] 
    24  
    25 class SimpleContainer(object): 
    26     """Simple container for enhancer parameters""" 
    27      
    28     def __init__(self): 
    29         pass 
     20__all__ = ['MergeInfoEnhancerModule'] 
    3021 
    3122 
     
    3728 
    3829 
    39 class MergeInfoEnhancer(Component): 
     30class MergeInfoEnhancer(RevtreeEnhancer): 
    4031    """Enhancer to show merge operation, based on svn:mergeinfo properties. 
    41      
    42        This enhancer requires a SVN >= 1.5 repository. Previous releases of 
    43        SVN do not manage the required information. This enhancer cannnot be 
    44        used with repositories managed with the svnmerge.py tool  
    4532    """ 
    4633 
    47     implements(IRevtreeEnhancer) 
    48  
    49     def create(self, env, req, repos, svgrevtree): 
     34    def __init__(self, env, req, repos, svgrevtree): 
    5035        """Creates the internal data from the repository""" 
    5136        enhancer = SimpleContainer() 
    52         enhancer._repos = repos 
    53         enhancer._svgrevtree = svgrevtree 
    54         enhancer._widgets = ([], [], []) 
    55         enhancer._merges = [] 
    56         enhancer._groups = [] 
     37        self._repos = repos 
     38        self._svgrevtree = svgrevtree 
     39        self._widgets = [[] for l in IRevtreeEnhancer.ZLEVELS] 
     40        self._merges = [] 
     41        self._groups = [] 
    5742         
    5843        for branch in repos.branches().values(): 
     
    11398                            lchg = repos.changeset(srcrevs[-1]) 
    11499                            cchg = repos.changeset(rev) 
    115                             enhancer._groups.append((branch, fchg, lchg)) 
    116                             enhancer._merges.append((lchg, cchg)) 
     100                            self._groups.append((branch, fchg, lchg)) 
     101                            self._merges.append((lchg, cchg)) 
    117102                         
    118103                            # update the list of non-merged source changesets 
     
    123108        return enhancer 
    124109                 
    125     def build(self, enhancer): 
     110    def build(self): 
    126111        """Build the enhanced widgets""" 
    127         svgrt = enhancer._svgrevtree 
     112        svgrt = self._svgrevtree 
    128113        # create groups of changesets 
    129         for (dstbranch, first, last) in enhancer._groups: 
     114        for (dstbranch, first, last) in self._groups: 
    130115            svgsrcbr = svgrt.svgbranch(branchname=first.branchname) 
    131116            svgdstbr = svgrt.svgbranch(branch=dstbranch) 
     
    136121            color = svgdstbr.fillcolor().lighten() 
    137122            group = SvgGroup(svgrt, fsvg, lsvg, color, 40) 
    138             enhancer._widgets[1].append(group) 
     123            self._widgets[IRevtreeEnhancer.ZBACK].append(group) 
    139124 
    140125        # create inter-branch operations 
    141         for (srcchg, dstchg) in enhancer._merges: 
     126        for (srcchg, dstchg) in self._merges: 
    142127            svgsrcbr = svgrt.svgbranch(branchname=srcchg.branchname) 
    143128            svgdstbr = svgrt.svgbranch(branchname=dstchg.branchname) 
     
    148133            op = SvgOperation(svgrt, svgsrcchg, svgdstchg,  
    149134                              svgdstbr.strokecolor()) 
    150             enhancer._widgets[2].append(op) 
     135            self._widgets[IRevtreeEnhancer.ZMID].append(op) 
    151136 
    152137        # build widgets 
    153         for wl in enhancer._widgets: 
     138        for wl in self._widgets: 
    154139            map(lambda w: w.build(), wl) 
    155140 
    156     def render(self, enhancer, level): 
     141    def render(self, level): 
    157142        """Renders the widgets, from background plane to foreground plane""" 
    158         if level < len(enhancer._widgets): 
    159             map(lambda w: w.render(), enhancer._widgets[level]) 
     143        if level < len(IRevtreeEnhancer.ZLEVELS): 
     144            map(lambda w: w.render(), self._widgets[level]) 
     145 
     146 
     147class MergeInfoEnhancerModule(Component): 
     148    """Enhancer to show merge operation, based on svn:mergeinfo properties. 
     149     
     150       This enhancer requires a SVN >= 1.5 repository. Previous releases of 
     151       SVN do not manage the required information. This enhancer cannnot be 
     152       used with repositories managed with the svnmerge.py tool  
     153    """ 
     154 
     155    implements(IRevtreeEnhancer) 
     156 
     157    def create(self, env, req, repos, svgrevtree): 
     158        return MergeInfoEnhancer(env, req, repos, svgrevtree) 
  • revtreeplugin/0.11/enhancers/mergeinfoenhancer/setup.py

    r3579 r4024  
    1616 
    1717PACKAGE = 'TracRevtreeMergeInfoEnhancer' 
    18 VERSION = '0.1.0' 
     18VERSION = '0.2.0' 
    1919 
    2020setup ( 
     
    2727    url='http://trac-hacks.org/wiki/RevtreePlugin/MergeInfoEnhancer', 
    2828    keywords = "trac revision svg graphical tree browser log", 
    29     install_requires = [ 'TracRevtreePlugin >= 0.5.7',  
    30                          'TracRevtreePlugin < 0.6 '], 
     29    install_requires = [ 'TracRevtreePlugin >= 0.6dev',  
     30                         'TracRevtreePlugin < 0.7 '], 
    3131    packages = find_packages(exclude=['ez_setup', '*.tests*']), 
    3232    entry_points = { 
  • revtreeplugin/0.11/hooks/trac-commit-hook

    r3581 r4024  
    237237         
    238238        @param revisions a list of revisions 
    239         @return a dictionnary of tickets: the key is the ticket number, the value is 
     239        @return a dictionary of tickets: the key is the ticket number, the value is 
    240240                the list of revisions related to this ticket. Each revision is 
    241241                itself a list [author, log] 
  • revtreeplugin/0.11/revtree/api.py

    r2841 r4024  
    1616from trac.core import * 
    1717 
    18 __all__ = ['IRevtreeEnhancer', 'IRevtreeOptimizer',  
     18__all__ = ['IRevtreeEnhancer', 'IRevtreeOptimizer', 'RevtreeEnhancer', 
    1919           'EmptyRangeError', 'BranchPathError', 'RevtreeSystem'] 
     20 
     21 
     22class RevtreeEnhancer(object): 
     23    """Enhancer interface""" 
     24     
     25    def build(self): 
     26        """Build the widgets""" 
     27        raise NotImplementedError 
     28     
     29    def render(self, level): 
     30        """Render the widgets""" 
     31        raise NotImplementedError 
    2032 
    2133 
    2234class IRevtreeEnhancer(Interface): 
    2335    """Provide graphical enhancements to a revision tree""" 
     36     
     37    # Rendering Z levels 
     38    (ZBACK, ZMID, ZFORE) = ZLEVELS = range(3) 
    2439 
    2540    def create(env, req, repos, svgrevtree): 
    26         """Create the internal data from the repository""" 
    27          
    28     def build(enhancer): 
    29         """Build the widgets""" 
    30  
    31     def render(enhancer, level): 
    32         """Render the widgets""" 
     41        """Create the internal data from the repository 
     42           Return a RevtreeEnhancer instance 
     43        """ 
    3344 
    3445 
  • revtreeplugin/0.11/revtree/enhancer.py

    r3580 r4024  
    11# -*- coding: utf-8 -*- 
    22# 
    3 # Copyright (C) 2006-2007 Emmanuel Blot <emmanuel.blot@free.fr> 
     3# Copyright (C) 2006-2008 Emmanuel Blot <emmanuel.blot@free.fr> 
    44# All rights reserved. 
    55# 
     
    1313# 
    1414 
    15 from revtree.api import IRevtreeEnhancer 
     15from revtree.api import IRevtreeEnhancer, RevtreeEnhancer 
    1616from revtree.svgview import SvgOperation, SvgGroup 
    1717from trac.core import * 
    1818 
    19 __all__ = ['SimpleEnhancer'] 
     19__all__ = ['SimpleEnhancerModule'] 
    2020 
    21 class SimpleContainer(object): 
    22     """Simple container for enhancer parameters""" 
    23      
    24     def __init__(self): 
    25         pass 
     21 
     22class SimpleEnhancer(RevtreeEnhancer): 
     23    """This class is a very basic skeleton that needs to customized, to  
     24       provide SvgOperation, SvgGroup and other widgets in the RevTree graphic 
     25    """ 
    2626         
    27  
    28 class SimpleEnhancer(Component): 
    29     """Enhance the appearance of the RevTree with site-specific properties. 
    30      
    31     Create branch clone operation (on branch/tag operations) 
    32      
    33     This class is a very basic skeleton that needs to customized, to provide 
    34     SvgOperation, SvgGroup and other widgets in the RevTree graphic 
    35     """ 
    36      
    37     implements(IRevtreeEnhancer)     
    38      
    39     def create(self, env, req, repos, svgrevtree): 
     27    def __init__(self, env, req, repos, svgrevtree): 
    4028        """Creates the internal data from the repository""" 
    41         enhancer = SimpleContainer() 
    42         enhancer.repos = repos 
    43         enhancer.creations = [] 
    44         enhancer.svgrevtree = svgrevtree 
    45         # z-depth indexed widgets: back=1, fore=2 
    46         enhancer.widgets = ([], [], []) 
     29        self.repos = repos 
     30        self.creations = [] 
     31        self.svgrevtree = svgrevtree 
     32        # z-depth indexed widgets 
     33        self._widgets = [[] for l in IRevtreeEnhancer.ZLEVELS] 
    4734         
    48         for branch in enhancer.repos.branches().values(): 
    49             svgbranch = enhancer.svgrevtree.svgbranch(branch=branch) 
     35        for branch in self.repos.branches().values(): 
     36            svgbranch = self.svgrevtree.svgbranch(branch=branch) 
    5037            if not svgbranch: 
    5138                # branch has probably been filtered out 
     
    5845                svgbranch.svgchangeset(firstchgset).mark_first() 
    5946                (rev, path) = branch.source() 
    60                 srcchg = enhancer.repos.changeset(rev) 
     47                srcchg = self.repos.changeset(rev) 
    6148                if srcchg is None: 
    6249                    continue 
    6350                # .. and create an operation between both changesets 
    64                 enhancer.creations.append((srcchg, firstchgset)) 
     51                self.creations.append((srcchg, firstchgset)) 
    6552            lastchgset = branch.youngest() 
    6653            if lastchgset: 
     
    7158        return enhancer 
    7259 
    73     def build(self, enhancer): 
     60    def build(self): 
    7461        """Build the enhanced widgets""" 
    75         for (srcchg, dstchg) in enhancer.creations: 
    76             svgsrcbr = enhancer.svgrevtree.svgbranch(branchname=srcchg.branchname) 
     62        for (srcchg, dstchg) in self.creations: 
     63            svgsrcbr = self.svgrevtree.svgbranch(branchname=srcchg.branchname) 
    7764            if svgsrcbr is None: 
    7865                continue 
    7966            svgsrcchg = svgsrcbr.svgchangeset(srcchg) 
    80             svgdstbr = enhancer.svgrevtree.svgbranch(branchname=dstchg.branchname) 
     67            svgdstbr = self.svgrevtree.svgbranch(branchname=dstchg.branchname) 
    8168            if svgdstbr is None: 
    8269                continue 
    8370            svgdstchg = svgdstbr.svgchangeset(dstchg) 
    84             op = SvgOperation(enhancer.svgrevtree, svgsrcchg, svgdstchg, \ 
    85                               '#3f3f3f') 
    86             enhancer.widgets[2].append(op) 
     71            op = SvgOperation(self.svgrevtree, svgsrcchg, svgdstchg, '#3f3f3f') 
     72            self.widgets[IRevtreeEnhancer.ZFORE].append(op) 
    8773                     
    88         for wl in enhancer.widgets: 
     74        for wl in self.widgets: 
    8975            map(lambda w: w.build(), wl) 
    9076         
    91     def render(self, enhancer, level): 
     77    def render(self, level): 
    9278        """Renders the widgets, from background plane to foreground plane""" 
    93         if level < len(enhancer.widgets): 
    94             map(lambda w: w.render(), enhancer.widgets[level]) 
    95              
     79        if level < len(IRevtreeEnhancer.ZLEVELS): 
     80            map(lambda w: w.render(), self._widgets[level]) 
    9681 
    9782 
    98          
     83class SimpleEnhancerModule(Component): 
     84    """Enhance the appearance of the RevTree with site-specific properties. 
     85     
     86    Create branch clone operation (on branch/tag operations) 
     87     
     88    This class is a very basic skeleton that needs to customized, to provide 
     89    SvgOperation, SvgGroup and other widgets in the RevTree graphic 
     90    """ 
     91     
     92    implements(IRevtreeEnhancer)     
     93 
     94    def create(self, env, req, repos, svgrevtree): 
     95        return SimpleEnhancer(env, req, repos, svgrevtree) 
  • revtreeplugin/0.11/revtree/model.py

    r2497 r4024  
    11# -*- coding: utf-8 -*- 
    22# 
    3 # Copyright (C) 2006-2007 Emmanuel Blot <emmanuel.blot@free.fr> 
     3# Copyright (C) 2006-2007 Emmanuel Blot <emmanuel.blot@free.fr>x 
    44# All rights reserved. 
    55# 
     
    2121from trac.util.datefmt import utc 
    2222from trac.util.text import to_unicode 
    23 from trac.versioncontrol import Node, Changeset 
     23from trac.versioncontrol import NoSuchNode, Node as TracNode, \ 
     24                                Changeset as TracChangeset 
    2425 
    2526__all__ = ['Repository'] 
    2627 
    27 class BranchChangeset(object): 
     28 
     29class Changeset(object): 
    2830    """Represents a Subversion revision with additionnal properties""" 
    2931 
     
    3739        # revision number 
    3840        self.rev = self.changeset.rev 
    39         # branch name 
    40         self.branchname = None 
    4141        # clone information (if any) 
    4242        self.clone = None 
     
    4646        self.properties = None 
    4747         
     48    @staticmethod 
     49    def get_chgset_info(tracchgset): 
     50        chgit = tracchgset.get_changes() 
     51        item = chgit.next() 
     52        info = {} 
     53        try: 
     54            chgit.next() 
     55        except StopIteration: 
     56            info['unique'] = True 
     57        else: 
     58            # more changes are available, i.e. this is not a simple changeset  
     59            info['unique'] = False 
     60        enum = ('path', 'kind', 'change', 'base_path', 'base_rev') 
     61        for (pos, name) in enumerate(enum): 
     62            info[name] = item[pos] 
     63        return info 
     64     
    4865    def __cmp__(self, other): 
    4966        """Compares to another changeset, based on the revision number""" 
    5067        return cmp(self.rev, other.rev) 
    5168             
    52     def build(self, bcre): 
    53         """Loads a changeset from a SVN repository 
    54         bcre should define two named groups 'branch' and 'path' 
    55         """ 
    56         try: 
    57             if not self._find_simple_branch(bcre): 
    58                 self._find_plain_branch(bcre) 
    59         except BranchPathError, e: 
    60             self.env.log.warn("%s @ rev %s" % (e, self.rev or 0)) 
    61             self.branchname = None  
    62          
    6369    def _load_properties(self): 
    6470        if not isinstance(self.properties, dict): 
     
    8187                    props[items[1]] = v 
    8288            return props 
    83              
     89 
     90 
     91class BranchChangeset(Changeset): 
     92    """Represents a Subversion revision with lies in a regular branch""" 
     93     
     94    def __init__(self, repos, changeset): 
     95        Changeset.__init__(self, repos, changeset) 
     96        # branch name 
     97        self.branchname = None 
     98        self.prettyname = None 
     99 
    84100    def _find_simple_branch(self, bcre): 
     101        """A 'simple' changeset is described with a changeset whose only  
     102           change is a (branch) directory creation or deletion. Neither a file 
     103           nor a subdirectory should be altered in any way 
     104        """ 
    85105        change_gen = self.changeset.get_changes() 
    86106        item = change_gen.next() 
     
    92112            return False 
    93113        (path, kind, change, base_path, base_rev) = item 
    94         if kind is not Node.DIRECTORY: 
    95             return False 
    96         if change is Changeset.COPY: 
     114        if kind is not TracNode.DIRECTORY: 
     115            return False 
     116        if change is TracChangeset.COPY: 
    97117            path_mo = bcre.match(path) 
    98118            src_mo = bcre.match(base_path) 
    99         elif change is Changeset.DELETE: 
     119        elif change is TracChangeset.DELETE: 
    100120            path_mo = bcre.match(base_path) 
    101121            if path_mo and not path_mo.group('path'): 
     
    108128        if path_mo.group('path'): 
    109129            return False 
    110         self.branchname = path_mo.group('branch') 
    111130        if src_mo: 
    112131            self.clone = (int(base_rev), src_mo.group('branch')) 
     132        self.branchname = path_mo.group('branch') 
     133        self.prettyname = path_mo.group('branchname') or self.branchname 
    113134        return True 
    114135 
    115136    def _find_plain_branch(self, bcre): 
     137        """A 'plain' changeset is a regular changeset, with file addition,  
     138           deletion or modification 
     139        """ 
    116140        branch = None 
    117141        for item in self.changeset.get_changes(): 
     
    130154                raise BranchPathError, "'%s' != '%s'" % (br, branch) 
    131155        self.branchname = branch 
     156        self.prettyname = mo.group('branchname') or self.branchname 
    132157        return True 
     158 
     159    def build(self, bcre): 
     160        """Loads a changeset from a SVN repository 
     161        bcre should define two named groups 'branch' and 'path' 
     162        """ 
     163        try: 
     164            if self._find_simple_branch(bcre): 
     165                return True 
     166            if self._find_plain_branch(bcre): 
     167                return True 
     168        except BranchPathError, e: 
     169            self.env.log.warn("%s @ rev %s" % (e, self.rev or 0)) 
     170        return True 
     171 
     172 
     173class TagChangeset(Changeset): 
     174    """Represent a Subversion 'tags' which is barely not more than a regular 
     175       changeset tied to a specific directory 
     176    """ 
     177     
     178    def __init__(self, repos, changeset): 
     179        Changeset.__init__(self, repos, changeset) 
     180        self.repos = repos 
     181        self.name =  None 
     182        self.prettyname = None 
     183 
     184    def _find_tagged_changeset(self, bcre): 
     185        info = self.get_chgset_info(self.changeset) 
     186        if not info: 
     187            return False 
     188        if not info['unique']: 
     189            self.env.log.warn('Tag: too complex') 
     190            return False 
     191        if info['kind'] is not TracNode.DIRECTORY: 
     192            self.env.log.warn('Tag: not a dir: %s: %s' % \ 
     193                                (info['kind'], info['path'])) 
     194            return False 
     195        if info['change'] is not TracChangeset.COPY: 
     196            self.env.log.warn('Tag: not a copy: %s: %s' % \ 
     197                                (info['change'], info['path'])) 
     198            return False 
     199        path_mo = bcre.match(info['path']) 
     200        if not path_mo: # or not src_mo: 
     201            self.env.log.warn('Tag: with path: %s <- %s' % \ 
     202                                (info['path'], info['base_path'])) 
     203            return False 
     204        if path_mo.group('path'): 
     205            self.env.log.warn('Tag: cannot have path') 
     206            return False 
     207        try: 
     208            node = self.repos.get_node(info['path'], self.changeset.rev) 
     209        except NoSuchNode: 
     210            return False 
     211        (prev_path, prev_rev, prev_chg) = node.get_previous() 
     212        self.env.log.info("PREV: %s %s %s" % (prev_path, prev_rev, prev_chg)) 
     213        self.clone = (int(prev_rev), prev_path) 
     214        self.name = path_mo.group('tag') 
     215        self.prettyname = path_mo.group('tagname') or self.name 
     216        return True 
     217 
     218    def build(self, bcre): 
     219        return self._find_tagged_changeset(bcre) 
     220             
     221    def source(self): 
     222        return self.clone and self.repos.changeset(self.clone[0]) 
     223 
    133224 
    134225class Branch(object): 
     
    136227       changesets""" 
    137228 
    138     def __init__(self, name): 
     229    def __init__(self, name, prettyname): 
    139230        # Name (path) 
    140231        self.name = name 
     232        self.prettyname = prettyname 
    141233        # Source 
    142234        self._source = None 
     
    209301                node = repos.find_node(clone[1], clone[0]) 
    210302                self._source = (int(node[1]), node[0]) 
    211  
     303     
     304     
    212305class Repository(object): 
    213306    """Represents a Subversion repositories as a set of branches and a set 
     
    221314        # Trac version control 
    222315        self._crepos = self.env.get_repository(authname) 
    223         # Dictionnary of changesets 
     316        # Dictionary of changesets 
    224317        self._changesets = {} 
    225         # Dictionnary of branches 
     318        # Dictionary of branches 
    226319        self._branches = {} 
    227  
    228     def _build_branches(self): 
    229         """Constructs the branch dictionnary from the changeset dictionnary"""  
     320        # Dictionary of tags 
     321        self._tags = {} 
     322 
     323    def _dispatch(self): 
     324        """Constructs the branch and tag dictionaries from the changeset  
     325           dictionary"""  
    230326        for chgset in self._changesets.values(): 
    231             br = chgset.branchname 
    232             if not self._branches.has_key(br): 
    233                 self._branches[br] = Branch(br) 
    234             self._branches[br].add_changeset(chgset) 
     327            if isinstance(chgset, BranchChangeset): 
     328                br = chgset.branchname 
     329                if not self._branches.has_key(br): 
     330                    self._branches[br] = Branch(br, chgset.prettyname) 
     331                self._branches[br].add_changeset(chgset) 
     332            elif isinstance(chgset, TagChangeset): 
     333                if self._tags.has_key(chgset.name): 
    &nbs