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 file |
|
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 |
|
|
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 |
|
69 | if parent in seen: | |
109 |
parents |
|
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 |
|
|
271 | start, stop = get_revs(repo, opts["rev"]) | |
311 |
stop |
|
272 | stop = max(stop, start - limit + 1) | |
312 |
if start |
|
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 |
rev |
|
279 | revdag = filerevs(repo, path, start, stop) | |
318 | else: |
|
280 | else: | |
319 |
rev |
|
281 | revdag = revisions(repo, start, stop) | |
320 |
|
282 | |||
321 | repo_parents = repo.dirstate.parents() |
|
283 | repo_parents = repo.dirstate.parents() | |
322 |
|
|
284 | displayer = show_changeset(ui, repo, opts) | |
323 |
def graph |
|
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 |
|
|
290 | displayer.show(ctx) | |
329 | log_strings = ui.popbuffer().split("\n")[:-1] |
|
291 | log_strings = ui.popbuffer().split("\n")[:-1] | |
330 |
|
|
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