~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to graph.py

  • Committer: Aaron Bentley
  • Date: 2005-09-22 18:12:30 UTC
  • Revision ID: abentley@panoramicfeedback.com-20050922181230-4ef95c7a832bd760
Use Grapher for both kinds of graphs

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
from bzrlib.errors import BzrCommandError, NoCommonRoot, NoSuchRevision
5
5
from bzrlib.fetch import greedy_fetch
6
6
from bzrlib.graph import node_distances, select_farthest
7
 
from bzrlib.revision import combined_graph, MultipleRevisionSources
 
7
from bzrlib.revision import combined_graph, revision_graph
 
8
from bzrlib.revision import MultipleRevisionSources
8
9
import bzrlib.errors
9
10
import re
10
11
import os.path
18
19
                })
19
20
 
20
21
committer_alias = {'abentley': 'Aaron Bentley'}
21
 
def add_relations(rev_id):
22
 
    if rev_id in ancestors:
23
 
        return
24
 
    print rev_id
25
 
    if rev_id not in nodes:
26
 
        nodes[rev_id] = Node("n%d" % counter, label = rev_id)
27
 
        counter += 1
28
 
    revision = branch.get_revision(rev_id)
29
 
    ancestors [rev_id] = []
30
 
    for p in (p.revision_id for p in revision.parents):
31
 
        add_relations(p)
32
 
        if p not in descendants:
33
 
            descendants[p] = []
34
 
        descendants[p].append(rev_id)
35
 
        ancestors [rev_id].append(rev_id)
36
 
 
37
22
def short_committer(committer):
38
23
    new_committer = re.sub('<.*>', '', committer).strip(' ')
39
24
    if len(new_committer) < 2:
75
60
            new_ancestors[me][new_parent] = distance
76
61
    return new_ancestors    
77
62
 
78
 
def compact_descendants(descendants, ancestors):
79
 
    new_descendants={}
80
 
    skip = set()
81
 
    for me, my_descendants in descendants.iteritems():
82
 
        if me in skip:
83
 
            continue
84
 
        new_descendants[me] = []
85
 
        for descendant in my_descendants:
86
 
            new_descendant = descendant
87
 
            while can_skip(new_descendant, descendants, ancestors):
88
 
                skip.add(new_descendant)
89
 
                if new_descendant in new_descendants:
90
 
                    del new_descendants[new_descendant]
91
 
                new_descendant = descendants[new_descendant][0]
92
 
            new_descendants[me].append(new_descendant)
93
 
    return new_descendants    
94
 
 
95
 
 
96
 
def graph_ancestry(branch, collapse=True):
97
 
    nodes = {}
98
 
    q = ((i+1, n) for (i, n) in enumerate(branch.revision_history()))
99
 
    r = 1
100
 
    try:
101
 
        branch_name = os.path.basename(branch.base)
102
 
    except AttributeError:
103
 
        branch_name = "main"
104
 
    for (revno, rev_id) in q:
105
 
        nodes[rev_id] = Node("R%d" % revno, color="#ffff00", rev_id=rev_id, 
106
 
                             cluster=branch_name)
107
 
 
108
 
    ancestors = {} 
109
 
    descendants = {}
110
 
    counter = 0
111
 
    lines = [branch.last_patch()]
112
 
    while len(lines) > 0:
113
 
        new_lines = set()
114
 
        for rev_id in lines:
115
 
            if rev_id not in nodes:
116
 
                nodes[rev_id] = Node("n%d" % counter, label=rev_id, 
117
 
                                     rev_id=rev_id)
118
 
                counter+=1
119
 
                
120
 
            try:
121
 
                revision = branch.get_revision(rev_id)
122
 
            except bzrlib.errors.NoSuchRevision:
123
 
                nodes[rev_id].node_style.append('dotted')
124
 
                continue
125
 
            if nodes[rev_id].committer is None:
