##// END OF EJS Templates
rebase: do not add second parent to rebased changeset (drop detach option) (BC)...
rebase: do not add second parent to rebased changeset (drop detach option) (BC) Rebase now behaves as if --detach was always passed. Non-merges are rebased as non-merges, regardless of their parent being an ancestor of the destination. Merges will usually be rebased as merges unless both of their parents are ancestors of the destination, or one of their parents is pruned when rebased. This only alters the behavior of rebase when using the --source/--rev options. --detach option is deprecated. All test changes were carefully validated.

File last commit:

r16777:058e14da default
r17005:50f43451 default
Show More
graphlog.py
588 lines | 21.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
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319 from mercurial.cmdutil import show_changeset
Joel Rosdahl
Add graphlog extension
r4344 from mercurial.i18n import _
Joel Rosdahl
Remove unused imports
r6212 from mercurial.node import nullrev
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319 from mercurial import cmdutil, commands, extensions, scmutil
Patrick Mezard
graphlog: cleanup before code move...
r16412 from mercurial import hg, util, graphmod, templatekw, revset
Steve Borho
graphlog: add filelog revision grapher...
r5938
Adrian Buehlmann
graphlog: use cmdutil.command decorator
r14311 cmdtable = {}
command = cmdutil.command(cmdtable)
Augie Fackler
hgext: mark all first-party extensions as such
r16743 testedwith = 'internal'
Adrian Buehlmann
graphlog: use cmdutil.command decorator
r14311
Peter Arrenbrecht
graphmod/graphlog: make dag walks carry data as type, payload
r8840 ASCIIDATA = 'ASC'
Patrick Mezard
graphlog: display nodes with more than 2 predecessors...
r14130 def asciiedges(type, char, lines, 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)
Patrick Mezard
graphlog: display nodes with more than 2 predecessors...
r14130 nextseen = seen[:]
nextseen[nodeidx:nodeidx + 1] = newparents
edges = [(nodeidx, nextseen.index(p)) for p in knownparents]
while len(newparents) > 2:
# ascii() only knows how to add or remove a single column between two
# calls. Nodes with more than two parents break this constraint so we
# introduce intermediate expansion lines to grow the active node list
# slowly.
edges.append((nodeidx, nodeidx))
edges.append((nodeidx, nodeidx + 1))
nmorecols = 1
yield (type, char, lines, (nodeidx, edges, ncols, nmorecols))
char = '\\'
lines = []
nodeidx += 1
ncols += 1
edges = []
del newparents[0]
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))
Patrick Mezard
graphlog: display nodes with more than 2 predecessors...
r14130 nmorecols = len(nextseen) - ncols
seen[:] = nextseen
yield (type, char, lines, (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:
Matt Mackall
graphlog: attempt to fix index overrun (issue2912)...
r15032 if 2 * end >= len(nodeline):
continue
Joel Rosdahl
Add graphlog extension
r4344 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:
Matt Mackall
scmutil: move revsingle/pair/range from cmdutil...
r14319 revs = scmutil.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)
Patrick Mezard
graphlog: log -G --follow file does not work, forbid it...
r14086 def check_unsupported_flags(pats, opts):
Patrick Mezard
graphlog: implement --copies
r16180 for op in ["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
Patrick Mezard
graphlog: cleanup before code move...
r16412 def _makefilematcher(repo, pats, followfirst):
Patrick Mezard
graphlog: apply file filters --patch/--stat output...
r16186 # When displaying a revision with --patch --follow FILE, we have
# to know which file of the revision must be diffed. With
# --follow, we want the names of the ancestors of FILE in the
# revision, stored in "fcache". "fcache" is populated by
# reproducing the graph traversal already done by --follow revset
# and relating linkrevs to file names (which is not "correct" but
# good enough).
fcache = {}
fcacheready = [False]
pctx = repo['.']
wctx = repo[None]
def populate():
for fn in pats:
for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
for c in i:
fcache.setdefault(c.linkrev(), set()).add(c.path())
def filematcher(rev):
if not fcacheready[0]:
# Lazy initialization
fcacheready[0] = True
populate()
return scmutil.match(wctx, fcache.get(rev, []), default='path')
return filematcher
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 def _makelogrevset(repo, pats, opts, revs):
Patrick Mezard
graphlog: apply file filters --patch/--stat output...
r16186 """Return (expr, filematcher) where expr is a revset string built
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 from log options and file patterns or None. If --stat or --patch
are not passed filematcher is None. Otherwise it is a callable
taking a revision number and returning a match objects filtering
the files to be detailed when displaying the revision.
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 """
Patrick Mezard
graphlog: unify log -G revset translation
r14085 opt2revset = {
Patrick Mezard
graphlog: implement --follow-first...
r16174 'no_merges': ('not merge()', None),
'only_merges': ('merge()', None),
Patrick Mezard
graphlog: fix --follow --rev combinations...
r16408 '_ancestors': ('ancestors(%(val)s)', None),
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 '_fancestors': ('_firstancestors(%(val)s)', None),
Patrick Mezard
graphlog: fix --follow --rev combinations...
r16408 '_descendants': ('descendants(%(val)s)', None),
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 '_fdescendants': ('_firstdescendants(%(val)s)', None),
Patrick Mezard
graphlog: handle old-style --rev values...
r16316 '_matchfiles': ('_matchfiles(%(val)s)', None),
Patrick Mezard
graphlog: implement --follow-first...
r16174 'date': ('date(%(val)r)', None),
'branch': ('branch(%(val)r)', ' or '),
'_patslog': ('filelog(%(val)r)', ' or '),
'_patsfollow': ('follow(%(val)r)', ' or '),
'_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
'keyword': ('keyword(%(val)r)', ' or '),
'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
'user': ('user(%(val)r)', ' or '),
Patrick Mezard
graphlog: unify log -G revset translation
r14085 }
Patrick Mezard
graphlog: --branch and --only-branch are the same...
r16157
Patrick Mezard
graphlog: paths arguments must be or'ed
r16159 opts = dict(opts)
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 # follow or not follow?
Patrick Mezard
graphlog: implement --follow-first...
r16174 follow = opts.get('follow') or opts.get('follow_first')
Patrick Mezard
graphlog: reduce duplication in --follow code
r16433 followfirst = opts.get('follow_first') and 1 or 0
Patrick Mezard
graphlog: fix --follow --rev combinations...
r16408 # --follow with FILE behaviour depends on revs...
startrev = revs[0]
Patrick Mezard
graphlog: reduce duplication in --follow code
r16433 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405
# branch and only_branch are really aliases and must be handled at
# the same time
opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
Patrick Mezard
graphlog: support changeset identifiers in --branch
r16407 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
Patrick Mezard
graphlog: restore FILE glob expansion on Windows...
r16171 # pats/include/exclude are passed to match.match() directly in
# _matchfile() revset but walkchangerevs() builds its matcher with
# scmutil.match(). The difference is input pats are globbed on
# platforms without shell expansion (windows).
Patrick Mezard
graphlog: implement --follow with file arguments
r16173 pctx = repo[None]
match, pats = scmutil.matchandpats(pctx, pats, opts)
Patrick Mezard
graphlog: imitate log slowpath when inputs are explicit files
r16160 slowpath = match.anypats() or (match.files() and opts.get('removed'))
if not slowpath:
for f in match.files():
Patrick Mezard
graphlog: implement --follow with file arguments
r16173 if follow and f not in pctx:
raise util.Abort(_('cannot follow file not in parent '
'revision: "%s"') % f)
Patrick Mezard
graphlog: imitate log slowpath when inputs are explicit files
r16160 filelog = repo.file(f)
if not len(filelog):
# A zero count may be a directory or deleted file, so
# try to find matching entries on the slow path.
Patrick Mezard
graphlog: implement --follow with file arguments
r16173 if follow:
raise util.Abort(
_('cannot follow nonexistent file: "%s"') % f)
Patrick Mezard
graphlog: imitate log slowpath when inputs are explicit files
r16160 slowpath = True
if slowpath:
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 # See cmdutil.walkchangerevs() slow path.
#
Patrick Mezard
graphlog: implement --follow with file arguments
r16173 if follow:
raise util.Abort(_('can only follow copies/renames for explicit '
'filenames'))
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 # pats/include/exclude cannot be represented as separate
# revset expressions as their filtering logic applies at file
# level. For instance "-I a -X a" matches a revision touching
Patrick Mezard
graphlog: evaluate FILE/-I/-X filesets on the working dir...
r16181 # "a" and "b" while "file(a) and not file(b)" does
# not. Besides, filesets are evaluated against the working
# directory.
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 matchargs = ['r:', 'd:relpath']
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 for p in pats:
matchargs.append('p:' + p)
for p in opts.get('include', []):
matchargs.append('i:' + p)
for p in opts.get('exclude', []):
matchargs.append('x:' + p)
matchargs = ','.join(('%r' % p) for p in matchargs)
Patrick Mezard
graphlog: handle old-style --rev values...
r16316 opts['_matchfiles'] = matchargs
Patrick Mezard
graphlog: imitate log slowpath when inputs are explicit files
r16160 else:
Patrick Mezard
graphlog: implement --follow with file arguments
r16173 if follow:
Patrick Mezard
graphlog: reduce duplication in --follow code
r16433 fpats = ('_patsfollow', '_patsfollowfirst')
fnopats = (('_ancestors', '_fancestors'),
('_descendants', '_fdescendants'))
if pats:
Patrick Mezard
graphlog: fix --follow FILE and relative paths...
r16434 # follow() revset inteprets its file argument as a
# manifest entry, so use match.files(), not pats.
opts[fpats[followfirst]] = list(match.files())
Patrick Mezard
graphlog: implement --follow with file arguments
r16173 else:
Patrick Mezard
graphlog: reduce duplication in --follow code
r16433 opts[fnopats[followdescendants][followfirst]] = str(startrev)
Patrick Mezard
graphlog: implement --follow with file arguments
r16173 else:
opts['_patslog'] = list(pats)
Patrick Mezard
graphlog: --branch and --only-branch are the same...
r16157
Patrick Mezard
graphlog: apply file filters --patch/--stat output...
r16186 filematcher = None
if opts.get('patch') or opts.get('stat'):
if follow:
Patrick Mezard
graphlog: cleanup before code move...
r16412 filematcher = _makefilematcher(repo, pats, followfirst)
Patrick Mezard
graphlog: apply file filters --patch/--stat output...
r16186 else:
filematcher = lambda rev: match
Patrick Mezard
graphlog: cleanup before code move...
r16412 expr = []
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 for op, val in opts.iteritems():
if not val:
continue
Patrick Mezard
graphlog: unify log -G revset translation
r14085 if op not in opt2revset:
continue
Patrick Mezard
graphlog: explicitely join multivalue parameters...
r16147 revop, andor = opt2revset[op]
Patrick Mezard
graphlog: rewrite --rev like all other options
r16158 if '%(val)' not in revop:
Patrick Mezard
graphlog: cleanup before code move...
r16412 expr.append(revop)
Patrick Mezard
graphlog: unify log -G revset translation
r14085 else:
Patrick Mezard
graphlog: explicitely join multivalue parameters...
r16147 if not isinstance(val, list):
Patrick Mezard
graphlog: cleanup before code move...
r16412 e = revop % {'val': val}
Patrick Mezard
graphlog: explicitely join multivalue parameters...
r16147 else:
Patrick Mezard
graphlog: cleanup before code move...
r16412 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
expr.append(e)
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043
Patrick Mezard
graphlog: cleanup before code move...
r16412 if expr:
expr = '(' + ' and '.join(expr) + ')'
Patrick Mezard
graphlog: take the union of --rev specs instead of the intersection
r14132 else:
Patrick Mezard
graphlog: cleanup before code move...
r16412 expr = None
return expr, filematcher
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 def getlogrevs(repo, pats, opts):
Patrick Mezard
graphlog: turn getlogrevs() into a generator...
r16777 """Return (revs, expr, filematcher) where revs is an iterable of
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 revision numbers, expr is a revset string built from log options
and file patterns or None, and used to filter 'revs'. If --stat or
--patch are not passed filematcher is None. Otherwise it is a
callable taking a revision number and returning a match objects
filtering the files to be detailed when displaying the revision.
"""
Patrick Mezard
graphlog: turn getlogrevs() into a generator...
r16777 def increasingrevs(repo, revs, matcher):
# The sorted input rev sequence is chopped in sub-sequences
# which are sorted in ascending order and passed to the
# matcher. The filtered revs are sorted again as they were in
# the original sub-sequence. This achieve several things:
#
# - getlogrevs() now returns a generator which behaviour is
# adapted to log need. First results come fast, last ones
# are batched for performances.
#
# - revset matchers often operate faster on revision in
# changelog order, because most filters deal with the
# changelog.
#
# - revset matchers can reorder revisions. "A or B" typically
# returns returns the revision matching A then the revision
# matching B. We want to hide this internal implementation
# detail from the caller, and sorting the filtered revision
# again achieves this.
for i, window in cmdutil.increasingwindows(0, len(revs), windowsize=1):
orevs = revs[i:i + window]
nrevs = set(matcher(repo, sorted(orevs)))
for rev in orevs:
if rev in nrevs:
yield rev
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 if not len(repo):
Patrick Mezard
graphlog: turn getlogrevs() into a generator...
r16777 return iter([]), None, None
Patrick Mezard
graphlog: fix --follow --rev combinations...
r16408 # Default --rev value depends on --follow but --follow behaviour
# depends on revisions resolved from --rev...
follow = opts.get('follow') or opts.get('follow_first')
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 if opts.get('rev'):
revs = scmutil.revrange(repo, opts['rev'])
else:
Patrick Mezard
graphlog: fix --follow --rev combinations...
r16408 if follow and len(repo) > 0:
revs = scmutil.revrange(repo, ['.:0'])
else:
revs = range(len(repo) - 1, -1, -1)
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 if not revs:
Patrick Mezard
graphlog: turn getlogrevs() into a generator...
r16777 return iter([]), None, None
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 expr, filematcher = _makelogrevset(repo, pats, opts, revs)
if expr:
Patrick Mezard
graphlog: turn getlogrevs() into a generator...
r16777 matcher = revset.match(repo.ui, expr)
revs = increasingrevs(repo, revs, matcher)
Patrick Mezard
graphlog: implement --hidden
r16431 if not opts.get('hidden'):
# --hidden is still experimental and not worth a dedicated revset
# yet. Fortunately, filtering revision number is fast.
Patrick Mezard
graphlog: turn getlogrevs() into a generator...
r16777 revs = (r for r in revs if r not in repo.changelog.hiddenrevs)
else:
revs = iter(revs)
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 return revs, expr, filematcher
Patrick Mezard
graphlog: apply file filters --patch/--stat output...
r16186 def generate(ui, dag, displayer, showparents, edgefn, getrenamed=None,
filematcher=None):
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'
Patrick Mezard
graphlog: implement --copies
r16180 copies = None
if getrenamed and ctx.rev():
copies = []
for fn in ctx.files():
rename = getrenamed(fn, ctx.rev())
if rename:
copies.append((fn, rename[0]))
Patrick Mezard
graphlog: apply file filters --patch/--stat output...
r16186 revmatchfn = None
if filematcher is not None:
revmatchfn = filematcher(ctx.rev())
displayer.show(ctx, copies=copies, matchfn=revmatchfn)
Dirkjan Ochtman
graphlog: move common code into function again, change function types
r9369 lines = displayer.hunk.pop(rev).split('\n')[:-1]
Mads Kiilerich
graphlog: style with header and footer (issue2395)...
r12579 displayer.flush(rev)
Patrick Mezard
graphlog: display nodes with more than 2 predecessors...
r14130 edges = edgefn(type, char, lines, seen, rev, parents)
for type, char, lines, coldata in edges:
ascii(ui, state, type, char, lines, coldata)
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
Adrian Buehlmann
graphlog: use cmdutil.command decorator
r14311 @command('glog',
Patrick Mezard
graphlog: add all log options to glog command...
r16432 [('f', 'follow', None,
_('follow changeset history, or file history across copies and renames')),
('', 'follow-first', None,
_('only follow the first parent of merge changesets (DEPRECATED)')),
('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
('C', 'copies', None, _('show copied files')),
('k', 'keyword', [],
_('do case-insensitive search for a given text'), _('TEXT')),
Adrian Buehlmann
graphlog: use cmdutil.command decorator
r14311 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
Patrick Mezard
graphlog: add all log options to glog command...
r16432 ('', 'removed', None, _('include revisions where files were removed')),
('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
('u', 'user', [], _('revisions committed by user'), _('USER')),
('', 'only-branch', [],
_('show only changesets within the given named branch (DEPRECATED)'),
_('BRANCH')),
('b', 'branch', [],
_('show changesets within the given named branch'), _('BRANCH')),
('P', 'prune', [],
_('do not display revision or any of its ancestors'), _('REV')),
('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
] + commands.logopts + commands.walkopts,
_('[OPTION]... [FILE]'))
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 """
Patrick Mezard
graphlog: refactor revset() to return revisions...
r16405 revs, expr, filematcher = getlogrevs(repo, pats, opts)
Patrick Mezard
graphlog: handle old-style --rev values...
r16316 revs = sorted(revs, reverse=1)
Patrick Mezard
graphlog: always sort revisions topologically...
r14133 limit = cmdutil.loglimit(opts)
if limit is not None:
revs = revs[:limit]
Alexander Solovyov
graphlog: make use of graphmod's revset support
r14043 revdag = graphmod.dagwalker(repo, revs)
Peter Arrenbrecht
graphlog: split the actual DAG grapher out into a separate method...
r7325
Patrick Mezard
graphlog: implement --copies
r16180 getrenamed = None
if opts.get('copies'):
endrev = None
if opts.get('rev'):
endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
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()]
Patrick Mezard
graphlog: apply file filters --patch/--stat output...
r16186 generate(ui, revdag, displayer, showparents, asciiedges, getrenamed,
filematcher)
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
Patrick Mezard
graphlog: log -G --follow file does not work, forbid it...
r14086 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
Patrick Mezard
graphlog: log -G --follow file does not work, forbid it...
r14086 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.'''
Idan Kamara
graphlog: remove unused arg from _wrapcmd
r14416 _wrapcmd('log', commands.table, graphlog)
_wrapcmd('incoming', commands.table, gincoming)
_wrapcmd('outgoing', commands.table, goutgoing)
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426
Idan Kamara
graphlog: remove unused arg from _wrapcmd
r14416 def _wrapcmd(cmd, table, wrapfn):
Alpar Juttner
Graphlog extension adds a --graph option to log/in/out...
r7426 '''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")))