Show More
@@ -13,115 +13,76 b' from mercurial.commands import templateo' | |||
|
13 | 13 | from mercurial.i18n import _ |
|
14 | 14 | from mercurial.node import nullrev |
|
15 | 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. | |
|
55 | parents = get_rev_parents(repo, curr_rev) | |
|
56 | parents_to_add = [] | |
|
57 | for parent in parents: | |
|
58 | if parent not in next_revs: | |
|
59 | parents_to_add.append(parent) | |
|
60 | next_revs[rev_index:rev_index + 1] = util.sort(parents_to_add) | |
|
61 | ||
|
62 | edges = [] | |
|
63 | for parent in parents: | |
|
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 | |
|
17 | def revisions(repo, start, stop): | |
|
18 | """cset DAG generator yielding (rev, node, [parents]) tuples | |
|
19 | ||
|
20 | This generator function walks through the revision history from revision | |
|
21 | start to revision stop (which must be less than or equal to start). | |
|
22 | """ | |
|
23 | assert start >= stop | |
|
24 | cur = start | |
|
25 | while cur >= stop: | |
|
26 | ctx = repo[cur] | |
|
27 | parents = sorted(p.rev() for p in ctx.parents() if p.rev() != nullrev) | |
|
28 | yield (ctx, parents) | |
|
29 | cur -= 1 | |
|
71 | 30 | |
|
72 |
def file |
|
|
73 | """incremental file log grapher | |
|
74 | ||
|
75 | This generator function walks through the revision history of a | |
|
76 |
|
|
|
77 | be less than or equal to start_rev) and for each revision emits | |
|
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. | |
|
31 | def filerevs(repo, path, start, stop): | |
|
32 | """file cset DAG generator yielding (rev, node, [parents]) tuples | |
|
33 | ||
|
34 | This generator function walks through the revision history of a single | |
|
35 | file from revision start to revision stop (which must be less than or | |
|
36 | equal to start). | |
|
90 | 37 | """ |
|
91 | ||
|
92 | assert start_rev >= stop_rev | |
|
93 | revs = [] | |
|
38 | assert start >= stop | |
|
94 | 39 | filerev = len(repo.file(path)) - 1 |
|
95 | 40 | while filerev >= 0: |
|
96 | 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. | |
|
99 | if filerev not in revs: | |
|
100 | revs.append(filerev) | |
|
101 | rev_index = revs.index(filerev) | |
|
102 | next_revs = revs[:] | |
|
50 | def grapher(nodes): | |
|
51 | """grapher for asciigraph on a list of nodes and their parents | |
|
52 | ||
|
53 | nodes must generate tuples (node, parents, char, lines) where | |
|
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. | |
|
105 | parents = [f.filerev() for f in fctx.parents() if f.path() == path] | |
|
106 | parents_to_add = [] | |
|
66 | knownparents = [] | |
|
67 | newparents = [] | |
|
107 | 68 | for parent in parents: |
|
108 |
if parent |
|
|
109 |
parents |
|
|
110 | next_revs[rev_index:rev_index + 1] = util.sort(parents_to_add) | |
|
111 | ||
|
112 | edges = [] | |
|
113 | for parent in parents: | |
|
114 | edges.append((rev_index, next_revs.index(parent))) | |
|
69 | if parent in seen: | |
|
70 | knownparents.append(parent) | |
|
71 | else: | |
|
72 | newparents.append(parent) | |
|
115 | 73 | |
|
116 | changerev = fctx.linkrev() | |
|
117 | if changerev <= start_rev: | |
|
118 | node = repo.changelog.node(changerev) | |
|
119 | n_columns_diff = len(next_revs) - len(revs) | |
|
120 | yield (changerev, node, rev_index, edges, len(revs), n_columns_diff) | |
|
121 | if changerev <= stop_rev: | |
|
122 | break | |
|
123 | revs = next_revs | |
|
124 | filerev -= 1 | |
|
74 | ncols = len(seen) | |
|
75 | nextseen = seen[:] | |
|
76 | nextseen[nodeidx:nodeidx + 1] = newparents | |
|
77 | edges = [(nodeidx, nextseen.index(p)) for p in knownparents] | |
|
78 | ||
|
79 | if len(newparents) > 0: | |
|
80 | edges.append((nodeidx, nodeidx)) | |
|
81 | if len(newparents) > 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 | 87 | def fix_long_right_edges(edges): |
|
127 | 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 | 270 | limit = get_limit(opts["limit"]) |
|
310 |
|
|
|
311 |
stop |
|
|
312 |
if start |
|
|
271 | start, stop = get_revs(repo, opts["rev"]) | |
|
272 | stop = max(stop, start - limit + 1) | |
|
273 | if start == nullrev: | |
|
313 | 274 | return |
|
275 | ||
|
314 | 276 | if path: |
|
315 | 277 | path = canonpath(repo.root, os.getcwd(), path) |
|
316 | if path: | |
|
317 |
rev |
|
|
278 | if path: # could be reset in canonpath | |
|
279 | revdag = filerevs(repo, path, start, stop) | |
|
318 | 280 | else: |
|
319 |
rev |
|
|
281 | revdag = revisions(repo, start, stop) | |
|
320 | 282 | |
|
321 | 283 | repo_parents = repo.dirstate.parents() |
|
322 |
|
|
|
323 |
def graph |
|
|
324 | for (rev, node, node_index, edges, n_columns, n_columns_diff) in revgrapher: | |
|
284 | displayer = show_changeset(ui, repo, opts) | |
|
285 | def graphabledag(): | |
|
286 | for (ctx, parents) in revdag: | |
|
325 | 287 | # log_strings is the list of all log strings to draw alongside |
|
326 | 288 | # the graph. |
|
327 | 289 | ui.pushbuffer() |
|
328 |
|
|
|
290 | displayer.show(ctx) | |
|
329 | 291 | log_strings = ui.popbuffer().split("\n")[:-1] |
|
330 |
|
|
|
331 | node_ch = "@" | |
|
332 | else: | |
|
333 | node_ch = "o" | |
|
334 | yield (node_ch, log_strings, node_index, edges, n_columns, n_columns_diff) | |
|
292 | char = ctx.node() in repo_parents and '@' or 'o' | |
|
293 | yield (ctx.rev(), parents, char, log_strings) | |
|
335 | 294 | |
|
336 | ascii(ui, grapher()) | |
|
295 | ascii(ui, grapher(graphabledag())) | |
|
337 | 296 | |
|
338 | 297 | cmdtable = { |
|
339 | 298 | "glog": |
General Comments 0
You need to be logged in to leave comments.
Login now