##// END OF EJS Templates
graphlog: refactor common grapher code...
Peter Arrenbrecht -
r7370:7bc62ebe default
parent child Browse files
Show More
@@ -13,115 +13,76 b' from mercurial.commands import templateo'
13 from mercurial.i18n import _
13 from mercurial.i18n import _
14 from mercurial.node import nullrev
14 from mercurial.node import nullrev
15 from mercurial.util import Abort, canonpath
15 from mercurial.util import Abort, canonpath
16 from mercurial import util
17
18 def get_rev_parents(repo, rev):
19 return [x for x in repo.changelog.parentrevs(rev) if x != nullrev]
20
21 def revision_grapher(repo, start_rev, stop_rev):
22 """incremental revision grapher
23
24 This generator function walks through the revision history from
25 revision start_rev to revision stop_rev (which must be less than
26 or equal to start_rev) and for each revision emits tuples with the
27 following elements:
28
29 - Current revision.
30 - Current node.
31 - Column of the current node in the set of ongoing edges.
32 - Edges; a list of (col, next_col) indicating the edges between
33 the current node and its parents.
34 - Number of columns (ongoing edges) in the current revision.
35 - The difference between the number of columns (ongoing edges)
36 in the next revision and the number of columns (ongoing edges)
37 in the current revision. That is: -1 means one column removed;
38 0 means no columns added or removed; 1 means one column added.
39 """
40
41 assert start_rev >= stop_rev
42 curr_rev = start_rev
43 revs = []
44 while curr_rev >= stop_rev:
45 node = repo.changelog.node(curr_rev)
46
47 # Compute revs and next_revs.
48 if curr_rev not in revs:
49 # New head.
50 revs.append(curr_rev)
51 rev_index = revs.index(curr_rev)
52 next_revs = revs[:]
53
16
54 # Add parents to next_revs.
17 def revisions(repo, start, stop):
55 parents = get_rev_parents(repo, curr_rev)
18 """cset DAG generator yielding (rev, node, [parents]) tuples
56 parents_to_add = []
19
57 for parent in parents:
20 This generator function walks through the revision history from revision
58 if parent not in next_revs:
21 start to revision stop (which must be less than or equal to start).
59 parents_to_add.append(parent)
22 """
60 next_revs[rev_index:rev_index + 1] = util.sort(parents_to_add)
23 assert start >= stop
61
24 cur = start
62 edges = []
25 while cur >= stop:
63 for parent in parents:
26 ctx = repo[cur]
64 edges.append((rev_index, next_revs.index(parent)))
27 parents = sorted(p.rev() for p in ctx.parents() if p.rev() != nullrev)
65
28 yield (ctx, parents)
66 n_columns_diff = len(next_revs) - len(revs)
29 cur -= 1
67 yield (curr_rev, node, rev_index, edges, len(revs), n_columns_diff)
68
69 revs = next_revs
70 curr_rev -= 1
71
30
72 def filelog_grapher(repo, path, start_rev, stop_rev):
31 def filerevs(repo, path, start, stop):
73 """incremental file log grapher
32 """file cset DAG generator yielding (rev, node, [parents]) tuples
74
33
75 This generator function walks through the revision history of a
34 This generator function walks through the revision history of a single
76 single file from revision start_rev to revision stop_rev (which must
35 file from revision start to revision stop (which must be less than or
77 be less than or equal to start_rev) and for each revision emits
36 equal to start).
78 tuples with the following elements:
79
80 - Current revision.
81 - Current node.
82 - Column of the current node in the set of ongoing edges.
83 - Edges; a list of (col, next_col) indicating the edges between
84 the current node and its parents.
85 - Number of columns (ongoing edges) in the current revision.
86 - The difference between the number of columns (ongoing edges)
87 in the next revision and the number of columns (ongoing edges)
88 in the current revision. That is: -1 means one column removed;
89 0 means no columns added or removed; 1 means one column added.
90 """
37 """
91
38 assert start >= stop
92 assert start_rev >= stop_rev
93 revs = []
94 filerev = len(repo.file(path)) - 1
39 filerev = len(repo.file(path)) - 1
95 while filerev >= 0:
40 while filerev >= 0:
96 fctx = repo.filectx(path, fileid=filerev)
41 fctx = repo.filectx(path, fileid=filerev)
42 parents = [f.filerev() for f in fctx.parents() if f.path() == path]
43 parents.sort()
44 if fctx.rev() <= start:
45 yield (fctx, parents)
46 if fctx.rev() <= stop:
47 break
48 filerev -= 1
97
49
98 # Compute revs and next_revs.
50 def grapher(nodes):
99 if filerev not in revs:
51 """grapher for asciigraph on a list of nodes and their parents
100 revs.append(filerev)
52
101 rev_index = revs.index(filerev)
53 nodes must generate tuples (node, parents, char, lines) where
102 next_revs = revs[:]
54
55 - parents must generate the parents of node, in sorted order,
56 and max length 2,
57 - char is the char to print as the node symbol, and
58 - lines are the lines to display next to the node.
59 """
60 seen = []
61 for node, parents, char, lines in nodes:
62 if node not in seen:
63 seen.append(node)
64 nodeidx = seen.index(node)
103
65
104 # Add parents to next_revs.
66 knownparents = []
105 parents = [f.filerev() for f in fctx.parents() if f.path() == path]
67 newparents = []
106 parents_to_add = []
107 for parent in parents:
68 for parent in parents:
108 if parent not in next_revs:
69 if parent in seen:
109 parents_to_add.append(parent)
70 knownparents.append(parent)
110 next_revs[rev_index:rev_index + 1] = util.sort(parents_to_add)
71 else:
111
72 newparents.append(parent)
112 edges = []
113 for parent in parents:
114 edges.append((rev_index, next_revs.index(parent)))
115
73
116 changerev = fctx.linkrev()
74 ncols = len(seen)
117 if changerev <= start_rev:
75 nextseen = seen[:]
118 node = repo.changelog.node(changerev)
76 nextseen[nodeidx:nodeidx + 1] = newparents
119 n_columns_diff = len(next_revs) - len(revs)
77 edges = [(nodeidx, nextseen.index(p)) for p in knownparents]
120 yield (changerev, node, rev_index, edges, len(revs), n_columns_diff)
78
121 if changerev <= stop_rev:
79 if len(newparents) > 0:
122 break
80 edges.append((nodeidx, nodeidx))
123 revs = next_revs
81 if len(newparents) > 1:
124 filerev -= 1
82 edges.append((nodeidx, nodeidx + 1))
83 nmorecols = len(nextseen) - ncols
84 seen = nextseen
85 yield (char, lines, nodeidx, edges, ncols, nmorecols)
125
86
126 def fix_long_right_edges(edges):
87 def fix_long_right_edges(edges):
127 for (i, (start, end)) in enumerate(edges):
88 for (i, (start, end)) in enumerate(edges):
@@ -307,33 +268,31 b' def graphlog(ui, repo, path=None, **opts'
307 """
268 """
308
269
309 limit = get_limit(opts["limit"])
270 limit = get_limit(opts["limit"])
310 (start_rev, stop_rev) = get_revs(repo, opts["rev"])
271 start, stop = get_revs(repo, opts["rev"])
311 stop_rev = max(stop_rev, start_rev - limit + 1)
272 stop = max(stop, start - limit + 1)
312 if start_rev == nullrev:
273 if start == nullrev:
313 return
274 return
275
314 if path:
276 if path:
315 path = canonpath(repo.root, os.getcwd(), path)
277 path = canonpath(repo.root, os.getcwd(), path)
316 if path:
278 if path: # could be reset in canonpath
317 revgrapher = filelog_grapher(repo, path, start_rev, stop_rev)
279 revdag = filerevs(repo, path, start, stop)
318 else:
280 else:
319 revgrapher = revision_grapher(repo, start_rev, stop_rev)
281 revdag = revisions(repo, start, stop)
320
282
321 repo_parents = repo.dirstate.parents()
283 repo_parents = repo.dirstate.parents()
322 cs_printer = show_changeset(ui, repo, opts)
284 displayer = show_changeset(ui, repo, opts)
323 def grapher():
285 def graphabledag():
324 for (rev, node, node_index, edges, n_columns, n_columns_diff) in revgrapher:
286 for (ctx, parents) in revdag:
325 # log_strings is the list of all log strings to draw alongside
287 # log_strings is the list of all log strings to draw alongside
326 # the graph.
288 # the graph.
327 ui.pushbuffer()
289 ui.pushbuffer()
328 cs_printer.show(repo[rev])
290 displayer.show(ctx)
329 log_strings = ui.popbuffer().split("\n")[:-1]
291 log_strings = ui.popbuffer().split("\n")[:-1]
330 if node in repo_parents:
292 char = ctx.node() in repo_parents and '@' or 'o'
331 node_ch = "@"
293 yield (ctx.rev(), parents, char, log_strings)
332 else:
333 node_ch = "o"
334 yield (node_ch, log_strings, node_index, edges, n_columns, n_columns_diff)
335
294
336 ascii(ui, grapher())
295 ascii(ui, grapher(graphabledag()))
337
296
338 cmdtable = {
297 cmdtable = {
339 "glog":
298 "glog":
General Comments 0
You need to be logged in to leave comments. Login now