~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to graph.py

  • Committer: Aaron Bentley
  • Date: 2008-05-30 02:30:22 UTC
  • Revision ID: aaron@aaronbentley.com-20080530023022-l2fzmlvuzkotwnhv
Remove baz-import

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Aaron Bentley
2
 
# <aaron.bentley@utoronto.ca>
 
1
# Copyright (C) 2005, 2008 Aaron Bentley
 
2
# <aaron@aaronbentley.com>
3
3
#
4
4
#    This program is free software; you can redistribute it and/or modify
5
5
#    it under the terms of the GNU General Public License as published by
14
14
#    You should have received a copy of the GNU General Public License
15
15
#    along with this program; if not, write to the Free Software
16
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 
from bzrtools import short_committer
18
 
from dotgraph import Node, dot_output, invoke_dot, invoke_dot_aa, NoDot, NoRsvg
19
 
from dotgraph import RSVG_OUTPUT_TYPES, DOT_OUTPUT_TYPES, Edge, invoke_dot_html
 
17
 
 
18
 
 
19
import time
 
20
 
20
21
from bzrlib.branch import Branch
21
 
from bzrlib.errors import BzrCommandError, NoCommonRoot, NoSuchRevision
 
22
from bzrlib.errors import BzrCommandError, NoSuchRevision
22
23
from bzrlib.graph import node_distances, select_farthest
23
 
from bzrlib.revision import combined_graph, revision_graph
24
 
from bzrlib.revision import MultipleRevisionSources
25
 
import bzrlib.errors
26
 
import re
27
 
import os.path
28
 
import time
 
24
from bzrlib.revision import NULL_REVISION
 
25
 
 
26
from bzrtools import short_committer
 
27
from dotgraph import (
 
28
    dot_output,
 
29
    DOT_OUTPUT_TYPES,
 
30
    Edge,
 
31
    invoke_dot,
 
32
    invoke_dot_aa,
 
33
    invoke_dot_html,
 
34
    Node,
 
35
    NoDot,
 
36
    NoRsvg,
 
37
    RSVG_OUTPUT_TYPES,
 
38
    )
 
39
 
29
40
 
