##// END OF EJS Templates
revset: add missing whitespace
revset: add missing whitespace

File last commit:

r14043:1c1e1232 default
r14072:2e4d79dc default
Show More
graphlog.py
359 lines | 11.7 KiB | text/x-python | PythonLexer
Joel Rosdahl
Add graphlog extension
r4344 # ASCII graph log extension for Mercurial
#
# Copyright 2007 Joel Rosdahl <joel@rosdahl.net>
Thomas Arendsen Hein
Removed trailing whitespace and tabs from python files
r4516 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Martin Geisler
add blank line after copyright notices and after header
r8228
Dirkjan Ochtman
extensions: change descriptions for extensions providing a few commands
r8934 '''command to view revision graphs from a shell
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
This extension adds a --graph option to the incoming, outgoing and log
Martin Geisler
graphlog: wrap docstrings at 70 characters
r9259 commands. When this options is given, an ASCII representation of the
revision graph is also shown.
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 '''
Joel Rosdahl
Add graphlog extension
r4344
from mercurial.cmdutil import revrange, show_changeset
Peter Arrenbrecht
cleanup: drop unused imports
r7873 from mercurial.commands import templateopts
Joel Rosdahl
Add graphlog extension
r4344 from mercurial.i18n import _
Joel Rosdahl
Remove unused imports
r6212 from mercurial.node import nullrev
Nicolas Dumazet
incoming: unify code for incoming and graphlog.incoming
r12730 from mercurial import cmdutil, commands, extensions
Adrian Buehlmann
move canonpath from util to scmutil
r13971 from mercurial import hg, scmutil, util, graphmod
Steve Borho
graphlog: add filelog revision grapher...
r5938
Peter Arrenbrecht
graphmod/graphlog: make dag walks carry data as type, payload
r8840 ASCIIDATA = 'ASC'
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369 def asciiedges(seen, rev, parents):
Peter Arrenbrecht
graphmod/graphlog: make dag walks carry data as type, payload
r8840 """adds edge info to changelog DAG walk suitable for ascii()"""
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369 if rev not in seen:
seen.append(rev)
nodeidx = seen.index(rev)
Steve Borho
graphlog: add filelog revision grapher...
r5938
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369 knownparents = []
newparents = []
for parent in parents:
if parent in seen:
knownparents.append(parent)
else:
newparents.append(parent)
Steve Borho
graphlog: add filelog revision grapher...
r5938
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369 ncols = len(seen)
seen[nodeidx:nodeidx + 1] = newparents
edges = [(nodeidx, seen.index(p)) for p in knownparents]
Peter Arrenbrecht
graphlog: refactor common grapher code...
r7370
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369 if len(newparents) > 0:
edges.append((nodeidx, nodeidx))
if len(newparents) > 1:
edges.append((nodeidx, nodeidx + 1))
nmorecols = len(seen) - ncols
return nodeidx, edges, ncols, nmorecols
Steve Borho
graphlog: add filelog revision grapher...
r5938
Joel Rosdahl
Add graphlog extension
r4344 def fix_long_right_edges(edges):
for (i, (start, end)) in enumerate(edges):
if end > start:
edges[i] = (start, end + 1)
Dirkjan Ochtman
graphlog: move functions around, eliminate helper function...
r7326 def get_nodeline_edges_tail(
node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail):
if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0:
# Still going in the same non-vertical direction.
if n_columns_diff == -1:
start = max(node_index + 1, p_node_index)
tail = ["|", " "] * (start - node_index - 1)
tail.extend(["/", " "] * (n_columns - start))
return tail
else:
return ["\\", " "] * (n_columns - node_index - 1)
else:
return ["|", " "] * (n_columns - node_index - 1)
Joel Rosdahl
Add graphlog extension
r4344 def draw_edges(edges, nodeline, interline):
for (start, end) in edges:
if start == end + 1:
interline[2 * end + 1] = "/"
elif start == end - 1:
interline[2 * start + 1] = "\\"
elif start == end:
interline[2 * start] = "|"
else:
nodeline[2 * end] = "+"
if start > end:
Martin Geisler
coding style: use a space after comma...
r9198 (start, end) = (end, start)
Joel Rosdahl
Add graphlog extension
r4344 for i in range(2 * start + 1, 2 * end):
if nodeline[i] != "+":
nodeline[i] = "-"
def get_padding_line(ni, n_columns, edges):
line = []
line.extend(["|", " "] * ni)
if (ni, ni - 1) in edges or (ni, ni) in edges:
# (ni, ni - 1) (ni, ni)
# | | | | | | | |
# +---o | | o---+
# | | c | | c | |
# | |/ / | |/ /
# | | | | | |
c = "|"
else:
c = " "
line.extend([c, " "])
line.extend(["|", " "] * (n_columns - ni - 1))
return line
Peter Arrenbrecht
graphlog: hide internal state of ascii() from users
r9631 def asciistate():
"""returns the initial value for the "state" argument to ascii()"""
return [0, 0]
def ascii(ui, state, type, char, text, coldata):
Peter Arrenbrecht
graphlog: rename grapher to asciiedges
r8839 """prints an ASCII graph of the DAG
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 takes the following arguments (one call per node in the graph):
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 - ui to write to
Peter Arrenbrecht
graphlog: hide internal state of ascii() from users
r9631 - Somewhere to keep the needed state in (init to asciistate())
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325 - Column of the current node in the set of ongoing edges.
Peter Arrenbrecht
graphmod/graphlog: make dag walks carry data as type, payload
r8840 - Type indicator of node data == ASCIIDATA.
- Payload: (char, lines):
- Character to use as node's symbol.
- List of lines to display as the node's text.
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325 - Edges; a list of (col, next_col) indicating the edges between
the current node and its parents.
- Number of columns (ongoing edges) in the current revision.
- The difference between the number of columns (ongoing edges)
in the next revision and the number of columns (ongoing edges)
in the current revision. That is: -1 means one column removed;
0 means no columns added or removed; 1 means one column added.
"""
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 idx, edges, ncols, coldiff = coldata
assert -2 < coldiff < 2
if coldiff == -1:
# Transform
Joel Rosdahl
Add graphlog extension
r4344 #
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # | | | | | |
# o | | into o---+
# |X / |/ /
# | | | |
fix_long_right_edges(edges)
# add_padding_line says whether to rewrite
#
# | | | | | | | |
# | o---+ into | o---+
# | / / | | | # <--- padding line
# o | | | / /
# o | |
add_padding_line = (len(text) > 2 and coldiff == -1 and
[x for (x, y) in edges if x + 1 < y])
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # fix_nodeline_tail says whether to rewrite
#
# | | o | | | | o | |
# | | |/ / | | |/ /
# | o | | into | o / / # <--- fixed nodeline tail
# | |/ / | |/ /
# o | | o | |
fix_nodeline_tail = len(text) <= 2 and not add_padding_line
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # nodeline is the line containing the node character (typically o)
nodeline = ["|", " "] * idx
nodeline.extend([char, " "])
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 nodeline.extend(
Peter Arrenbrecht
graphlog: hide internal state of ascii() from users
r9631 get_nodeline_edges_tail(idx, state[1], ncols, coldiff,
state[0], fix_nodeline_tail))
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # shift_interline is the line containing the non-vertical
# edges between this entry and the next
shift_interline = ["|", " "] * idx
if coldiff == -1:
n_spaces = 1
edge_ch = "/"
elif coldiff == 0:
n_spaces = 2
edge_ch = "|"
else:
n_spaces = 3
edge_ch = "\\"
shift_interline.extend(n_spaces * [" "])
shift_interline.extend([edge_ch, " "] * (ncols - idx - 1))
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # draw edges from the current node to its parents
draw_edges(edges, nodeline, shift_interline)
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # lines is the list of all graph lines to print
lines = [nodeline]
if add_padding_line:
lines.append(get_padding_line(idx, ncols, edges))
lines.append(shift_interline)
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # make sure that there are as many graph lines as there are
# log strings
while len(text) < len(lines):
text.append("")
if len(lines) < len(text):
extra_interline = ["|", " "] * (ncols + coldiff)
while len(lines) < len(text):
lines.append(extra_interline)
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # print lines
indentation_level = max(ncols, ncols + coldiff)
for (line, logstr) in zip(lines, text):
ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr)
ui.write(ln.rstrip() + '\n')
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 # ... and start over
Peter Arrenbrecht
graphlog: hide internal state of ascii() from users
r9631 state[0] = coldiff
state[1] = idx
Joel Rosdahl
Add graphlog extension
r4344
Dirkjan Ochtman
graphlog: move functions around, eliminate helper function...
r7326 def get_revs(repo, rev_opt):
if rev_opt:
revs = revrange(repo, rev_opt)
Eric Eisner
glog: fix crash on empty revision range
r11448 if len(revs) == 0:
return (nullrev, nullrev)
Dirkjan Ochtman
graphlog: move functions around, eliminate helper function...
r7326 return (max(revs), min(revs))
else:
return (len(repo) - 1, 0)
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 def check_unsupported_flags(opts):
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 for op in ["follow_first", "copies", "newest_first"]:
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 if op in opts and opts[op]:
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 raise util.Abort(_("-G/--graph option is incompatible with --%s")
Greg Ward
glog: fix "incompatible option" error message....
r10097 % op.replace("_", "-"))
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 def revset(pats, opts):
"""Return revset str built of revisions, log options and file patterns.
"""
opt2revset = dict(only_merges='merge',
only_branch='branch',
no_merges='not merge',
include='file',
exclude='not file',
prune='not follow')
revset = []
for op, val in opts.iteritems():
if not val:
continue
revop = opt2revset.get(op, op)
if op in ('follow', 'only_merges', 'no_merges'):
revset.append('%s()' % revop)
elif op in ("date", "keyword", "remove", "user", "branch",
"only_branch", "prune"):
revset.append('%s(%s)' % (op, val))
elif op in ('include', 'exclude'):
for f in val:
revset.append('%s(%r)' % (op, f))
elif op == 'rev':
revset.extend(val)
for path in pats:
revset.append('file(%r)' % path)
revset = ' and '.join(revset) or 'all()'
# we want reverted revset to build graph
revset = 'reverse(%s)' % revset
if opts['limit']:
revset = 'limit(%s, %s)' % (revset, opts['limit'])
return revset
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 def generate(ui, dag, displayer, showparents, edgefn):
Peter Arrenbrecht
graphlog: hide internal state of ascii() from users
r9631 seen, state = [], asciistate()
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369 for rev, type, ctx, parents in dag:
char = ctx.node() in showparents and '@' or 'o'
displayer.show(ctx)
lines = displayer.hunk.pop(rev).split('\n')[:-1]
Mads Kiilerich
graphlog: style with header and footer (issue2395)...
r12579 displayer.flush(rev)
Peter Arrenbrecht
graphlog: hide internal state of ascii() from users
r9631 ascii(ui, state, type, char, lines, edgefn(seen, rev, parents))
Mads Kiilerich
graphlog: style with header and footer (issue2395)...
r12579 displayer.close()
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 def graphlog(ui, repo, *pats, **opts):
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325 """show revision history alongside an ASCII revision graph
Martin Geisler
graphlog: wrap docstrings at 70 characters
r9259 Print a revision history alongside a revision graph drawn with
ASCII characters.
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325
Martin Geisler
graphlog: wrap docstrings at 70 characters
r9259 Nodes printed as an @ character are parents of the working
directory.
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325 """
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 check_unsupported_flags(opts)
Peter Arrenbrecht
graphlog: refactor common grapher code...
r7370
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 revs = revrange(repo, [revset(pats, opts)])
revdag = graphmod.dagwalker(repo, revs)
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325
Dirkjan Ochtman
graphlog: extract some setup code out of common functions
r9368 displayer = show_changeset(ui, repo, opts, buffered=True)
showparents = [ctx.node() for ctx in repo[None].parents()]
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 generate(ui, revdag, displayer, showparents, asciiedges)
Dirkjan Ochtman
graphlog: extract large parts of repeated code from incoming/outgoing
r7716
def graphrevs(repo, nodes, opts):
limit = cmdutil.loglimit(opts)
Peter Arrenbrecht
graphmod/graphlog: extract nodelistwalk
r8837 nodes.reverse()
Nicolas Dumazet
cmdutil: replace sys.maxint with None as default value in loglimit...
r10111 if limit is not None:
Peter Arrenbrecht
graphmod/graphlog: extract nodelistwalk
r8837 nodes = nodes[:limit]
return graphmod.nodes(repo, nodes)
Dirkjan Ochtman
graphlog: extract large parts of repeated code from incoming/outgoing
r7716
def goutgoing(ui, repo, dest=None, **opts):
"""show the outgoing changesets alongside an ASCII revision graph
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325
Dirkjan Ochtman
graphlog: extract large parts of repeated code from incoming/outgoing
r7716 Print the outgoing changesets alongside a revision graph drawn with
ASCII characters.
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
Dirkjan Ochtman
graphlog: extract large parts of repeated code from incoming/outgoing
r7716 Nodes printed as an @ character are parents of the working
directory.
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 """
Dirkjan Ochtman
graphlog: extract large parts of repeated code from incoming/outgoing
r7716
check_unsupported_flags(opts)
Nicolas Dumazet
outgoing: unify common graphlog.outgoing and hg.outgoing code
r12735 o = hg._outgoing(ui, repo, dest, opts)
if o is None:
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 return
Dirkjan Ochtman
graphlog: extract large parts of repeated code from incoming/outgoing
r7716
revdag = graphrevs(repo, o, opts)
Dirkjan Ochtman
graphlog: extract some setup code out of common functions
r9368 displayer = show_changeset(ui, repo, opts, buffered=True)
showparents = [ctx.node() for ctx in repo[None].parents()]
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 generate(ui, revdag, displayer, showparents, asciiedges)
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
def gincoming(ui, repo, source="default", **opts):
"""show the incoming changesets alongside an ASCII revision graph
Martin Geisler
graphlog: wrap docstrings at 70 characters
r9259 Print the incoming changesets alongside a revision graph drawn with
ASCII characters.
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
Martin Geisler
graphlog: wrap docstrings at 70 characters
r9259 Nodes printed as an @ character are parents of the working
directory.
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 """
Nicolas Dumazet
incoming: unify code for incoming and graphlog.incoming
r12730 def subreporecurse():
return 1
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
check_unsupported_flags(opts)
Nicolas Dumazet
incoming: unify code for incoming and graphlog.incoming
r12730 def display(other, chlist, displayer):
Dirkjan Ochtman
graphlog: extract large parts of repeated code from incoming/outgoing
r7716 revdag = graphrevs(other, chlist, opts)
Dirkjan Ochtman
graphlog: extract some setup code out of common functions
r9368 showparents = [ctx.node() for ctx in repo[None].parents()]
Dirkjan Ochtman
graphlog: simplify ascii drawing to process one cset at a time
r9371 generate(ui, revdag, displayer, showparents, asciiedges)
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
Nicolas Dumazet
incoming: unify code for incoming and graphlog.incoming
r12730 hg._incoming(display, subreporecurse, ui, repo, source, opts, buffered=True)
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
def uisetup(ui):
'''Initialize the extension.'''
_wrapcmd(ui, 'log', commands.table, graphlog)
_wrapcmd(ui, 'incoming', commands.table, gincoming)
_wrapcmd(ui, 'outgoing', commands.table, goutgoing)
def _wrapcmd(ui, cmd, table, wrapfn):
'''wrap the command'''
def graph(orig, *args, **kwargs):
if kwargs['graph']:
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 return wrapfn(*args, **kwargs)
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 return orig(*args, **kwargs)
entry = extensions.wrapcommand(table, cmd, graph)
Jim Correia
log-like commands now use -G for --graph, -g for --git
r7763 entry[1].append(('G', 'graph', None, _("show the revision DAG")))
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
Joel Rosdahl
Add graphlog extension
r4344 cmdtable = {
"glog":
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 (graphlog,
FUJIWARA Katsunori
help: show value requirement and multiple occurrence of options...
r11321 [('l', 'limit', '',
_('limit number of changes displayed'), _('NUM')),
Thomas Arendsen Hein
Updated command tables in commands.py and hgext extensions....
r4730 ('p', 'patch', False, _('show patch')),
FUJIWARA Katsunori
help: show value requirement and multiple occurrence of options...
r11321 ('r', 'rev', [],
_('show the specified revision or range'), _('REV')),
Thomas Arendsen Hein
Introduce templateopts and logopts to reduce duplicate option definitions.
r6192 ] + templateopts,
Thomas Arendsen Hein
glog shows at most one file: correct synopsis
r5942 _('hg glog [OPTION]... [FILE]')),
Joel Rosdahl
Add graphlog extension
r4344 }