comparison hgext/graphlog.py @ 5938:9ed100559851

graphlog: add filelog revision grapher Graph a filelog's DAG, e.g.: hg glog mercurial/util.py
author Steve Borho <steve@borho.org>
date Fri, 25 Jan 2008 10:28:21 -0600
parents 8d4fac0a9df7
children 7b222815a462
comparison
equal deleted inserted replaced
5937:d8878742a924 5938:9ed100559851
3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net> 3 # Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
4 # 4 #
5 # This software may be used and distributed according to the terms of 5 # This software may be used and distributed according to the terms of
6 # the GNU General Public License, incorporated herein by reference. 6 # the GNU General Public License, incorporated herein by reference.
7 7
8 import os
8 import sys 9 import sys
9 from mercurial.cmdutil import revrange, show_changeset 10 from mercurial.cmdutil import revrange, show_changeset
10 from mercurial.i18n import _ 11 from mercurial.i18n import _
11 from mercurial.node import nullid, nullrev 12 from mercurial.node import nullid, nullrev
12 from mercurial.util import Abort 13 from mercurial.util import Abort, canonpath
13 14
14 def revision_grapher(repo, start_rev, stop_rev): 15 def revision_grapher(repo, start_rev, stop_rev):
15 """incremental revision grapher 16 """incremental revision grapher
16 17
17 This generator function walks through the revision history from 18 This generator function walks through the revision history from
60 n_columns_diff = len(next_revs) - len(revs) 61 n_columns_diff = len(next_revs) - len(revs)
61 yield (curr_rev, node, rev_index, edges, len(revs), n_columns_diff) 62 yield (curr_rev, node, rev_index, edges, len(revs), n_columns_diff)
62 63
63 revs = next_revs 64 revs = next_revs
64 curr_rev -= 1 65 curr_rev -= 1
66
67 def filelog_grapher(repo, path, start_rev, stop_rev):
68 """incremental file log grapher
69
70 This generator function walks through the revision history of a
71 single file from revision start_rev to revision stop_rev (which must
72 be less than or equal to start_rev) and for each revision emits
73 tuples with the following elements:
74
75 - Current revision.
76 - Current node.
77 - Column of the current node in the set of ongoing edges.
78 - Edges; a list of (col, next_col) indicating the edges between
79 the current node and its parents.
80 - Number of columns (ongoing edges) in the current revision.
81 - The difference between the number of columns (ongoing edges)
82 in the next revision and the number of columns (ongoing edges)
83 in the current revision. That is: -1 means one column removed;
84 0 means no columns added or removed; 1 means one column added.
85 """
86
87 assert start_rev >= stop_rev
88 curr_rev = start_rev
89 revs = []
90 filerev = repo.file(path).count() - 1
91 while filerev >= 0:
92 fctx = repo.filectx(path, fileid=filerev)
93
94 # Compute revs and next_revs.
95 if filerev not in revs:
96 revs.append(filerev)
97 rev_index = revs.index(filerev)
98 next_revs = revs[:]
99
100 # Add parents to next_revs.
101 parents = [f.filerev() for f in fctx.parents()]
102 parents_to_add = []
103 for parent in parents:
104 if parent not in next_revs:
105 parents_to_add.append(parent)
106 parents_to_add.sort()
107 next_revs[rev_index:rev_index + 1] = parents_to_add
108
109 edges = []
110 for parent in parents:
111 edges.append((rev_index, next_revs.index(parent)))
112
113 changerev = fctx.linkrev()
114 if changerev <= start_rev:
115 node = repo.changelog.node(changerev)
116 n_columns_diff = len(next_revs) - len(revs)
117 yield (changerev, node, rev_index, edges, len(revs), n_columns_diff)
118 if changerev <= stop_rev:
119 break
120 revs = next_revs
121 filerev -= 1
65 122
66 def get_rev_parents(repo, rev): 123 def get_rev_parents(repo, rev):
67 return [x for x in repo.changelog.parentrevs(rev) if x != nullrev] 124 return [x for x in repo.changelog.parentrevs(rev) if x != nullrev]
68 125
69 def fix_long_right_edges(edges): 126 def fix_long_right_edges(edges):
139 revs = revrange(repo, rev_opt) 196 revs = revrange(repo, rev_opt)
140 return (max(revs), min(revs)) 197 return (max(revs), min(revs))
141 else: 198 else:
142 return (repo.changelog.count() - 1, 0) 199 return (repo.changelog.count() - 1, 0)
143 200
144 def graphlog(ui, repo, **opts): 201 def graphlog(ui, repo, path=None, **opts):
145 """show revision history alongside an ASCII revision graph 202 """show revision history alongside an ASCII revision graph
146 203
147 Print a revision history alongside a revision graph drawn with 204 Print a revision history alongside a revision graph drawn with
148 ASCII characters. 205 ASCII characters.
149 206
155 (start_rev, stop_rev) = get_revs(repo, opts["rev"]) 212 (start_rev, stop_rev) = get_revs(repo, opts["rev"])
156 stop_rev = max(stop_rev, start_rev - limit + 1) 213 stop_rev = max(stop_rev, start_rev - limit + 1)
157 if start_rev == nullrev: 214 if start_rev == nullrev:
158 return 215 return
159 cs_printer = show_changeset(ui, repo, opts) 216 cs_printer = show_changeset(ui, repo, opts)
160 grapher = revision_grapher(repo, start_rev, stop_rev) 217 if path:
218 cpath = canonpath(repo.root, os.getcwd(), path)
219 grapher = filelog_grapher(repo, cpath, start_rev, stop_rev)
220 else:
221 grapher = revision_grapher(repo, start_rev, stop_rev)
161 repo_parents = repo.dirstate.parents() 222 repo_parents = repo.dirstate.parents()
162 prev_n_columns_diff = 0 223 prev_n_columns_diff = 0
163 prev_node_index = 0 224 prev_node_index = 0
164 225
165 for (rev, node, node_index, edges, n_columns, n_columns_diff) in grapher: 226 for (rev, node, node_index, edges, n_columns, n_columns_diff) in grapher:
259 [('l', 'limit', '', _('limit number of changes displayed')), 320 [('l', 'limit', '', _('limit number of changes displayed')),
260 ('p', 'patch', False, _('show patch')), 321 ('p', 'patch', False, _('show patch')),
261 ('r', 'rev', [], _('show the specified revision or range')), 322 ('r', 'rev', [], _('show the specified revision or range')),
262 ('', 'style', '', _('display using template map file')), 323 ('', 'style', '', _('display using template map file')),
263 ('', 'template', '', _('display with template'))], 324 ('', 'template', '', _('display with template'))],
264 _('hg glog [OPTION]...')), 325 _('hg glog [OPTION] [FILE]...')),
265 } 326 }