/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to graph.py

  • Committer: Scott James Remnant
  • Date: 2005-10-17 01:07:49 UTC
  • Revision ID: scott@netsplit.com-20051017010749-15fa95fc2cf09289
Commit the first version of bzrk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
        self.message = self.revision_id
31
31
 
32
32
 
33
 
def distances(branch, start):
34
 
    """Sort the revisions.
 
33
def graph(branch, start):
 
34
    """Produce a directed graph of a bzr branch.
35
35
 
36
36
    Traverses the branch revision tree starting at start and produces an
37
37
    ordered list of revisions such that a revision always comes after
38
 
    any revision it is the parent of.
39
 
 
40
 
    Returns a tuple of (revids, revisions, colours, children)
 
38
    any revision it is the parent of.  It also tries to make a reasonably
 
39
    not-too-stupid decision whether a parent revision is on the same
 
40
    logical branch, as that information is not available with bzr.
 
41
 
 
42
    For each revision it then yields a tuple of (revision, node, lines).
 
43
    If the revision is only referenced in the branch and not present in the
 
44
    store, revision will be a DummyRevision object, otherwise it is the bzr
 
45
    Revision object with the meta-data for the revision.
 
46
 
 
47
    Node is a tuple of (column, colour) with column being a zero-indexed
 
48
    column number of the graph that this revision represents and colour
 
49
    being a zero-indexed colour (which doesn't specify any actual colour
 
50
    in particular) to draw the node in.
 
51
 
 
52
    Lines is a list of tuples which represent lines you should draw away
 
53
    from the revision, if you also need to draw lines into the revision
 
54
    you should use the lines list from the previous iteration.  Each
 
55
    typle in the list is in the form (start, end, colour) with start and
 
56
    end being zero-indexed column numbers and colour as in node.
 
57
 
 
58
    It's up to you how to actually draw the nodes and lines (straight,
 
59
    curved, kinked, etc.) and to pick the actual colours for each index.
41
60
    """
42
61
    revisions = { start: branch.get_revision(start) }
43
 
    children = { revisions[start]: set() }
44
62
    distances = { start: 0 }
45
63
    colours = { start: 0 }
46
64
    last_colour = 0
56
74
        distance = distances[revid] + 1
57
75
        colour = colours[revid]
58
76
 
 
77
        reused = False
59
78
        for parent_id in revision.parent_ids:
60
79
            # Check whether there's any point re-processing this
61
80
            if parent_id in distances and distances[parent_id] >= distance:
64
83
            # Get the parent from the cache, or put it in the cache
65
84
            try:
66
85
                parent = revisions[parent_id]
67
 
                children[parent].add(revision)
68
86
            except KeyError:
69
87
                try:
70
88
                    parent = revisions[parent_id] \
72
90
                except NoSuchRevision:
73
91
                    parent = revisions[parent_id] = DummyRevision(parent_id)
74
92
 
75
 
                children[parent] = set([ revision ])
76
 
 
77
 
            # Penalise revisions a little at a fork if we think they're on
78
 
            # the same branch -- this makes the few few (at least) revisions
79
 
            # of a branch appear straight after the fork
80
 
            if same_branch(revision, parent):
81
 
                colours[parent_id] = colour
82
 
                if len(revision.parent_ids) > 1:
83
 
                    distances[parent_id] = distance + 10
84
 
                else:
85
 
                    distances[parent_id] = distance
 
93
            # Make a guess as to whether this node represents the same
 
94
            # branch, or a new one.  Penalise same branches in the distance
 
95
            # stakes to give new ones a chance to appear first as one set.
 
96
            if len(revision.parent_ids) == 1:
 
97
                colours[parent_id] = colour
 
98
                distances[parent_id] = distance
 
99
            elif revision.committer == parent.committer and not reused:
 
100
                colours[parent_id] = colour
 
101
                distances[parent_id] = distance
 
102
                reused = True
86
103
            else:
87
104
                colours[parent_id] = last_colour = last_colour + 1
88
 
                distances[parent_id] = distance
 
105
                distances[parent_id] = distance + 10
89
106
 
90
107
            todo.add(parent_id)
91
108
 
92
 
    return ( sorted(distances, key=distances.get), revisions, colours,
93
 
             children )
94
 
 
95
 
def graph(revids, revisions, colours):
96
 
    """Produce a directed graph of a bzr branch.
97
 
 
98
 
    For each revision it then yields a tuple of (revision, node, lines).
99
 
    If the revision is only referenced in the branch and not present in the
100
 
    store, revision will be a DummyRevision object, otherwise it is the bzr
101
 
    Revision object with the meta-data for the revision.
102
 
 
103
 
    Node is a tuple of (column, colour) with column being a zero-indexed
104
 
    column number of the graph that this revision represents and colour
105
 
    being a zero-indexed colour (which doesn't specify any actual colour
106
 
    in particular) to draw the node in.
107
 
 
108
 
    Lines is a list of tuples which represent lines you should draw away
109
 
    from the revision, if you also need to draw lines into the revision
110
 
    you should use the lines list from the previous iteration.  Each
111
 
    typle in the list is in the form (start, end, colour) with start and
112
 
    end being zero-indexed column numbers and colour as in node.
113
 
 
114
 
    It's up to you how to actually draw the nodes and lines (straight,
115
 
    curved, kinked, etc.) and to pick the actual colours for each index.
116
 
    """
117
 
    hanging = revids[:1]
118
 
    for revid in revids:
 
109
    # Now iterate the revisions again, but this time in list order rather
 
110
    # than traversing the tree, and build up the graph lines.  We do this
 
111
    # by keeping a list of "hanging parents", which can only be removed
 
112
    # once we encounter the revision being hung.
 
113
    hanging = [ start ]
 
114
    for revid in sorted(distances, key=distances.get):
119
115
        lines = []
120
116
        node = None
121
117
 
150
146
        hanging = new_hanging
151
147
 
152
148
        yield (revisions[revid], node, lines)
153
 
 
154
 
def same_branch(a, b):
155
 
    """Return whether we think revisions a and b are on the same branch."""
156
 
    if len(a.parent_ids) == 1:
157
 
        # Defacto same branch if only parent
158
 
        return True
159
 
    elif a.committer == b.committer:
160
 
        # Same committer so may as well be
161
 
        return True
162
 
    else:
163
 
        return False