30
41
mail_map = {'aaron.bentley@utoronto.ca'     : 'Aaron Bentley',
31
42
            'abentley@panoramicfeedback.com': 'Aaron Bentley',
106
117
    return committer, message, nick, date
107
118
 
108
119
class Grapher(object):
 
120
 
109
121
    def __init__(self, branch, other_branch=None):
110
122
        object.__init__(self)
111
123
        self.branch = branch
112
124
        self.other_branch = other_branch
 
125
        if other_branch is not None:
 
126
            other_repo = other_branch.repository
 
127
            revision_b = self.other_branch.last_revision()
 
128
        else:
 
129
            other_repo = None
 
130
            revision_b = None
 
131
        self.graph = self.branch.repository.get_graph(other_repo)
113
132
        revision_a = self.branch.last_revision()
114
 
        if other_branch is not None:
115
 
            branch.fetch(other_branch)
116
 
            revision_b = self.other_branch.last_revision()
117
 
            try:
118
 
                self.root, self.ancestors, self.descendants, self.common = \
119
 
                    combined_graph(revision_a, revision_b,
120
 
                                   self.branch.repository)
121
 
            except bzrlib.errors.NoCommonRoot:
122
 
                raise bzrlib.errors.NoCommonAncestor(revision_a, revision_b)
123
 
        else:
124
 
            self.root, self.ancestors, self.descendants = \
125
 
                revision_graph(revision_a, branch.repository)
126
 
            self.common = []
127
 
 
 
133
        self.scan_graph(revision_a, revision_b)
128
134
        self.n_history = branch.revision_history()
 
135
        self.n_revnos = branch.get_revision_id_to_revno_map()
129
136
        self.distances = node_distances(self.descendants, self.ancestors,
130
137
                                        self.root)
131
138
        if other_branch is not None:
132
139
            self.base = select_farthest(self.distances, self.common)
133
140
            self.m_history = other_branch.revision_history()
134
 
            new_graph = getattr(branch.repository, 'get_graph', lambda: None)()
135
 
            if new_graph is None:
136
 
                self.new_base = None
137
 
                self.lcas = set()
138
 
            else:
139
 
                self.new_base = new_graph.find_unique_lca(revision_a,
140
 
                                                          revision_b)
141
 
                self.lcas = new_graph.find_lca(revision_a, revision_b)
 
141
            self.m_revnos = other_branch.get_revision_id_to_revno_map()
 
142
            self.new_base = self.graph.find_unique_lca(revision_a,
 
143
                                                       revision_b)
 
144
            self.lcas = self.graph.find_lca(revision_a, revision_b)
142
145
        else:
143
146
            self.base = None
144
147
            self.new_base = None
145
148
            self.lcas = set()
146
149
            self.m_history = []
 
150
            self.m_revnos = {}
 
151
 
 
152
    def scan_graph(self, revision_a, revision_b):
 
153
        a_ancestors = dict(self.graph.iter_ancestry([revision_a]))
 
154
        self.ancestors = a_ancestors
 
155
        self.root = NULL_REVISION
 
156
        if revision_b is not None:
 
157
            b_ancestors = dict(self.graph.iter_ancestry([revision_b]))
 
158
            self.common = set(a_ancestors.keys())
 
159
            self.common.intersection_update(b_ancestors)
 
160
            self.ancestors.update(b_ancestors)
 
161
        else:
 
162
            self.common = []
 
163
            revision_b = None
 
164
        self.descendants = {}
 
165
        ghosts = set()
 
166
        for revision, parents in self.ancestors.iteritems():
 
167
            self.descendants.setdefault(revision, [])
 
168
            if parents is None:
 
169
                ghosts.add(revision)
 
170
                parents = [NULL_REVISION]
 
171
            for parent in parents:
 
172
                self.descendants.setdefault(parent, []).append(revision)
 
173
        for ghost in ghosts:
 
174
            self.ancestors[ghost] = [NULL_REVISION]
 
175
 
 
176
    @staticmethod
 
177
    def _get_revno_str(prefix, revno_map, revision_id):
 
178
        try:
 
179
            revno = revno_map[revision_id]
 
180
        except KeyError:
 
181
            return None
 
182
        return '%s%s' % (prefix, '.'.join(str(n) for n in revno))
147
183
 
148
184
    def dot_node(self, node, num):
149
185
        try:
155
191
        except ValueError:
156
192
            m_rev = None
157
193
        if (n_rev, m_rev) == (None, None):
158
 
            name = node[-5:]
 
194
            name = self._get_revno_str('r', self.n_revnos, node)
 
195
            if name is None:
 
196
                name = self._get_revno_str('R', self.m_revnos, node)
 
197
            if name is None:
 
198
                name = node[-5:]
159
199
            cluster = None
160
200
        elif n_rev == m_rev:
161
201
            name = "rR%d" % n_rev
294
334
            done = True
295
335
        except NoDot, e:
296
336
            raise BzrCommandError("Can't find 'dot'.  Please ensure Graphviz"\
297
 
                " is installed correctly, or use --noantialias")
 
337
                " is installed correctly.")
298
338
    elif ext == 'dot' and not done:
299
339
        my_file = file(filename, 'wb')
300
340
        for fragment in output:
304
344
            invoke_dot_html(output, filename)
305
345
        except NoDot, e:
306
346
            raise BzrCommandError("Can't find 'dot'.  Please ensure Graphviz"\
307
 
                " is installed correctly, or use --noantialias")
 
347
                " is installed correctly.")
308
348
    elif not done:
309
349
        print "Unknown file extension: %s" % ext
310