##// END OF EJS Templates
walk: simplify logic for badfn clause...
walk: simplify logic for badfn clause - matchfn redundant - call badfn always rather than fwarn - use for/else rather than keep var

File last commit:

r8614:573734e7 default
r8677:34df078b default
Show More
cmdutil.py
1272 lines | 44.2 KiB | text/x-python | PythonLexer
Vadim Gelfer
fix comment.
r2957 # cmdutil.py - help for command processing in mercurial
Vadim Gelfer
refactor text diff/patch code....
r2874 #
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
Vadim Gelfer
refactor text diff/patch code....
r2874 #
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
# GNU General Public License version 2, incorporated herein by reference.
Vadim Gelfer
refactor text diff/patch code....
r2874
Joel Rosdahl
Expand import * to allow Pyflakes to find problems
r6211 from node import hex, nullid, nullrev, short
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Matt Mackall
cmdutils: Take over glob expansion duties from util
r8614 import os, sys, bisect, stat, errno, re, glob
Peter Arrenbrecht
drop unused imports
r8390 import mdiff, bdiff, util, templater, patch, error, encoding
Matt Mackall
walk: pass match object to cmdutil.walk...
r6579 import match as _match
Vadim Gelfer
refactor text diff/patch code....
r2874
Brendan Cully
Move revision parsing into cmdutil.
r3090 revrangesep = ':'
Matt Mackall
findcmd: have dispatch look up strict flag
r7213 def findpossible(cmd, table, strict=False):
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 """
Return cmd -> (aliases, command table entry)
for each matching command.
Return debug commands (or their aliases) only if no normal command matches.
"""
choice = {}
debugchoice = {}
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 for e in table.keys():
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 aliases = e.lstrip("^").split("|")
found = None
if cmd in aliases:
found = cmd
Matt Mackall
findcmd: have dispatch look up strict flag
r7213 elif not strict:
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 for a in aliases:
if a.startswith(cmd):
found = a
break
if found is not None:
if aliases[0].startswith("debug") or found.startswith("debug"):
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 debugchoice[found] = (aliases, table[e])
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 else:
Matt Mackall
dispatch: move command dispatching into its own module...
r5178 choice[found] = (aliases, table[e])
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
if not choice and debugchoice:
choice = debugchoice
return choice
Matt Mackall
findcmd: have dispatch look up strict flag
r7213 def findcmd(cmd, table, strict=True):
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 """Return (aliases, command table entry) for command string."""
Matt Mackall
findcmd: have dispatch look up strict flag
r7213 choice = findpossible(cmd, table, strict)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if cmd in choice:
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 return choice[cmd]
if len(choice) > 1:
clist = choice.keys()
clist.sort()
Matt Mackall
error: move UnknownCommand and AmbiguousCommand
r7643 raise error.AmbiguousCommand(cmd, clist)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
if choice:
return choice.values()[0]
Matt Mackall
error: move UnknownCommand and AmbiguousCommand
r7643 raise error.UnknownCommand(cmd)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
def bail_if_changed(repo):
Matt Mackall
cmdutil: make bail_if_changed bail on uncommitted merge
r5716 if repo.dirstate.parents()[1] != nullid:
raise util.Abort(_('outstanding uncommitted merge'))
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 modified, added, removed, deleted = repo.status()[:4]
if modified or added or removed or deleted:
raise util.Abort(_("outstanding uncommitted changes"))
def logmessage(opts):
""" get the log message according to -m and -l option """
Alexander Solovyov
cmdutil.logmessage: options should be optional
r7667 message = opts.get('message')
logfile = opts.get('logfile')
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
if message and logfile:
raise util.Abort(_('options --message and --logfile are mutually '
'exclusive'))
if not message and logfile:
try:
if logfile == '-':
message = sys.stdin.read()
else:
message = open(logfile).read()
except IOError, inst:
raise util.Abort(_("can't read commit message '%s': %s") %
(logfile, inst.strerror))
return message
Thomas Arendsen Hein
Move finding/checking the log limit to cmdutil
r6190 def loglimit(opts):
"""get the log limit according to option -l/--limit"""
limit = opts.get('limit')
if limit:
try:
limit = int(limit)
except ValueError:
raise util.Abort(_('limit must be a positive integer'))
if limit <= 0: raise util.Abort(_('limit must be positive'))
else:
limit = sys.maxint
return limit
Matt Mackall
add cmdutil.remoteui...
r8188 def remoteui(src, opts):
'build a remote ui from ui or repo and opts'
Matt Mackall
ui: replace parentui mechanism with repo.baseui
r8189 if hasattr(src, 'baseui'): # looks like a repository
dst = src.baseui # drop repo-specific config
Matt Mackall
add cmdutil.remoteui...
r8188 src = src.ui # copy target options from repo
Matt Mackall
ui: replace parentui mechanism with repo.baseui
r8189 else: # assume it's a global ui object
Matt Mackall
add cmdutil.remoteui...
r8188 dst = src # keep all global options
# copy ssh-specific options
for o in 'ssh', 'remotecmd':
v = opts.get(o) or src.config('ui', o)
if v:
dst.setconfig("ui", o, v)
# copy bundle-specific options
r = src.config('bundle', 'mainreporoot')
if r:
dst.setconfig('bundle', 'mainreporoot', r)
return dst
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
Thomas Arendsen Hein
Removed unused ui parameter from revpair/revrange and fix its users.
r3707 def revpair(repo, revs):
Brendan Cully
Move revision parsing into cmdutil.
r3090 '''return pair of nodes, given list of revisions. second item can
be None, meaning use working dir.'''
Matt Mackall
simplify revrange and revpair
r3525
def revfix(repo, val, defval):
Alexis S. L. Carvalho
fix hg diff -r ''
r3825 if not val and val != 0 and defval is not None:
Matt Mackall
simplify revrange and revpair
r3525 val = defval
return repo.lookup(val)
Brendan Cully
Move revision parsing into cmdutil.
r3090 if not revs:
return repo.dirstate.parents()[0], None
end = None
if len(revs) == 1:
Matt Mackall
simplify revrange and revpair
r3525 if revrangesep in revs[0]:
start, end = revs[0].split(revrangesep, 1)
Brendan Cully
Move revision parsing into cmdutil.
r3090 start = revfix(repo, start, 0)
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 end = revfix(repo, end, len(repo) - 1)
Brendan Cully
Move revision parsing into cmdutil.
r3090 else:
Matt Mackall
simplify revrange and revpair
r3525 start = revfix(repo, revs[0], None)
Brendan Cully
Move revision parsing into cmdutil.
r3090 elif len(revs) == 2:
if revrangesep in revs[0] or revrangesep in revs[1]:
raise util.Abort(_('too many revisions specified'))
start = revfix(repo, revs[0], None)
end = revfix(repo, revs[1], None)
else:
raise util.Abort(_('too many revisions specified'))
Matt Mackall
simplify revrange and revpair
r3525 return start, end
Brendan Cully
Move revision parsing into cmdutil.
r3090
Thomas Arendsen Hein
Removed unused ui parameter from revpair/revrange and fix its users.
r3707 def revrange(repo, revs):
Brendan Cully
Move revision parsing into cmdutil.
r3090 """Yield revision as strings from a list of revision specifications."""
Matt Mackall
simplify revrange and revpair
r3525
def revfix(repo, val, defval):
Alexis S. L. Carvalho
fix hg log -r ''
r3718 if not val and val != 0 and defval is not None:
Matt Mackall
simplify revrange and revpair
r3525 return defval
return repo.changelog.rev(repo.lookup(val))
Martin Geisler
cmdutil: replace pseudo-set by real set
r8368 seen, l = set(), []
Brendan Cully
Move revision parsing into cmdutil.
r3090 for spec in revs:
if revrangesep in spec:
start, end = spec.split(revrangesep, 1)
start = revfix(repo, start, 0)
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 end = revfix(repo, end, len(repo) - 1)
Brendan Cully
Move revision parsing into cmdutil.
r3090 step = start > end and -1 or 1
for rev in xrange(start, end+step, step):
if rev in seen:
continue
Martin Geisler
cmdutil: replace pseudo-set by real set
r8368 seen.add(rev)
Matt Mackall
Make revrange return a list of ints so that callers don't have to convert
r3526 l.append(rev)
Brendan Cully
Move revision parsing into cmdutil.
r3090 else:
rev = revfix(repo, spec, None)
if rev in seen:
continue
Martin Geisler
cmdutil: replace pseudo-set by real set
r8368 seen.add(rev)
Matt Mackall
Make revrange return a list of ints so that callers don't have to convert
r3526 l.append(rev)
return l
Brendan Cully
Move revision parsing into cmdutil.
r3090
Vadim Gelfer
refactor text diff/patch code....
r2874 def make_filename(repo, pat, node,
total=None, seqno=None, revwidth=None, pathname=None):
node_expander = {
'H': lambda: hex(node),
'R': lambda: str(repo.changelog.rev(node)),
'h': lambda: short(node),
}
expander = {
'%': lambda: '%',
'b': lambda: os.path.basename(repo.root),
}
try:
if node:
expander.update(node_expander)
Alexis S. L. Carvalho
archive: make the %r escape work.
r4836 if node:
Vadim Gelfer
refactor text diff/patch code....
r2874 expander['r'] = (lambda:
Alexis S. L. Carvalho
archive: make the %r escape work.
r4836 str(repo.changelog.rev(node)).zfill(revwidth or 0))
Vadim Gelfer
refactor text diff/patch code....
r2874 if total is not None:
expander['N'] = lambda: str(total)
if seqno is not None:
expander['n'] = lambda: str(seqno)
if total is not None and seqno is not None:
Thomas Arendsen Hein
white space and line break cleanups
r3673 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
Vadim Gelfer
refactor text diff/patch code....
r2874 if pathname is not None:
expander['s'] = lambda: os.path.basename(pathname)
expander['d'] = lambda: os.path.dirname(pathname) or '.'
expander['p'] = lambda: pathname
newname = []
patlen = len(pat)
i = 0
while i < patlen:
c = pat[i]
if c == '%':
i += 1
c = pat[i]
c = expander[c]()
newname.append(c)
i += 1
return ''.join(newname)
except KeyError, inst:
Thomas Arendsen Hein
Never apply string formatting to generated errors with util.Abort....
r3072 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
inst.args[0])
Vadim Gelfer
refactor text diff/patch code....
r2874
def make_file(repo, pat, node=None,
total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
Ronny Pfannschmidt
export: fixed silent output file overwriting...
r7319
writable = 'w' in mode or 'a' in mode
Vadim Gelfer
refactor text diff/patch code....
r2874 if not pat or pat == '-':
Ronny Pfannschmidt
export: fixed silent output file overwriting...
r7319 return writable and sys.stdout or sys.stdin
if hasattr(pat, 'write') and writable:
Vadim Gelfer
refactor text diff/patch code....
r2874 return pat
if hasattr(pat, 'read') and 'r' in mode:
return pat
return open(make_filename(repo, pat, node, total, seqno, revwidth,
pathname),
mode)
Vadim Gelfer
move walk and matchpats from commands to cmdutil.
r2882
Matt Mackall
cmdutils: Take over glob expansion duties from util
r8614 def expandpats(pats):
if not util.expandglobs:
return list(pats)
ret = []
for p in pats:
kind, name = _match._patsplit(p, None)
if kind is None:
globbed = glob.glob(name)
if globbed:
ret.extend(globbed)
continue
ret.append(p)
return ret
Matt Mackall
walk: pass match object to cmdutil.walk...
r6579 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
Matt Mackall
walk: kill util.cmdmatcher and _matcher
r6575 if not globbed and default == 'relpath':
Matt Mackall
cmdutils: Take over glob expansion duties from util
r8614 pats = expandpats(pats or [])
Matt Mackall
walk: pass match object to cmdutil.walk...
r6579 m = _match.match(repo.root, repo.getcwd(), pats,
opts.get('include'), opts.get('exclude'), default)
Matt Mackall
walk: begin refactoring badmatch handling
r6578 def badfn(f, msg):
repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
return False
m.bad = badfn
Matt Mackall
walk: pass match object to cmdutil.walk...
r6579 return m
Vadim Gelfer
move walk and matchpats from commands to cmdutil.
r2882
Matt Mackall
match: use helpers for cmdutil
r6597 def matchall(repo):
return _match.always(repo.root, repo.getcwd())
def matchfiles(repo, files):
return _match.exact(repo.root, repo.getcwd(), files)
Vadim Gelfer
move commands.addremove_lock to cmdutil.addremove
r2883
Benoit Boissinot
addremove/findrenames: find renames according to the match object (issue1527)...
r8489 def findrenames(repo, match=None, threshold=0.5):
Erling Ellingsen
Avoid some false positives for addremove -s...
r4135 '''find renamed files -- yields (before, after, score) tuples'''
Benoit Boissinot
addremove/findrenames: find renames according to the match object (issue1527)...
r8489 added, removed = repo.status(match=match)[1:3]
Matt Mackall
use repo[changeid] to get a changectx
r6747 ctx = repo['.']
Vadim Gelfer
addremove: add -s/--similarity option...
r2958 for a in added:
aa = repo.wread(a)
Erling Ellingsen
Avoid some false positives for addremove -s...
r4135 bestname, bestscore = None, threshold
Vadim Gelfer
addremove: add -s/--similarity option...
r2958 for r in removed:
Benoit Boissinot
cmdutil.py: use contexts in findrenames
r3971 rr = ctx.filectx(r).data()
Erling Ellingsen
Avoid some false positives for addremove -s...
r4135
# bdiff.blocks() returns blocks of matching lines
# count the number of bytes in each
equal = 0
alines = mdiff.splitnewlines(aa)
matches = bdiff.blocks(aa, rr)
for x1,x2,y1,y2 in matches:
for line in alines[x1:x2]:
equal += len(line)
Thomas Arendsen Hein
addremove: comparing two empty files caused ZeroDivisionError...
r4472 lengths = len(aa) + len(rr)
if lengths:
myscore = equal*2.0 / lengths
if myscore >= bestscore:
bestname, bestscore = r, myscore
Erling Ellingsen
Avoid some false positives for addremove -s...
r4135 if bestname:
Vadim Gelfer
addremove: add -s/--similarity option...
r2958 yield bestname, a, bestscore
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
Vadim Gelfer
move commands.addremove_lock to cmdutil.addremove
r2883 if dry_run is None:
dry_run = opts.get('dry_run')
Vadim Gelfer
addremove: add -s/--similarity option...
r2958 if similarity is None:
similarity = float(opts.get('similarity') or 0)
Vadim Gelfer
move commands.addremove_lock to cmdutil.addremove
r2883 add, remove = [], []
Maxim Dounin
addremove: correctly handle intermediate symlinks...
r6651 audit_path = util.path_auditor(repo.root)
Matt Mackall
walk: pass match object to cmdutil.walk...
r6579 m = match(repo, pats, opts)
Matt Mackall
walk: return a single value
r6586 for abs in repo.walk(m):
Alexis S. L. Carvalho
Use absolute paths in addremove....
r4522 target = repo.wjoin(abs)
Maxim Dounin
addremove: correctly handle intermediate symlinks...
r6651 good = True
try:
audit_path(abs)
except:
good = False
Matt Mackall
walk: remove rel and exact returns
r6584 rel = m.rel(abs)
exact = m.exact(abs)
Patrick Mezard
Merge with crew-stable
r6656 if good and abs not in repo.dirstate:
Vadim Gelfer
move commands.addremove_lock to cmdutil.addremove
r2883 add.append(abs)
if repo.ui.verbose or not exact:
repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
Maxim Dounin
addremove: correctly handle intermediate symlinks...
r6651 if repo.dirstate[abs] != 'r' and (not good or not util.lexists(target)
Maxim Dounin
Fix file-changed-to-dir and dir-to-file commits (issue660)....
r5487 or (os.path.isdir(target) and not os.path.islink(target))):
Vadim Gelfer
move commands.addremove_lock to cmdutil.addremove
r2883 remove.append(abs)
if repo.ui.verbose or not exact:
repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
if not dry_run:
Maxim Dounin
Fix file-changed-to-dir and dir-to-file commits (issue660)....
r5487 repo.remove(remove)
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 repo.add(add)
Vadim Gelfer
addremove: add -s/--similarity option...
r2958 if similarity > 0:
Benoit Boissinot
addremove/findrenames: find renames according to the match object (issue1527)...
r8489 for old, new, score in findrenames(repo, m, similarity):
Benoit Boissinot
addremove: mapping isn't really needed, simplify
r8488 oldexact, newexact = m.exact(old), m.exact(new)
Vadim Gelfer
addremove: add -s/--similarity option...
r2958 if repo.ui.verbose or not oldexact or not newexact:
Benoit Boissinot
addremove: mapping isn't really needed, simplify
r8488 oldrel, newrel = m.rel(old), m.rel(new)
Vadim Gelfer
addremove: add -s/--similarity option...
r2958 repo.ui.status(_('recording removal of %s as rename to %s '
'(%d%% similar)\n') %
(oldrel, newrel, score * 100))
if not dry_run:
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 repo.copy(old, new)
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Matt Mackall
copy: handle rename internally...
r5610 def copy(ui, repo, pats, opts, rename=False):
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 # called with the repo lock held
#
# hgsep => pathname that uses "/" to separate directories
# ossep => pathname that uses os.sep to separate directories
cwd = repo.getcwd()
targets = {}
Matt Mackall
copy: minor cleanups...
r5607 after = opts.get("after")
dryrun = opts.get("dry_run")
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 def walkpat(pat):
srcs = []
Matt Mackall
walk: pass match object to cmdutil.walk...
r6579 m = match(repo, [pat], opts, globbed=True)
Matt Mackall
walk: return a single value
r6586 for abs in repo.walk(m):
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 state = repo.dirstate[abs]
Matt Mackall
walk: remove rel and exact returns
r6584 rel = m.rel(abs)
exact = m.exact(abs)
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 if state in '?r':
if exact and state == '?':
ui.warn(_('%s: not copying - file is not managed\n') % rel)
if exact and state == 'r':
ui.warn(_('%s: not copying - file has been marked for'
' remove\n') % rel)
continue
# abs: hgsep
# rel: ossep
srcs.append((abs, rel, exact))
return srcs
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
# abssrc: hgsep
# relsrc: ossep
# otarget: ossep
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 def copyfile(abssrc, relsrc, otarget, exact):
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 abstarget = util.canonpath(repo.root, cwd, otarget)
reltarget = repo.pathto(abstarget, cwd)
Matt Mackall
copy: minor cleanups...
r5607 target = repo.wjoin(abstarget)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 src = repo.wjoin(abssrc)
Matt Mackall
copy: simplify inner copy...
r5608 state = repo.dirstate[abstarget]
Matt Mackall
copy: minor cleanups...
r5607
# check for collisions
prevsrc = targets.get(abstarget)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if prevsrc is not None:
ui.warn(_('%s: not overwriting - %s collides with %s\n') %
(reltarget, repo.pathto(abssrc, cwd),
repo.pathto(prevsrc, cwd)))
return
Matt Mackall
copy: minor cleanups...
r5607
# check for overwrites
Matt Mackall
copy: simplify inner copy...
r5608 exists = os.path.exists(target)
Martin Geisler
remove unnecessary outer parenthesis in if-statements
r8117 if not after and exists or after and state in 'mn':
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if not opts['force']:
ui.warn(_('%s: not overwriting - file exists\n') %
reltarget)
return
Matt Mackall
copy: minor cleanups...
r5607
if after:
Matt Mackall
copy: simplify inner copy...
r5608 if not exists:
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 return
Matt Mackall
copy: simplify inner copy...
r5608 elif not dryrun:
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 try:
Matt Mackall
copy: simplify inner copy...
r5608 if exists:
os.unlink(target)
targetdir = os.path.dirname(target) or '.'
if not os.path.isdir(targetdir):
os.makedirs(targetdir)
util.copyfile(src, target)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 except IOError, inst:
if inst.errno == errno.ENOENT:
ui.warn(_('%s: deleted in working copy\n') % relsrc)
else:
ui.warn(_('%s: cannot copy - %s\n') %
(relsrc, inst.strerror))
Matt Mackall
copy: propagate errors properly
r5606 return True # report a failure
Matt Mackall
copy: minor cleanups...
r5607
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if ui.verbose or not exact:
Martin Geisler
cmdutil: fix untranslatable string in copy
r7894 if rename:
ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
else:
ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
Matt Mackall
copy: simplify inner copy...
r5608
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 targets[abstarget] = abssrc
Matt Mackall
copy: minor cleanups...
r5607
# fix up dirstate
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 origsrc = repo.dirstate.copied(abssrc) or abssrc
Matt Mackall
copy: fix copying back with -A (issue836)
r5604 if abstarget == origsrc: # copying back a copy?
Matt Mackall
copy: simplify inner copy...
r5608 if state not in 'mn' and not dryrun:
repo.dirstate.normallookup(abstarget)
Matt Mackall
copy: fix copying back with -A (issue836)
r5604 else:
Matt Mackall
rename: handle renaming to a target marked removed
r7121 if repo.dirstate[origsrc] == 'a' and origsrc == abssrc:
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if not ui.quiet:
ui.warn(_("%s has not been committed yet, so no copy "
"data will be stored for %s.\n")
% (repo.pathto(origsrc, cwd), reltarget))
Matt Mackall
rename: handle renaming to a target marked removed
r7121 if repo.dirstate[abstarget] in '?r' and not dryrun:
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 repo.add([abstarget])
Matt Mackall
copy: minor cleanups...
r5607 elif not dryrun:
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 repo.copy(origsrc, abstarget)
Matt Mackall
copy: handle rename internally...
r5610
if rename and not dryrun:
Alexis S. L. Carvalho
rename --after: do not unlink source file (issue910)...
r6566 repo.remove([abssrc], not after)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
# pat: ossep
# dest ossep
# srcs: list of (hgsep, hgsep, ossep, bool)
# return: function that takes hgsep and returns ossep
def targetpathfn(pat, dest, srcs):
if os.path.isdir(pat):
abspfx = util.canonpath(repo.root, cwd, pat)
abspfx = util.localpath(abspfx)
if destdirexists:
striplen = len(os.path.split(abspfx)[0])
else:
striplen = len(abspfx)
if striplen:
striplen += len(os.sep)
res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
elif destdirexists:
res = lambda p: os.path.join(dest,
os.path.basename(util.localpath(p)))
else:
res = lambda p: dest
return res
# pat: ossep
# dest ossep
# srcs: list of (hgsep, hgsep, ossep, bool)
# return: function that takes hgsep and returns ossep
def targetpathafterfn(pat, dest, srcs):
Matt Mackall
match: refactor patkind...
r8568 if _match.patkind(pat):
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 # a mercurial pattern
res = lambda p: os.path.join(dest,
os.path.basename(util.localpath(p)))
else:
abspfx = util.canonpath(repo.root, cwd, pat)
if len(abspfx) < len(srcs[0][0]):
# A directory. Either the target path contains the last
# component of the source path or it does not.
def evalpath(striplen):
score = 0
for s in srcs:
t = os.path.join(dest, util.localpath(s[0])[striplen:])
if os.path.exists(t):
score += 1
return score
abspfx = util.localpath(abspfx)
striplen = len(abspfx)
if striplen:
striplen += len(os.sep)
if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
score = evalpath(striplen)
striplen1 = len(os.path.split(abspfx)[0])
if striplen1:
striplen1 += len(os.sep)
if evalpath(striplen1) > score:
striplen = striplen1
res = lambda p: os.path.join(dest,
util.localpath(p)[striplen:])
else:
# a file
if destdirexists:
res = lambda p: os.path.join(dest,
os.path.basename(util.localpath(p)))
else:
res = lambda p: dest
return res
Matt Mackall
cmdutils: Take over glob expansion duties from util
r8614 pats = expandpats(pats)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if not pats:
raise util.Abort(_('no source or destination specified'))
if len(pats) == 1:
raise util.Abort(_('no destination specified'))
dest = pats.pop()
Alexis S. L. Carvalho
Fix issue995 (copy --after and symlinks pointing to a directory)...
r6258 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if not destdirexists:
Matt Mackall
match: refactor patkind...
r8568 if len(pats) > 1 or _match.patkind(pats[0]):
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 raise util.Abort(_('with multiple sources, destination must be an '
'existing directory'))
Shun-ichi GOTO
Add endswithsep() and use it instead of using os.sep and os.altsep directly....
r5843 if util.endswithsep(dest):
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 raise util.Abort(_('destination %s is not a directory') % dest)
Matt Mackall
copy: minor cleanups...
r5607
tfn = targetpathfn
if after:
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 tfn = targetpathafterfn
copylist = []
for pat in pats:
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 srcs = walkpat(pat)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if not srcs:
continue
copylist.append((tfn(pat, dest, srcs), srcs))
if not copylist:
raise util.Abort(_('no files to copy'))
Matt Mackall
copy: propagate errors properly
r5606 errors = 0
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 for targetpath, srcs in copylist:
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 for abssrc, relsrc, exact in srcs:
Matt Mackall
copy: propagate errors properly
r5606 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
errors += 1
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
if errors:
ui.warn(_('(consider using --after)\n'))
Matt Mackall
copy: move rename logic
r5609
Matt Mackall
copy: handle rename internally...
r5610 return errors
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380 def service(opts, parentfn=None, initfn=None, runfn=None):
'''Run a command as a service.'''
if opts['daemon'] and not opts['daemon_pipefds']:
rfd, wfd = os.pipe()
args = sys.argv[:]
args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
Bryan O'Sullivan
serve: Don't change directory in the child if invoked with -d and --cwd
r5797 # Don't pass --cwd to the child process, because we've already
# changed directory.
for i in xrange(1,len(args)):
if args[i].startswith('--cwd='):
del args[i]
break
elif args[i].startswith('--cwd'):
del args[i:i+2]
break
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
args[0], args)
os.close(wfd)
os.read(rfd, 1)
if parentfn:
return parentfn(pid)
else:
os._exit(0)
if initfn:
initfn()
if opts['pid_file']:
fp = open(opts['pid_file'], 'w')
fp.write(str(os.getpid()) + '\n')
fp.close()
if opts['daemon_pipefds']:
rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
os.close(rfd)
try:
os.setsid()
except AttributeError:
pass
os.write(wfd, 'y')
os.close(wfd)
sys.stdout.flush()
sys.stderr.flush()
fd = os.open(util.nulldev, os.O_RDWR)
if fd != 0: os.dup2(fd, 0)
if fd != 1: os.dup2(fd, 1)
if fd != 2: os.dup2(fd, 2)
if fd not in (0, 1, 2): os.close(fd)
if runfn:
return runfn()
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 class changeset_printer(object):
'''show changeset information when templating not requested.'''
Jim Correia
add --git option to commands supporting --patch (log, incoming, history, tip)...
r7762 def __init__(self, ui, repo, patch, diffopts, buffered):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui = ui
self.repo = repo
Matt Mackall
Refactor log ui buffering and patch display
r3645 self.buffered = buffered
self.patch = patch
Jim Correia
add --git option to commands supporting --patch (log, incoming, history, tip)...
r7762 self.diffopts = diffopts
Matt Mackall
use ui buffering in changeset printer...
r3738 self.header = {}
self.hunk = {}
self.lastheader = None
Matt Mackall
Refactor log ui buffering and patch display
r3645
def flush(self, rev):
Matt Mackall
use ui buffering in changeset printer...
r3738 if rev in self.header:
h = self.header[rev]
if h != self.lastheader:
self.lastheader = h
self.ui.write(h)
del self.header[rev]
if rev in self.hunk:
self.ui.write(self.hunk[rev])
del self.hunk[rev]
return 1
return 0
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 def show(self, ctx, copies=(), **props):
Matt Mackall
use ui buffering in changeset printer...
r3738 if self.buffered:
self.ui.pushbuffer()
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 self._show(ctx, copies, props)
self.hunk[ctx.rev()] = self.ui.popbuffer()
Matt Mackall
use ui buffering in changeset printer...
r3738 else:
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 self._show(ctx, copies, props)
Matt Mackall
use ui buffering in changeset printer...
r3738
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 def _show(self, ctx, copies, props):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 '''show a single changeset or file revision'''
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 changenode = ctx.node()
rev = ctx.rev()
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
if self.ui.quiet:
self.ui.write("%d:%s\n" % (rev, short(changenode)))
return
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 log = self.repo.changelog
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 changes = log.read(changenode)
date = util.datestr(changes[2])
extra = changes[5]
branch = extra.get("branch")
hexfunc = self.ui.debugflag and hex or short
Thomas Arendsen Hein
hg log: Move filtering implicit parents to own method and use it in templater....
r4825 parents = [(p, hexfunc(log.node(p)))
for p in self._meaningful_parentrevs(log, rev)]
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
Alexis S. L. Carvalho
"default" is the default branch name
r4176 # don't show the default branch name
if branch != 'default':
Matt Mackall
move encoding bits from util to encoding...
r7948 branch = encoding.tolocal(branch)
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui.write(_("branch: %s\n") % branch)
for tag in self.repo.nodetags(changenode):
self.ui.write(_("tag: %s\n") % tag)
for parent in parents:
self.ui.write(_("parent: %d:%s\n") % parent)
if self.ui.debugflag:
self.ui.write(_("manifest: %d:%s\n") %
(self.repo.manifest.rev(changes[0]), hex(changes[0])))
self.ui.write(_("user: %s\n") % changes[1])
self.ui.write(_("date: %s\n") % date)
if self.ui.debugflag:
files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
for key, value in zip([_("files:"), _("files+:"), _("files-:")],
files):
if value:
self.ui.write("%-12s %s\n" % (key, " ".join(value)))
elif changes[3] and self.ui.verbose:
self.ui.write(_("files: %s\n") % " ".join(changes[3]))
if copies and self.ui.verbose:
copies = ['%s (%s)' % c for c in copies]
self.ui.write(_("copies: %s\n") % ' '.join(copies))
if extra and self.ui.debugflag:
Matt Mackall
replace util.sort with sorted built-in...
r8209 for key, value in sorted(extra.items()):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui.write(_("extra: %s=%s\n")
% (key, value.encode('string_escape')))
description = changes[4].strip()
if description:
if self.ui.verbose:
self.ui.write(_("description:\n"))
self.ui.write(description)
self.ui.write("\n\n")
else:
self.ui.write(_("summary: %s\n") %
description.splitlines()[0])
self.ui.write("\n")
Matt Mackall
Refactor log ui buffering and patch display
r3645 self.showpatch(changenode)
def showpatch(self, node):
if self.patch:
prev = self.repo.changelog.parents(node)[0]
Dirkjan Ochtman
patch: turn patch.diff() into a generator...
r7308 chunks = patch.diff(self.repo, prev, node, match=self.patch,
Jim Correia
add --git option to commands supporting --patch (log, incoming, history, tip)...
r7762 opts=patch.diffopts(self.ui, self.diffopts))
Dirkjan Ochtman
patch: turn patch.diff() into a generator...
r7308 for chunk in chunks:
self.ui.write(chunk)
Matt Mackall
Refactor log ui buffering and patch display
r3645 self.ui.write("\n")
Thomas Arendsen Hein
hg log: Move filtering implicit parents to own method and use it in templater....
r4825 def _meaningful_parentrevs(self, log, rev):
"""Return list of meaningful (or all if debug) parentrevs for rev.
For merges (two non-nullrev revisions) both parents are meaningful.
Otherwise the first parent revision is considered meaningful if it
is not the preceding revision.
"""
parents = log.parentrevs(rev)
if not self.ui.debugflag and parents[1] == nullrev:
if parents[0] >= rev - 1:
parents = []
else:
parents = [parents[0]]
return parents
Matt Mackall
Refactor log ui buffering and patch display
r3645 class changeset_templater(changeset_printer):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 '''format changeset information.'''
Jim Correia
add --git option to commands supporting --patch (log, incoming, history, tip)...
r7762 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
Dirkjan Ochtman
templater: provide the standard template filters by default
r8360 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
self.t = templater.templater(mapfile, {'formatnode': formatnode},
Alexis S. L. Carvalho
command line templates: add formatnode filter...
r4352 cache={
'parent': '{rev}:{node|formatnode} ',
'manifest': '{rev}:{node|formatnode}',
'filecopy': '{name} ({source})'})
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
def use_template(self, t):
'''set template string to use'''
self.t.cache['changeset'] = t
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 def _meaningful_parentrevs(self, ctx):
"""Return list of meaningful (or all if debug) parentrevs for rev.
"""
parents = ctx.parents()
if len(parents) > 1:
return parents
if self.ui.debugflag:
return [parents[0], self.repo['null']]
if parents[0].rev() >= ctx.rev() - 1:
return []
return parents
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 def _show(self, ctx, copies, props):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 '''show a single changeset or file revision'''
def showlist(name, values, plural=None, **args):
'''expand set of values.
name is name of key in template map.
values is list of strings or dicts.
plural is plural of name, if not simply name + 's'.
expansion works like this, given name 'foo'.
if values is empty, expand 'no_foos'.
if 'foo' not in template map, return values as a string,
joined by space.
expand 'start_foos'.
for each value, expand 'foo'. if 'last_foo' in template
map, expand it instead of 'foo' for last key.
expand 'end_foos'.
'''
if plural: names = plural
else: names = name + 's'
if not values:
noname = 'no_' + names
if noname in self.t:
yield self.t(noname, **args)
return
if name not in self.t:
if isinstance(values[0], str):
yield ' '.join(values)
else:
for v in values:
yield dict(v, **args)
return
startname = 'start_' + names
if startname in self.t:
yield self.t(startname, **args)
vargs = args.copy()
def one(v, tag=name):
try:
vargs.update(v)
except (AttributeError, ValueError):
try:
for a, b in v:
vargs[a] = b
except ValueError:
vargs[name] = v
return self.t(tag, **vargs)
lastname = 'last_' + name
if lastname in self.t:
last = values.pop()
else:
last = None
for v in values:
yield one(v)
if last is not None:
yield one(last, tag=lastname)
endname = 'end_' + names
if endname in self.t:
yield self.t(endname, **args)
def showbranches(**args):
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 branch = ctx.branch()
Alexis S. L. Carvalho
"default" is the default branch name
r4176 if branch != 'default':
Matt Mackall
move encoding bits from util to encoding...
r7948 branch = encoding.tolocal(branch)
Matt Mackall
changeset templater: convert some unnecessary yields to returns
r3648 return showlist('branch', [branch], plural='branches', **args)
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
def showparents(**args):
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 parents = [[('rev', p.rev()), ('node', p.hex())]
for p in self._meaningful_parentrevs(ctx)]
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 return showlist('parent', parents, **args)
def showtags(**args):
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 return showlist('tag', ctx.tags(), **args)
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
def showextras(**args):
Matt Mackall
replace util.sort with sorted built-in...
r8209 for key, value in sorted(ctx.extra().items()):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 args = args.copy()
args.update(dict(key=key, value=value))
yield self.t('extra', **args)
def showcopies(**args):
c = [{'name': x[0], 'source': x[1]} for x in copies]
return showlist('file_copy', c, plural='file_copies', **args)
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Patrick Mezard
cmdutil: always expose "files_add", "files_del" and "manifest" templater properties
r5545 files = []
def getfiles():
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760 if not files:
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 files[:] = self.repo.status(ctx.parents()[0].node(),
ctx.node())[:3]
Patrick Mezard
cmdutil: always expose "files_add", "files_del" and "manifest" templater properties
r5545 return files
Patrick Mezard
cmdutil: make "files" list all files, add "file_mods" for modified files
r5550 def showfiles(**args):
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 return showlist('file', ctx.files(), **args)
Patrick Mezard
cmdutil: make "files" list all files, add "file_mods" for modified files
r5550 def showmods(**args):
return showlist('file_mod', getfiles()[0], **args)
Patrick Mezard
cmdutil: always expose "files_add", "files_del" and "manifest" templater properties
r5545 def showadds(**args):
return showlist('file_add', getfiles()[1], **args)
def showdels(**args):
return showlist('file_del', getfiles()[2], **args)
def showmanifest(**args):
args = args.copy()
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 args.update(dict(rev=self.repo.manifest.rev(ctx.changeset()[0]),
node=hex(ctx.changeset()[0])))
Patrick Mezard
cmdutil: always expose "files_add", "files_del" and "manifest" templater properties
r5545 return self.t('manifest', **args)
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Alexander Solovyov <piranha at piranha.org.ua>
templater: ability to display diffstat for log-like commands
r7879 def showdiffstat(**args):
diff = patch.diff(self.repo, ctx.parents()[0].node(), ctx.node())
files, adds, removes = 0, 0, 0
for i in patch.diffstatdata(util.iterlines(diff)):
files += 1
adds += i[1]
removes += i[2]
return '%s: +%s/-%s' % (files, adds, removes)
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 defprops = {
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 'author': ctx.user(),
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 'branches': showbranches,
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 'date': ctx.date(),
'desc': ctx.description().strip(),
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 'file_adds': showadds,
'file_dels': showdels,
Patrick Mezard
cmdutil: make "files" list all files, add "file_mods" for modified files
r5550 'file_mods': showmods,
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 'files': showfiles,
'file_copies': showcopies,
'manifest': showmanifest,
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 'node': ctx.hex(),
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 'parents': showparents,
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 'rev': ctx.rev(),
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 'tags': showtags,
'extras': showextras,
Alexander Solovyov <piranha at piranha.org.ua>
templater: ability to display diffstat for log-like commands
r7879 'diffstat': showdiffstat,
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 }
props = props.copy()
props.update(defprops)
Dirkjan Ochtman
cmdutil: prevent code repetition by abstraction in changeset_templater
r8013 # find correct templates for current mode
tmplmodes = [
(True, None),
(self.ui.verbose, 'verbose'),
(self.ui.quiet, 'quiet'),
(self.ui.debugflag, 'debug'),
]
types = {'header': '', 'changeset': 'changeset'}
for mode, postfix in tmplmodes:
for type in types:
cur = postfix and ('%s_%s' % (type, postfix)) or type
if mode and cur in self.t:
types[type] = cur
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 try:
Dirkjan Ochtman
cmdutil: prevent code repetition by abstraction in changeset_templater
r8013
# write header
if types['header']:
h = templater.stringify(self.t(types['header'], **props))
Matt Mackall
Refactor log ui buffering and patch display
r3645 if self.buffered:
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 self.header[ctx.rev()] = h
Matt Mackall
Refactor log ui buffering and patch display
r3645 else:
self.ui.write(h)
Dirkjan Ochtman
cmdutil: prevent code repetition by abstraction in changeset_templater
r8013
# write changeset metadata, then patch if requested
key = types['changeset']
Matt Mackall
Refactor log ui buffering and patch display
r3645 self.ui.write(templater.stringify(self.t(key, **props)))
Alexander Solovyov
templater: use contexts consistently throughout changeset_templater
r7878 self.showpatch(ctx.node())
Dirkjan Ochtman
cmdutil: prevent code repetition by abstraction in changeset_templater
r8013
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 except KeyError, inst:
Dirkjan Ochtman
cmdutil: prevent code repetition by abstraction in changeset_templater
r8013 msg = _("%s: no key named '%s'")
raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 except SyntaxError, inst:
raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
Matt Mackall
Fix log regression where log -p file showed diffs for other files
r3837 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 """show one changeset using template or regular display.
Display format will be the first non-empty hit of:
1. option 'template'
2. option 'style'
3. [ui] setting 'logtemplate'
4. [ui] setting 'style'
If all of these values are either the unset or the empty string,
regular display via changeset_printer() is done.
"""
# options
Matt Mackall
Fix log regression where log -p file showed diffs for other files
r3837 patch = False
if opts.get('patch'):
Matt Mackall
match: use helpers for cmdutil
r6597 patch = matchfn or matchall(repo)
Matt Mackall
Fix log regression where log -p file showed diffs for other files
r3837
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 tmpl = opts.get('template')
Dirkjan Ochtman
cmdutil: refactor handling of templating in show_changeset()
r7967 style = None
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 if tmpl:
tmpl = templater.parsestring(tmpl, quoted=False)
else:
Dirkjan Ochtman
cmdutil: refactor handling of templating in show_changeset()
r7967 style = opts.get('style')
# ui settings
if not (tmpl or style):
tmpl = ui.config('ui', 'logtemplate')
if tmpl:
tmpl = templater.parsestring(tmpl)
else:
style = ui.config('ui', 'style')
if not (tmpl or style):
return changeset_printer(ui, repo, patch, opts, buffered)
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Dirkjan Ochtman
cmdutil: refactor handling of templating in show_changeset()
r7967 mapfile = None
if style and not tmpl:
mapfile = style
if not os.path.split(mapfile)[0]:
mapname = (templater.templatepath('map-cmdline.' + mapfile)
or templater.templatepath(mapfile))
if mapname: mapfile = mapname
try:
t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
except SyntaxError, inst:
raise util.Abort(inst.args[0])
if tmpl: t.use_template(tmpl)
return t
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Matt Mackall
Add --date support to update and revert...
r3814 def finddate(ui, repo, date):
"""Find the tipmost changeset that matches the given date spec"""
mark.williamson@cl.cam.ac.uk
Tweak finddate to pass date directly....
r5836 df = util.matchdate(date)
Matt Mackall
use repo[changeid] to get a changectx
r6747 get = util.cachefunc(lambda r: repo[r].changeset())
Matt Mackall
Add --date support to update and revert...
r3814 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
results = {}
for st, rev, fns in changeiter:
if st == 'add':
d = get(rev)[2]
if df(d[0]):
results[rev] = d
elif st == 'iter':
if rev in results:
Martin Geisler
i18n: mark strings for translation in Mercurial
r6953 ui.status(_("Found revision %s from %s\n") %
Matt Mackall
Add --date support to update and revert...
r3814 (rev, util.datestr(results[rev])))
return str(rev)
raise util.Abort(_("revision matching date not found"))
Matt Mackall
move walkchangerevs to cmdutils
r3650 def walkchangerevs(ui, repo, pats, change, opts):
timeless
help: miscellaneous language fixes
r7807 '''Iterate over files and the revs in which they changed.
Matt Mackall
move walkchangerevs to cmdutils
r3650
Callers most commonly need to iterate backwards over the history
timeless
help: miscellaneous language fixes
r7807 in which they are interested. Doing so has awful (quadratic-looking)
Matt Mackall
move walkchangerevs to cmdutils
r3650 performance, so we use iterators in a "windowed" way.
We walk a window of revisions in the desired order. Within the
window, we first walk forwards to gather data, then in the desired
order (usually backwards) to display it.
This function returns an (iterator, matchfn) tuple. The iterator
yields 3-tuples. They will be of one of the following forms:
"window", incrementing, lastrev: stepping through a window,
positive if walking forwards through revs, last rev in the
sequence iterated over - use to reset state for the current window
"add", rev, fns: out-of-order traversal of the given file names
fns, which changed during revision rev - use to gather data for
possible display
"iter", rev, None: in-order traversal of the revs earlier iterated
over with "add" - use to display data'''
def increasing_windows(start, end, windowsize=8, sizelimit=512):
if start < end:
while start < end:
yield start, min(windowsize, end-start)
start += windowsize
if windowsize < sizelimit:
windowsize *= 2
else:
while start > end:
yield start, min(windowsize, start-end-1)
start -= windowsize
if windowsize < sizelimit:
windowsize *= 2
Matt Mackall
walkchangerev: use new match objects
r6580 m = match(repo, pats, opts)
Matt Mackall
move walkchangerevs to cmdutils
r3650 follow = opts.get('follow') or opts.get('follow_first')
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 if not len(repo):
Matt Mackall
walkchangerev: use new match objects
r6580 return [], m
Matt Mackall
move walkchangerevs to cmdutils
r3650
if follow:
Matt Mackall
use repo[changeid] to get a changectx
r6747 defrange = '%s:0' % repo['.'].rev()
Matt Mackall
move walkchangerevs to cmdutils
r3650 else:
Alexis S. L. Carvalho
cmdutil.walkchangerevs: use '-1:0' instead ot 'tip:0'...
r6145 defrange = '-1:0'
Thomas Arendsen Hein
Removed unused ui parameter from revpair/revrange and fix its users.
r3707 revs = revrange(repo, opts['rev'] or [defrange])
Martin Geisler
replace set-like dictionaries with real sets...
r8152 wanted = set()
Matt Mackall
log: ignore --removed if no files specified (issue1166)...
r7779 slowpath = m.anypats() or (m.files() and opts.get('removed'))
Matt Mackall
move walkchangerevs to cmdutils
r3650 fncache = {}
Matt Mackall
walkchangerev: use new match objects
r6580 if not slowpath and not m.files():
Matt Mackall
move walkchangerevs to cmdutils
r3650 # No files, no patterns. Display all revs.
Martin Geisler
replace set-like dictionaries with real sets...
r8152 wanted = set(revs)
Matt Mackall
move walkchangerevs to cmdutils
r3650 copies = []
if not slowpath:
# Only files, no patterns. Check the history of each file.
def filerevgen(filelog, node):
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 cl_count = len(repo)
Matt Mackall
move walkchangerevs to cmdutils
r3650 if node is None:
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 last = len(filelog) - 1
Matt Mackall
move walkchangerevs to cmdutils
r3650 else:
last = filelog.rev(node)
for i, window in increasing_windows(last, nullrev):
revs = []
for j in xrange(i - window, i + 1):
n = filelog.node(j)
Matt Mackall
linkrev: take a revision number rather than a hash
r7361 revs.append((filelog.linkrev(j),
Matt Mackall
move walkchangerevs to cmdutils
r3650 follow and filelog.renamed(n)))
Matt Mackall
replace various uses of list.reverse()
r8210 for rev in reversed(revs):
Matt Mackall
move walkchangerevs to cmdutils
r3650 # only yield rev for which we have the changelog, it can
# happen while doing "hg log" during a pull or commit
if rev[0] < cl_count:
yield rev
def iterfiles():
Matt Mackall
walkchangerev: use new match objects
r6580 for filename in m.files():
Matt Mackall
move walkchangerevs to cmdutils
r3650 yield filename, None
for filename_node in copies:
yield filename_node
minrev, maxrev = min(revs), max(revs)
for file_, node in iterfiles():
filelog = repo.file(file_)
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 if not len(filelog):
Patrick Mezard
cmdutil: handle and warn about missing copy revisions
r6536 if node is None:
# A zero count may be a directory or deleted file, so
# try to find matching entries on the slow path.
Brendan Cully
Improved error message for log --follow...
r7404 if follow:
raise util.Abort(_('cannot follow nonexistent file: "%s"') % file_)
Patrick Mezard
cmdutil: handle and warn about missing copy revisions
r6536 slowpath = True
break
else:
Dirkjan Ochtman
remove trailing spaces
r6553 ui.warn(_('%s:%s copy source revision cannot be found!\n')
Patrick Mezard
cmdutil: handle and warn about missing copy revisions
r6536 % (file_, short(node)))
continue
Matt Mackall
move walkchangerevs to cmdutils
r3650 for rev, copied in filerevgen(filelog, node):
if rev <= maxrev:
if rev < minrev:
break
fncache.setdefault(rev, [])
fncache[rev].append(file_)
Martin Geisler
replace set-like dictionaries with real sets...
r8152 wanted.add(rev)
Matt Mackall
move walkchangerevs to cmdutils
r3650 if follow and copied:
copies.append(copied)
if slowpath:
if follow:
raise util.Abort(_('can only follow copies/renames for explicit '
'file names'))
# The slow path checks files modified in every changeset.
def changerevgen():
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for i, window in increasing_windows(len(repo) - 1, nullrev):
Matt Mackall
move walkchangerevs to cmdutils
r3650 for j in xrange(i - window, i + 1):
yield j, change(j)[3]
for rev, changefiles in changerevgen():
Matt Mackall
walkchangerev: use new match objects
r6580 matches = filter(m, changefiles)
Matt Mackall
move walkchangerevs to cmdutils
r3650 if matches:
fncache[rev] = matches
Martin Geisler
replace set-like dictionaries with real sets...
r8152 wanted.add(rev)
Matt Mackall
move walkchangerevs to cmdutils
r3650
class followfilter:
def __init__(self, onlyfirst=False):
self.startrev = nullrev
self.roots = []
self.onlyfirst = onlyfirst
def match(self, rev):
def realparents(rev):
if self.onlyfirst:
return repo.changelog.parentrevs(rev)[0:1]
else:
return filter(lambda x: x != nullrev,
repo.changelog.parentrevs(rev))
if self.startrev == nullrev:
self.startrev = rev
return True
if rev > self.startrev:
# forward: all descendants
if not self.roots:
self.roots.append(self.startrev)
for parent in realparents(rev):
if parent in self.roots:
self.roots.append(rev)
return True
else:
# backwards: all parents
if not self.roots:
self.roots.extend(realparents(self.startrev))
if rev in self.roots:
self.roots.remove(rev)
self.roots.extend(realparents(rev))
return True
return False
# it might be worthwhile to do this in the iterator if the rev range
# is descending and the prune args are all within that range
for rev in opts.get('prune', ()):
rev = repo.changelog.rev(repo.lookup(rev))
ff = followfilter()
stop = min(revs[0], revs[-1])
for x in xrange(rev, stop-1, -1):
Martin Geisler
replace set-like dictionaries with real sets...
r8152 if ff.match(x):
wanted.discard(x)
Matt Mackall
move walkchangerevs to cmdutils
r3650
def iterate():
Matt Mackall
walkchangerev: use new match objects
r6580 if follow and not m.files():
Matt Mackall
move walkchangerevs to cmdutils
r3650 ff = followfilter(onlyfirst=opts.get('follow_first'))
def want(rev):
Martin Geisler
cmdutil: return boolean result directly in want function
r8119 return ff.match(rev) and rev in wanted
Matt Mackall
move walkchangerevs to cmdutils
r3650 else:
def want(rev):
return rev in wanted
for i, window in increasing_windows(0, len(revs)):
yield 'window', revs[0] < revs[-1], revs[-1]
nrevs = [rev for rev in revs[i:i+window] if want(rev)]
Matt Mackall
replace util.sort with sorted built-in...
r8209 for rev in sorted(nrevs):
Matt Mackall
move walkchangerevs to cmdutils
r3650 fns = fncache.get(rev)
if not fns:
def fns_generator():
for f in change(rev)[3]:
Matt Mackall
walkchangerev: use new match objects
r6580 if m(f):
Matt Mackall
move walkchangerevs to cmdutils
r3650 yield f
fns = fns_generator()
yield 'add', rev, fns
for rev in nrevs:
yield 'iter', rev, None
Matt Mackall
walkchangerev: use new match objects
r6580 return iterate(), m
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034
def commit(ui, repo, commitfunc, pats, opts):
'''commit the specified files or all outstanding changes'''
Thomas Arendsen Hein
Fix bad behaviour when specifying an invalid date (issue700)...
r6139 date = opts.get('date')
if date:
opts['date'] = util.parsedate(date)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 message = logmessage(opts)
Kirill Smelkov
cmdutil.commit: extract 'addremove' from opts carefully...
r5829 # extract addremove carefully -- this function can be called from a command
# that doesn't support addremove
if opts.get('addremove'):
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 addremove(repo, pats, opts)
Kirill Smelkov
cmdutil.commit: extract 'addremove' from opts carefully...
r5829
Matt Mackall
cmdutil: switch commit to match
r6581 m = match(repo, pats, opts)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 if pats:
Matt Mackall
status: clean up all users for unknown files
r6760 modified, added, removed = repo.status(match=m)[:3]
Matt Mackall
replace util.sort with sorted built-in...
r8209 files = sorted(modified + added + removed)
Benoit Boissinot
allow committing a removed directory...
r6980
def is_dir(f):
name = f + '/'
i = bisect.bisect(files, name)
return i < len(files) and files[i].startswith(name)
Matt Mackall
cmdutil: switch commit to match
r6581 for f in m.files():
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 if f == '.':
continue
if f not in files:
rf = repo.wjoin(f)
Alexis S. L. Carvalho
cmdutil.commit: use relative paths in the error messages...
r6112 rel = repo.pathto(f)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 try:
mode = os.lstat(rf)[stat.ST_MODE]
except OSError:
Benoit Boissinot
allow committing a removed directory...
r6980 if is_dir(f): # deleted directory ?
continue
Alexis S. L. Carvalho
cmdutil.commit: use relative paths in the error messages...
r6112 raise util.Abort(_("file %s not found!") % rel)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 if stat.S_ISDIR(mode):
Benoit Boissinot
allow committing a removed directory...
r6980 if not is_dir(f):
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 raise util.Abort(_("no match under directory %s!")
Alexis S. L. Carvalho
cmdutil.commit: use relative paths in the error messages...
r6112 % rel)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
raise util.Abort(_("can't commit %s: "
Alexis S. L. Carvalho
cmdutil.commit: use relative paths in the error messages...
r6112 "unsupported file type!") % rel)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 elif f not in repo.dirstate:
Alexis S. L. Carvalho
cmdutil.commit: use relative paths in the error messages...
r6112 raise util.Abort(_("file %s not tracked!") % rel)
Matt Mackall
match: use helpers for cmdutil
r6597 m = matchfiles(repo, files)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 try:
Matt Mackall
match: stop passing files through commitfunc
r6600 return commitfunc(ui, repo, message, m, opts)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034 except ValueError, inst:
raise util.Abort(str(inst))
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407
def commiteditor(repo, ctx, added, updated, removed):
if ctx.description():
return ctx.description()
return commitforceeditor(repo, ctx, added, updated, removed)
def commitforceeditor(repo, ctx, added, updated, removed):
edittext = []
if ctx.description():
edittext.append(ctx.description())
edittext.append("")
edittext.append("") # Empty line between message and comments.
edittext.append(_("HG: Enter commit message."
" Lines beginning with 'HG:' are removed."))
Martin Geisler
cmdutil: mark string for translation
r8535 edittext.append(_("HG: Leave message empty to abort commit."))
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 edittext.append("HG: --")
edittext.append(_("HG: user: %s") % ctx.user())
if ctx.p2():
edittext.append(_("HG: branch merge"))
if ctx.branch():
edittext.append(_("HG: branch '%s'")
% encoding.tolocal(ctx.branch()))
edittext.extend([_("HG: added %s") % f for f in added])
edittext.extend([_("HG: changed %s") % f for f in updated])
edittext.extend([_("HG: removed %s") % f for f in removed])
if not added and not updated and not removed:
edittext.append(_("HG: no files changed"))
edittext.append("")
# run editor in the repository root
olddir = os.getcwd()
os.chdir(repo.root)
text = repo.ui.edit("\n".join(edittext), ctx.user())
Matt Mackall
editor: move HG: filtering from ui to commiteditor
r8409 text = re.sub("(?m)^HG:.*\n", "", text)
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 os.chdir(olddir)
if not text.strip():
raise util.Abort(_("empty commit message"))
return text