##// 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
16
18 def get_rev_parents(repo, rev):
17 def revisions(repo, start, stop):
19 return [x for x in repo.changelog.parentrevs(rev) if x != nullrev]
18 """cset DAG generator yielding (rev, node, [parents]) tuples
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
19
54 # Add parents to next_revs.
20 This generator function walks through the revision history from revision
55 parents = get_rev_parents(repo, curr_rev)
21 start to revision stop (which must be less than or equal to start).
56 parents_to_add = []
22 """
57 for parent in parents:
23 assert start >= stop
58 if parent not in next_revs:
24 cur = start
59 parents_to_add.append(parent)
25 while cur >= stop:
60 next_revs[rev_index:rev_index + 1] = util.sort(parents_to_add)
26 ctx = repo[cur]
61
27 parents = sorted(p.rev() for p in ctx.parents() if p.rev() != nullrev)
62 edges = []
28 yield (ctx, parents)
63 for parent in parents:
29 cur -= 1
64 edges.append((rev_index, next_revs.index(parent)))
65
66 n_columns_diff = len(next_revs) - len(revs)
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
75 This generator function walks through the revision history of a
76 single file from revision start_rev to revision stop_rev (which must
77 be less than or equal to start_rev) and for each revision emits
78 tuples with the following elements:
79
33
80 - Current revision.
34 This generator function walks through the revision history of a single
81 - Current node.
35 file from revision start to revision stop (which must be less than or
82 - Column of the current node in the set of ongoing edges.
36 equal to start).
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[:]
103
54
104 # Add parents to next_revs.
55 - parents must generate the parents of node, in sorted order,
105 parents = [f.filerev() for f in fctx.parents() if f.path() == path]
56 and max length 2,
106 parents_to_add = []
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)
65
66 knownparents = []
67 newparents = []
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