|
1 # Revision graph generator for Mercurial |
|
2 # |
|
3 # Copyright 2008 Dirkjan Ochtman <dirkjan@ochtman.nl> |
|
4 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net> |
|
5 # |
|
6 # This software may be used and distributed according to the terms of the |
|
7 # GNU General Public License version 2 or any later version. |
|
8 |
|
9 """supports walking the history as DAGs suitable for graphical output |
|
10 |
|
11 The most basic format we use is that of:: |
|
12 |
|
13 (id, type, data, [parentids]) |
|
14 |
|
15 The node and parent ids are arbitrary integers which identify a node in the |
|
16 context of the graph returned. Type is a constant specifying the node type. |
|
17 Data depends on type. |
|
18 """ |
|
19 |
|
20 from mercurial.node import nullrev |
|
21 |
|
22 CHANGESET = 'C' |
|
23 |
|
24 def revisions(repo, start, stop): |
|
25 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples |
|
26 |
|
27 This generator function walks through the revision history from revision |
|
28 start to revision stop (which must be less than or equal to start). It |
|
29 returns a tuple for each node. The node and parent ids are arbitrary |
|
30 integers which identify a node in the context of the graph returned. |
|
31 """ |
|
32 cur = start |
|
33 while cur >= stop: |
|
34 ctx = repo[cur] |
|
35 parents = set([p.rev() for p in ctx.parents() if p.rev() != nullrev]) |
|
36 yield (cur, CHANGESET, ctx, sorted(parents)) |
|
37 cur -= 1 |
|
38 |
|
39 def filerevs(repo, path, start, stop, limit=None): |
|
40 """file cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples |
|
41 |
|
42 This generator function walks through the revision history of a single |
|
43 file from revision start down to revision stop. |
|
44 """ |
|
45 filerev = len(repo.file(path)) - 1 |
|
46 rev = stop + 1 |
|
47 count = 0 |
|
48 while filerev >= 0 and rev > stop: |
|
49 fctx = repo.filectx(path, fileid=filerev) |
|
50 parents = set([f.linkrev() for f in fctx.parents() if f.path() == path]) |
|
51 rev = fctx.rev() |
|
52 if rev <= start: |
|
53 yield (rev, CHANGESET, fctx.changectx(), sorted(parents)) |
|
54 count += 1 |
|
55 if count == limit: |
|
56 break |
|
57 filerev -= 1 |
|
58 |
|
59 def nodes(repo, nodes): |
|
60 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples |
|
61 |
|
62 This generator function walks the given nodes. It only returns parents |
|
63 that are in nodes, too. |
|
64 """ |
|
65 include = set(nodes) |
|
66 for node in nodes: |
|
67 ctx = repo[node] |
|
68 parents = set([p.rev() for p in ctx.parents() if p.node() in include]) |
|
69 yield (ctx.rev(), CHANGESET, ctx, sorted(parents)) |
|
70 |
|
71 def colored(dag): |
|
72 """annotates a DAG with colored edge information |
|
73 |
|
74 For each DAG node this function emits tuples:: |
|
75 |
|
76 (id, type, data, (col, color), [(col, nextcol, color)]) |
|
77 |
|
78 with the following new elements: |
|
79 |
|
80 - Tuple (col, color) with column and color index for the current node |
|
81 - A list of tuples indicating the edges between the current node and its |
|
82 parents. |
|
83 """ |
|
84 seen = [] |
|
85 colors = {} |
|
86 newcolor = 1 |
|
87 for (cur, type, data, parents) in dag: |
|
88 |
|
89 # Compute seen and next |
|
90 if cur not in seen: |
|
91 seen.append(cur) # new head |
|
92 colors[cur] = newcolor |
|
93 newcolor += 1 |
|
94 |
|
95 col = seen.index(cur) |
|
96 color = colors.pop(cur) |
|
97 next = seen[:] |
|
98 |
|
99 # Add parents to next |
|
100 addparents = [p for p in parents if p not in next] |
|
101 next[col:col + 1] = addparents |
|
102 |
|
103 # Set colors for the parents |
|
104 for i, p in enumerate(addparents): |
|
105 if not i: |
|
106 colors[p] = color |
|
107 else: |
|
108 colors[p] = newcolor |
|
109 newcolor += 1 |
|
110 |
|
111 # Add edges to the graph |
|
112 edges = [] |
|
113 for ecol, eid in enumerate(seen): |
|
114 if eid in next: |
|
115 edges.append((ecol, next.index(eid), colors[eid])) |
|
116 elif eid == cur: |
|
117 for p in parents: |
|
118 edges.append((ecol, next.index(p), color)) |
|
119 |
|
120 # Yield and move on |
|
121 yield (cur, type, data, (col, color), edges) |
|
122 seen = next |