~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to graph.py

  • Committer: Aaron Bentley
  • Date: 2007-07-12 20:55:33 UTC
  • mfrom: (553.1.1 bzrtools)
  • Revision ID: abentley@panoramicfeedback.com-20070712205533-ael98t8ly97zuba3
Merge option help fixes from vila

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2008 Aaron Bentley
2
 
# <aaron@aaronbentley.com>
 
1
# Copyright (C) 2005 Aaron Bentley
 
2
# <aaron.bentley@utoronto.ca>
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
 
 
18
 
 
 
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
 
20
from bzrlib.branch import Branch
 
21
from bzrlib.errors import BzrCommandError, NoCommonRoot, NoSuchRevision
 
22
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
19
28
import time
20
29
 
21
 
from bzrlib.branch import Branch
22
 
from bzrlib.errors import BzrCommandError, NoSuchRevision
23
 
from bzrlib.deprecated_graph import node_distances, select_farthest
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
 
 
40
 
 
41
30
mail_map = {'aaron.bentley@utoronto.ca'     : 'Aaron Bentley',
42
31
            'abentley@panoramicfeedback.com': 'Aaron Bentley',
43
32
            'abentley@lappy'                : 'Aaron Bentley',
117
106
    return committer, message, nick, date
118
107
 
119
108
class Grapher(object):
120
 
 
121
109
    def __init__(self, branch, other_branch=None):
122
110
        object.__init__(self)
123
111
        self.branch = branch
124
112
        self.other_branch = other_branch
 
113
        revision_a = self.branch.last_revision()
125
114
        if other_branch is not None:
126
 
            other_repo = other_branch.repository
 
115
            branch.fetch(other_branch)
127
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)
128
123
        else:
129
 
            other_repo = None
130
 
            revision_b = None
131
 
        self.graph = self.branch.repository.get_graph(other_repo)
132
 
        revision_a = self.branch.last_revision()
133
 
        self.scan_graph(revision_a, revision_b)
 
124
            self.root, self.ancestors, self.descendants = \
 
125
                revision_graph(revision_a, branch.repository)
 
126
            self.common = []
 
127
 
134
128
        self.n_history = branch.revision_history()
135
 
        self.n_revnos = branch.get_revision_id_to_revno_map()
136
129
        self.distances = node_distances(self.descendants, self.ancestors,
137
130
                                        self.root)
138
131
        if other_branch is not None:
139
132
            self.base = select_farthest(self.distances, self.common)
140
133
            self.m_history = other_branch.revision_history()
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)
 
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)
145
142
        else:
146
143
            self.base = None
147
144
            self.new_base = None
148
145
            self.lcas = set()
149
146
            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))
183
147
 
184
148
    def dot_node(self, node, num):
185
149
        try:
191
155
        except ValueError:
192
156
            m_rev = None
193
157
        if (n_rev, m_rev) == (None, None):
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:]
 
158
            name = node[-5:]
199
159
            cluster = None
200
160
        elif n_rev == m_rev:
201
161
            name = "rR%d" % n_rev
334
294
            done = True
335
295
        except NoDot, e:
336
296
            raise BzrCommandError("Can't find 'dot'.  Please ensure Graphviz"\
337
 
                " is installed correctly.")
 
297
                " is installed correctly, or use --noantialias")
338
298
    elif ext == 'dot' and not done:
339
299
        my_file = file(filename, 'wb')
340
300
        for fragment in output:
344
304
            invoke_dot_html(output, filename)
345
305
        except NoDot, e:
346
306
            raise BzrCommandError("Can't find 'dot'.  Please ensure Graphviz"\
347
 
                " is installed correctly.")
 
307
                " is installed correctly, or use --noantialias")
348
308
    elif not done:
349
309
        print "Unknown file extension: %s" % ext
 
310