126
 
                nodes[rev_id].committer = short_committer(revision.committer)
127
 
            parent_ids = [r.revision_id for r in revision.parents]
128
 
            ancestors [rev_id] = parent_ids
129
 
            for parent in parent_ids:
130
 
                if parent not in ancestors:
131
 
                    new_lines.add(parent)
132
 
                    descendants[parent] = []
133
 
                descendants[parent].append(rev_id)
134
 
        lines = new_lines
135
 
    node_relations = []
136
 
 
137
 
    for node in nodes.itervalues():
138
 
        node.label = node.get_label()
139
 
    if collapse:
140
 
        visible_descendants = compact_descendants(descendants, ancestors)
141
 
    else:
142
 
        visible_descendants = descendants
143
 
                
144
 
    for key, values in visible_descendants.iteritems():
145
 
        for value in values:
146
 
            node_relations.append((nodes[key], nodes[value]))
147
 
    return node_relations
148
 
 
149
63
def get_committer(rev_id, source):
150
64
    try:
151
65
        committer = short_committer(source.get_revision(rev_id).committer)
168
82
    return committer
169
83
 
170
84
class Grapher(object):
171
 
    def __init__(self, branch, other_branch):
 
85
    def __init__(self, branch, other_branch=None):
172
86
        object.__init__(self)
173
87
        self.branch = branch
174
88
        self.other_branch = other_branch
175
 
        greedy_fetch(branch, other_branch)
176
89
        revision_a = self.branch.last_patch()
177
 
        revision_b = self.other_branch.last_patch()
178
 
        try:
179
 
            self.root, self.ancestors, self.descendants, self.common = \
180
 
                combined_graph(revision_a, revision_b, self.branch)
181
 
        except bzrlib.errors.NoCommonRoot:
182
 
            raise bzrlib.errors.NoCommonAncestor(revision_a, revision_b)
 
90
        if other_branch is not None:
 
91
            greedy_fetch(branch, other_branch)
 
92
            revision_b = self.other_branch.last_patch()
 
93
            try:
 
94
                self.root, self.ancestors, self.descendants, self.common = \
 
95
                    combined_graph(revision_a, revision_b, self.branch)
 
96
            except bzrlib.errors.NoCommonRoot:
 
97
                raise bzrlib.errors.NoCommonAncestor(revision_a, revision_b)
 
98
        else:
 
99
            self.root, self.ancestors, self.descendants = \
 
100
                revision_graph(revision_a, branch)
 
101
            self.common = []
 
102
 
 
103
        self.n_history = branch.revision_history()
183
104
        self.distances = node_distances(self.descendants, self.ancestors, 
184
105
                                        self.root)
185
 
        self.base = select_farthest(self.distances, self.common)
186
 
        self.n_history = branch.revision_history()
187
 
        self.m_history = other_branch.revision_history() 
 
106
        if other_branch is not None:
 
107
            self.base = select_farthest(self.distances, self.common)
 
108
            self.m_history = other_branch.revision_history() 
 
109
        else:
 
110
            self.base = None
 
111
            self.m_history = []
188
112
 
189
113
    def dot_node(self, node, num):
190
114
        try:
276
200
def write_ancestry_file(branch, filename, collapse=True, antialias=True,
277
201
                        merge_branch=None, ranking="forced"):
278
202
    b = Branch.open_containing(branch)
279
 
    if merge_branch is None:
280
 
        relations = graph_ancestry(b, collapse)
281
 
    else:
 
203
    if merge_branch is not None:
282
204
        m = Branch.open_containing(merge_branch)
283
 
        grapher = Grapher(b, m)
284
 
        relations = grapher.get_relations(collapse)
 
205
    else:
 
206
        m = None
 
207
    grapher = Grapher(b, m)
 
208
    relations = grapher.get_relations(collapse)
285
209
 
286
210
    ext = filename.split('.')[-1]
287
211
    output = dot_output(relations, ranking)