comparison mercurial/graphmod.py @ 8842:acd03a6e2426

graphmod/webcommands: use generic DAG walks Changes graph() to colorededges(), which operates on the new generic DAG walks and adds color and edge information needed by the web graph. This is in preparation of adding DAG walk filters, like the linear run collapser in the next patch. The idea is to have a bunch of changelog walkers that return basic data. Then we can filter this data. Finally we add edge and formatting info suitable for the output media we want to target (glog, hgweb).
author Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
date Fri, 19 Jun 2009 13:44:23 +0200
parents 94ac080e7af9
children d00cee04a746
comparison
equal deleted inserted replaced
8841:94ac080e7af9 8842:acd03a6e2426
27 This generator function walks through the revision history from revision 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 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 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. 30 integers which identify a node in the context of the graph returned.
31 """ 31 """
32 assert start >= stop
33 cur = start 32 cur = start
34 while cur >= stop: 33 while cur >= stop:
35 ctx = repo[cur] 34 ctx = repo[cur]
36 parents = [p.rev() for p in ctx.parents() if p.rev() != nullrev] 35 parents = [p.rev() for p in ctx.parents() if p.rev() != nullrev]
37 yield (cur, CHANGESET, ctx, sorted(parents)) 36 yield (cur, CHANGESET, ctx, sorted(parents))
39 38
40 def filerevs(repo, path, start, stop): 39 def filerevs(repo, path, start, stop):
41 """file cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples 40 """file cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
42 41
43 This generator function walks through the revision history of a single 42 This generator function walks through the revision history of a single
44 file from revision start to revision stop (which must be less than or 43 file from revision start down to revision stop.
45 equal to start).
46 """ 44 """
47 assert start >= stop
48 filerev = len(repo.file(path)) - 1 45 filerev = len(repo.file(path)) - 1
49 while filerev >= 0: 46 while filerev >= 0:
50 fctx = repo.filectx(path, fileid=filerev) 47 fctx = repo.filectx(path, fileid=filerev)
51 parents = [f.linkrev() for f in fctx.parents() if f.path() == path] 48 parents = [f.linkrev() for f in fctx.parents() if f.path() == path]
52 rev = fctx.rev() 49 rev = fctx.rev()
66 for node in nodes: 63 for node in nodes:
67 ctx = repo[node] 64 ctx = repo[node]
68 parents = [p.rev() for p in ctx.parents() if p.node() in include] 65 parents = [p.rev() for p in ctx.parents() if p.node() in include]
69 yield (ctx.rev(), CHANGESET, ctx, sorted(parents)) 66 yield (ctx.rev(), CHANGESET, ctx, sorted(parents))
70 67
71 def graph(repo, start_rev, stop_rev): 68 def colored(dag):
72 """incremental revision grapher 69 """annotates a DAG with colored edge information
73 70
74 This generator function walks through the revision history from 71 For each DAG node this function emits tuples::
75 revision start_rev to revision stop_rev (which must be less than
76 or equal to start_rev) and for each revision emits tuples with the
77 following elements:
78 72
79 - Context of the current node 73 (id, type, data, (col, color), [(col, nextcol, color)])
74
75 with the following new elements:
76
80 - Tuple (col, color) with column and color index for the current node 77 - Tuple (col, color) with column and color index for the current node
81 - Edges; a list of (col, next_col, color) indicating the edges between 78 - A list of tuples indicating the edges between the current node and its
82 the current node and its parents. 79 parents.
83 """ 80 """
84
85 if start_rev == nullrev and not stop_rev:
86 return
87
88 assert start_rev >= stop_rev
89 assert stop_rev >= 0
90 cur = start_rev
91 seen = [] 81 seen = []
92 cl = repo.changelog
93 colors = {} 82 colors = {}
94 newcolor = 1 83 newcolor = 1
84 for (cur, type, data, parents) in dag:
95 85
96 while cur >= stop_rev:
97 # Compute seen and next 86 # Compute seen and next
98 if cur not in seen: 87 if cur not in seen:
99 seen.append(cur) # new head 88 seen.append(cur) # new head
100 colors[cur] = newcolor 89 colors[cur] = newcolor
101 newcolor += 1 90 newcolor += 1
102 91
103 col = seen.index(cur) 92 col = seen.index(cur)
104 color = colors.pop(cur) 93 color = colors.pop(cur)
105 next = seen[:] 94 next = seen[:]
106 95
107 # Add parents to next_revs 96 # Add parents to next
108 parents = [x for x in cl.parentrevs(cur) if x != nullrev]
109 addparents = [p for p in parents if p not in next] 97 addparents = [p for p in parents if p not in next]
110 next[col:col + 1] = addparents 98 next[col:col + 1] = addparents
111 99
112 # Set colors for the parents 100 # Set colors for the parents
113 for i, p in enumerate(addparents): 101 for i, p in enumerate(addparents):
120 # Add edges to the graph 108 # Add edges to the graph
121 edges = [] 109 edges = []
122 for ecol, eid in enumerate(seen): 110 for ecol, eid in enumerate(seen):
123 if eid in next: 111 if eid in next:
124 edges.append((ecol, next.index(eid), colors[eid])) 112 edges.append((ecol, next.index(eid), colors[eid]))
125 elif eid == id: 113 elif eid == cur:
126 for p in parents: 114 for p in parents:
127 edges.append((ecol, next.index(p), colors[p])) 115 edges.append((ecol, next.index(p), colors[p]))
128 116
129 # Yield and move on 117 # Yield and move on
130 yield (repo[cur], (col, color), edges) 118 yield (cur, type, data, (col, color), edges)
131 seen = next 119 seen = next
132 cur -= 1