##// END OF EJS Templates
histedit: abort if there are multiple roots in "--outgoing" revisions...
histedit: abort if there are multiple roots in "--outgoing" revisions Before this patch, if there are multiple roots in "--outgoing" revisions, result of "histedit --outgoing" depends on the parent of the working directory. It succeeds only when the parent of the working directory is a descendant of the oldest root in "--outgoing" revisions, and fails otherwise. It seems to be ambiguous and difficult for users. This patch makes "histedit --outgoing" abort if there are multiple roots in "--outgoing" revisions always.

File last commit:

r19804:061ce98c default
r19835:44d7bfe0 default
Show More
cmdutil.py
2161 lines | 78.1 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
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
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 _
Sune Foldager
cmdutil: fix errors reported by pyflakes test
r14269 import os, sys, errno, re, tempfile
Matt Mackall
rebase: move updatedirstate into cmdutil so it can be shared
r15214 import util, scmutil, templater, patch, error, templatekw, revlog, copies
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 import match as matchmod
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 import subrepo, context, repair, graphmod, revset, phases, obsolete
Pierre-Yves David
amend: add noise in extra to avoid creating obsolescence cycle (issue3664)...
r17811 import changelog
Antonio Zanardo
commit: show active bookmark in commit editor helper text...
r18538 import bookmarks
Pierre-Yves David
amend: lock the repository during the whole process...
r17471 import lock as lockmod
Vadim Gelfer
refactor text diff/patch code....
r2874
Brendan Cully
mq: add -Q option to all commands not in norepo
r10401 def parsealiases(cmd):
return cmd.lstrip("^").split("|")
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
alias: shortcut command matching show shadowing works properly (issue3104)...
r15600
if cmd in table:
# short-circuit exact matches, "log" alias beats "^log|history"
keys = [cmd]
else:
keys = table.keys()
for e in keys:
Brendan Cully
mq: add -Q option to all commands not in norepo
r10401 aliases = parsealiases(e)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 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
Brendan Cully
mq: make init -Q do what qinit -c did
r10402 def findrepo(p):
while not os.path.isdir(os.path.join(p, ".hg")):
oldp, p = p, os.path.dirname(p)
if p == oldp:
return None
return p
Matt Mackall
cmdutil: bail_if_changed to bailifchanged
r14289 def bailifchanged(repo):
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 if repo.dirstate.p2() != nullid:
Matt Mackall
cmdutil: make bail_if_changed bail on uncommitted merge
r5716 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:
Siddharth Agarwal
cmdutil.bailifchanged: standardize error message for dirty working dir...
r19804 raise util.Abort(_('uncommitted changes'))
Eric Roshan Eisner
cmdutil.bailifchanged: abort for dirty subrepos
r15231 ctx = repo[None]
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 for s in sorted(ctx.substate):
Eric Roshan Eisner
cmdutil.bailifchanged: abort for dirty subrepos
r15231 if ctx.sub(s).dirty():
raise util.Abort(_("uncommitted changes in subrepo %s") % s)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
Idan Kamara
cmdutil, logmessage: use ui.fin when reading from '-'
r14635 def logmessage(ui, opts):
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 """ 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 == '-':
Idan Kamara
cmdutil, logmessage: use ui.fin when reading from '-'
r14635 message = ui.fin.read()
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 else:
Patrick Mezard
cmdutil: normalize log message eols when reading from file...
r14249 message = '\n'.join(util.readfile(logfile).splitlines())
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 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'))
Matt Mackall
many, many trivial check-code fixups
r10282 if limit <= 0:
raise util.Abort(_('limit must be positive'))
Thomas Arendsen Hein
Move finding/checking the log limit to cmdutil
r6190 else:
Nicolas Dumazet
cmdutil: replace sys.maxint with None as default value in loglimit...
r10111 limit = None
Thomas Arendsen Hein
Move finding/checking the log limit to cmdutil
r6190 return limit
Andrzej Bieniek
export: add %m to file format string (first line of the commit message)...
r14986 def makefilename(repo, pat, node, desc=None,
Vadim Gelfer
refactor text diff/patch code....
r2874 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),
Andrzej Bieniek
export: add %m to file format string (first line of the commit message)...
r14986 'm': lambda: re.sub('[^\w]', '_', str(desc))
Vadim Gelfer
refactor text diff/patch code....
r2874 }
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:
timeless
Generally replace "file name" with "filename" in help and comments.
r8761 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
Thomas Arendsen Hein
Never apply string formatting to generated errors with util.Abort....
r3072 inst.args[0])
Vadim Gelfer
refactor text diff/patch code....
r2874
Andrzej Bieniek
export: add %m to file format string (first line of the commit message)...
r14986 def makefileobj(repo, pat, node=None, desc=None, total=None,
Augie Fackler
export: clobber files with -o (bc) (issue3652)...
r18613 seqno=None, revwidth=None, mode='wb', modemap={},
pathname=None):
Ronny Pfannschmidt
export: fixed silent output file overwriting...
r7319
Adrian Buehlmann
cmdutil: fix mode handling in make_file
r13769 writable = mode not in ('r', 'rb')
Ronny Pfannschmidt
export: fixed silent output file overwriting...
r7319
Vadim Gelfer
refactor text diff/patch code....
r2874 if not pat or pat == '-':
Idan Kamara
cmdutil: use ui descriptors in makefileobj
r14637 fp = writable and repo.ui.fout or repo.ui.fin
Augie Fackler
cmdutil: use safehasattr instead of hasattr
r14948 if util.safehasattr(fp, 'fileno'):
Idan Kamara
cmdutil: return a dummy, closable file object if it cannot be duped...
r14638 return os.fdopen(os.dup(fp.fileno()), mode)
else:
# if this fp can't be duped properly, return
# a dummy object that can be closed
class wrappedfileobj(object):
noop = lambda x: None
def __init__(self, f):
self.f = f
def __getattr__(self, attr):
if attr == 'close':
return self.noop
else:
return getattr(self.f, attr)
return wrappedfileobj(fp)
Augie Fackler
cmdutil: use safehasattr instead of hasattr
r14948 if util.safehasattr(pat, 'write') and writable:
Vadim Gelfer
refactor text diff/patch code....
r2874 return pat
Augie Fackler
cmdutil: use safehasattr instead of hasattr
r14948 if util.safehasattr(pat, 'read') and 'r' in mode:
Vadim Gelfer
refactor text diff/patch code....
r2874 return pat
Augie Fackler
export: clobber files with -o (bc) (issue3652)...
r18613 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
mode = modemap.get(fn, mode)
if mode == 'wb':
modemap[fn] = 'ab'
return open(fn, mode)
Vadim Gelfer
move walk and matchpats from commands to cmdutil.
r2882
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 def openrevlog(repo, cmd, file_, opts):
"""opens the changelog, manifest, a filelog or a given revlog"""
cl = opts['changelog']
mf = opts['manifest']
msg = None
if cl and mf:
msg = _('cannot specify --changelog and --manifest at the same time')
elif cl or mf:
if file_:
msg = _('cannot specify filename with --changelog or --manifest')
elif not repo:
msg = _('cannot specify --changelog or --manifest '
'without a repository')
if msg:
raise util.Abort(msg)
r = None
if repo:
if cl:
r = repo.changelog
elif mf:
r = repo.manifest
elif file_:
filelog = repo.file(file_)
if len(filelog):
r = filelog
if not r:
if not file_:
raise error.CommandError(cmd, _('invalid arguments'))
if not os.path.isfile(file_):
raise util.Abort(_("revlog '%s' not found") % file_)
r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
file_[:-2] + ".i")
return r
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")
Dirkjan Ochtman
move working dir/dirstate methods from localrepo to workingctx
r11303 wctx = repo[None]
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 def walkpat(pat):
srcs = []
Peter Arrenbrecht
rename: make --after work if source is already in R state...
r11223 badstates = after and '?' or '?r'
Matt Mackall
scmutil: switch match users to supplying contexts...
r14671 m = scmutil.match(repo[None], [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)
Peter Arrenbrecht
rename: make --after work if source is already in R state...
r11223 if state in badstates:
Matt Mackall
copy: refactor okaytocopy into walkpat...
r5605 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):
Adrian Buehlmann
move canonpath from util to scmutil
r13971 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
Patrick Mezard
dirstate: preserve path components case on renames (issue3402)...
r16542 if '/' in abstarget:
# We cannot normalize abstarget itself, this would prevent
# case only renames, like a => A.
abspath, absname = abstarget.rsplit('/', 1)
abstarget = repo.dirstate.normalize(abspath) + '/' + absname
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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
Adrian Buehlmann
add: introduce a warning message for non-portable filenames (issue2756) (BC)...
r13962 scmutil.checkportable(ui, abstarget)
Adrian Buehlmann
copy: do not copy file if name is disallowed anyway
r13945
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
Patrick Mezard
rename: do not overwrite existing broken symlinks
r12342 exists = os.path.lexists(target)
Matt Mackall
rename: handle case-changing (issue1717)
r16283 samefile = False
if exists and abssrc != abstarget:
if (repo.dirstate.normalize(abssrc) ==
repo.dirstate.normalize(abstarget)):
if not rename:
ui.warn(_("%s: can't copy - same file\n") % reltarget)
return
exists = False
samefile = True
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:
Steve Losh
cmdutil: Warn when trying to copy/rename --after to a nonexistant file....
r11152 if rename:
ui.warn(_('%s: not recording move - %s does not exist\n') %
(relsrc, reltarget))
else:
ui.warn(_('%s: not recording copy - %s does not exist\n') %
(relsrc, reltarget))
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)
Matt Mackall
rename: handle case-changing (issue1717)
r16283 if samefile:
tmp = target + "~hgrename"
os.rename(src, tmp)
os.rename(tmp, target)
else:
util.copyfile(src, target)
Adrian Buehlmann
workingctx: eliminate remove function...
r14518 srcexists = True
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)
Adrian Buehlmann
workingctx: eliminate remove function...
r14518 srcexists = False
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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
scmutil: drop some aliases in cmdutil
r14321 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
dryrun=dryrun, cwd=cwd)
Matt Mackall
copy: handle rename internally...
r5610 if rename and not dryrun:
Matt Mackall
rename: handle case-changing (issue1717)
r16283 if not after and srcexists and not samefile:
Adrian Buehlmann
workingctx: eliminate remove function...
r14518 util.unlinkpath(repo.wjoin(abssrc))
wctx.forget([abssrc])
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):
Adrian Buehlmann
move canonpath from util to scmutil
r13971 abspfx = scmutil.canonpath(repo.root, cwd, pat)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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):
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 if matchmod.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:
Adrian Buehlmann
move canonpath from util to scmutil
r13971 abspfx = scmutil.canonpath(repo.root, cwd, pat)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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:])
Patrick Mezard
Restore lexists() changes lost in e0ee3e822a9a merge
r12357 if os.path.lexists(t):
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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
scmutil: drop some aliases in cmdutil
r14321 pats = scmutil.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:
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 if len(pats) > 1 or matchmod.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
commands: initial audit of exit codes...
r11177 return errors != 0
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
Nicolas Dumazet
cmdutil: service: add an optional runargs argument to pass the command to run...
r9513 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
Nicolas Dumazet
cmdutil: service: add appendpid parameter to append pids to pid file
r10012 runargs=None, appendpid=False):
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380 '''Run a command as a service.'''
if opts['daemon'] and not opts['daemon_pipefds']:
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 # Signal child process startup with file removal
lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
Matt Mackall
many, many trivial check-code fixups
r10282 os.close(lockfd)
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 try:
if not runargs:
Patrick Mezard
Find right hg command for detached process...
r10239 runargs = util.hgcmd() + sys.argv[1:]
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 runargs.append('--daemon-pipefds=%s' % lockpath)
# Don't pass --cwd to the child process, because we've already
# changed directory.
Matt Mackall
many, many trivial check-code fixups
r10282 for i in xrange(1, len(runargs)):
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 if runargs[i].startswith('--cwd='):
del runargs[i]
break
elif runargs[i].startswith('--cwd'):
Matt Mackall
many, many trivial check-code fixups
r10282 del runargs[i:i + 2]
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 break
Patrick Mezard
util: make spawndetached() handle subprocess early terminations...
r10344 def condfn():
return not os.path.exists(lockpath)
pid = util.rundetached(runargs, condfn)
if pid < 0:
raise util.Abort(_('child process failed to start'))
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 finally:
try:
os.unlink(lockpath)
except OSError, e:
if e.errno != errno.ENOENT:
raise
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380 if parentfn:
return parentfn(pid)
else:
Nicolas Dumazet
cmdutil.service: do not _exit(0) in the parent process...
r9896 return
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380
if initfn:
initfn()
if opts['pid_file']:
Nicolas Dumazet
cmdutil: service: add appendpid parameter to append pids to pid file
r10012 mode = appendpid and 'a' or 'w'
fp = open(opts['pid_file'], mode)
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380 fp.write(str(os.getpid()) + '\n')
fp.close()
if opts['daemon_pipefds']:
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 lockpath = opts['daemon_pipefds']
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380 try:
os.setsid()
except AttributeError:
pass
Patrick Mezard
cmdutil: replace unix pipe handshake with file lock...
r10238 os.unlink(lockpath)
Patrick Mezard
cmdutil: hide child window created by win32 spawndetached()...
r10240 util.hidewindow()
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380 sys.stdout.flush()
sys.stderr.flush()
Nicolas Dumazet
cmdutil: service: logfile option to redirect stdout & stderr in a file
r8789
Ross Lagerwall
util: replace util.nulldev with os.devnull...
r17391 nullfd = os.open(os.devnull, os.O_RDWR)
Nicolas Dumazet
cmdutil: service: logfile option to redirect stdout & stderr in a file
r8789 logfilefd = nullfd
if logfile:
logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
os.dup2(nullfd, 0)
os.dup2(logfilefd, 1)
os.dup2(logfilefd, 2)
if nullfd not in (0, 1, 2):
os.close(nullfd)
if logfile and logfilefd not in (0, 1, 2):
os.close(logfilefd)
Bryan O'Sullivan
Refactor commands.serve to allow other commands to run as services....
r4380
if runfn:
return runfn()
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
opts=None):
'''export changesets as hg patches.'''
total = len(revs)
revwidth = max([len(str(rev)) for rev in revs])
Augie Fackler
export: clobber files with -o (bc) (issue3652)...
r18613 filemode = {}
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611
def single(rev, seqno, fp):
ctx = repo[rev]
node = ctx.node()
parents = [p.node() for p in ctx.parents() if p]
branch = ctx.branch()
if switch_parent:
parents.reverse()
prev = (parents and parents[0]) or nullid
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 shouldclose = False
Ankur Dahiya
color: enabled color support for export command (issue1507)...
r17460 if not fp and len(template) > 0:
Andrzej Bieniek
export: add %m to file format string (first line of the commit message)...
r14986 desc_lines = ctx.description().rstrip().split('\n')
desc = desc_lines[0] #Commit always has a first line.
fp = makefileobj(repo, template, node, desc=desc, total=total,
Augie Fackler
export: clobber files with -o (bc) (issue3652)...
r18613 seqno=seqno, revwidth=revwidth, mode='wb',
modemap=filemode)
Waqas Hussain
export: only close files which export itself has opened
r13467 if fp != template:
shouldclose = True
Ankur Dahiya
color: enabled color support for export command (issue1507)...
r17460 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611 repo.ui.note("%s\n" % fp.name)
Ankur Dahiya
color: enabled color support for export command (issue1507)...
r17460 if not fp:
write = repo.ui.write
else:
def write(s, **kw):
fp.write(s)
write("# HG changeset patch\n")
write("# User %s\n" % ctx.user())
write("# Date %d %d\n" % ctx.date())
Mads Kiilerich
export: show 'Date' header in a format that also is readable for humans...
r18648 write("# %s\n" % util.datestr(ctx.date()))
Martin Geisler
cmdutil: remove unnecessary parenthesis
r11821 if branch and branch != 'default':
Ankur Dahiya
color: enabled color support for export command (issue1507)...
r17460 write("# Branch %s\n" % branch)
write("# Node ID %s\n" % hex(node))
write("# Parent %s\n" % hex(prev))
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611 if len(parents) > 1:
Ankur Dahiya
color: enabled color support for export command (issue1507)...
r17460 write("# Parent %s\n" % hex(parents[1]))
write(ctx.description().rstrip())
write("\n\n")
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611
Ankur Dahiya
color: enabled color support for export command (issue1507)...
r17460 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
write(chunk, label=label)
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 if shouldclose:
fp.close()
Dan Villiom Podlaski Christiansen
export: flush the file pointer between patches
r13081
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611 for seqno, rev in enumerate(revs):
single(rev, seqno + 1, fp)
Yuya Nishihara
commands: refactor diff --stat and qdiff --stat...
r11050 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 changes=None, stat=False, fp=None, prefix='',
listsubrepos=False):
Yuya Nishihara
commands: refactor diff --stat and qdiff --stat...
r11050 '''show diff or diffstat.'''
if fp is None:
write = ui.write
else:
def write(s, **kw):
fp.write(s)
if stat:
Alecs King
log: fix the bug 'hg log --stat -p == hg log --stat'...
r11950 diffopts = diffopts.copy(context=0)
Yuya Nishihara
commands: refactor diff --stat and qdiff --stat...
r11050 width = 80
if not ui.plain():
Augie Fackler
termwidth: move to ui.ui from util
r12689 width = ui.termwidth()
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
prefix=prefix)
Yuya Nishihara
commands: refactor diff --stat and qdiff --stat...
r11050 for chunk, label in patch.diffstatui(util.iterlines(chunks),
width=width,
git=diffopts.git):
write(chunk, label=label)
else:
for chunk, label in patch.diffui(repo, node1, node2, match,
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 changes, diffopts, prefix=prefix):
Yuya Nishihara
commands: refactor diff --stat and qdiff --stat...
r11050 write(chunk, label=label)
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 if listsubrepos:
ctx1 = repo[node1]
Martin Geisler
subrepos: handle modified but uncommitted .hgsub
r12175 ctx2 = repo[node2]
Martin Geisler
subrepos: add function for iterating over ctx subrepos
r12176 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
Alistair Bell
diff: when diffing a revision with a deleted subrepo, maintain the node context (issue3153)
r15698 tempnode2 = node2
Renato Cunha
diff: don't crash when diffing a revision with a deleted subrepo (issue3153)...
r15634 try:
if node2 is not None:
Alistair Bell
diff: when diffing a revision with a deleted subrepo, maintain the node context (issue3153)
r15698 tempnode2 = ctx2.substate[subpath][1]
Renato Cunha
diff: don't crash when diffing a revision with a deleted subrepo (issue3153)...
r15634 except KeyError:
# A subrepo that existed in node1 was deleted between node1 and
# node2 (inclusive). Thus, ctx2's substate won't contain that
# subpath. The best we can do is to ignore it.
Alistair Bell
diff: when diffing a revision with a deleted subrepo, maintain the node context (issue3153)
r15698 tempnode2 = None
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 submatch = matchmod.narrowmatcher(subpath, match)
FUJIWARA Katsunori
subrepo: add argument to "diff()" to pass "ui" of caller side (issue3712) (API)...
r18006 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
Martin Geisler
diff: recurse into subrepositories with --subrepos/-S flag
r12167 stat=stat, fp=fp, prefix=prefix)
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
Robert Bachmann
Added support for templatevar "footer" to cmdutil.py
r10152 self.footer = 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
Robert Bachmann
Added support for templatevar "footer" to cmdutil.py
r10152 def close(self):
if self.footer:
self.ui.write(self.footer)
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 def show(self, ctx, copies=None, matchfn=None, **props):
Matt Mackall
use ui buffering in changeset printer...
r3738 if self.buffered:
self.ui.pushbuffer()
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 self._show(ctx, copies, matchfn, props)
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
Matt Mackall
use ui buffering in changeset printer...
r3738 else:
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 self._show(ctx, copies, matchfn, props)
Matt Mackall
use ui buffering in changeset printer...
r3738
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 def _show(self, ctx, copies, matchfn, 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:
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write("%d:%s\n" % (rev, short(changenode)),
label='log.node')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 return
Dirkjan Ochtman
cmdutil: use change contexts for cset-printer and cset-templater
r7369 log = self.repo.changelog
Greg Ward
cmdutil: changeset_printer: use methods of filectx/changectx....
r9547 date = util.datestr(ctx.date())
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
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
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
Sean Farley
color: add additional changeset.phase label to log.changeset and log.parent...
r17788 label='log.changeset changeset.%s' % ctx.phasestr())
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Adrian Buehlmann
cmdutil: minor refactoring of changeset_printer._show...
r9637 branch = ctx.branch()
Alexis S. L. Carvalho
"default" is the default branch name
r4176 # don't show the default branch name
if branch != 'default':
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("branch: %s\n") % branch,
label='log.branch')
David Soria Parra
templater: add bookmarks to templates and default output...
r13386 for bookmark in self.repo.nodebookmarks(changenode):
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
David Soria Parra
templater: add bookmarks to templates and default output...
r13386 self.ui.write(_("bookmark: %s\n") % bookmark,
label='log.bookmark')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 for tag in self.repo.nodetags(changenode):
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("tag: %s\n") % tag,
label='log.tag')
Pierre-Yves David
changeset_printer: display changeset phase on debug level...
r15907 if self.ui.debugflag and ctx.phase():
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Pierre-Yves David
changeset_printer: display changeset phase on debug level...
r15907 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
label='log.phase')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 for parent in parents:
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("parent: %d:%s\n") % parent,
Sean Farley
color: add additional changeset.phase label to log.changeset and log.parent...
r17788 label='log.parent changeset.%s' % ctx.phasestr())
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
if self.ui.debugflag:
Greg Ward
cmdutil: changeset_printer: use methods of filectx/changectx....
r9547 mnode = ctx.manifestnode()
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui.write(_("manifest: %d:%s\n") %
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 (self.repo.manifest.rev(mnode), hex(mnode)),
label='ui.debug log.manifest')
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("user: %s\n") % ctx.user(),
label='log.user')
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("date: %s\n") % date,
label='log.date')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
if self.ui.debugflag:
files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 for key, value in zip([# i18n: column positioning for "hg log"
_("files:"),
# i18n: column positioning for "hg log"
_("files+:"),
# i18n: column positioning for "hg log"
_("files-:")], files):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 if value:
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
label='ui.debug log.files')
Greg Ward
cmdutil: changeset_printer: use methods of filectx/changectx....
r9547 elif ctx.files() and self.ui.verbose:
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
label='ui.note log.files')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 if copies and self.ui.verbose:
copies = ['%s (%s)' % c for c in copies]
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("copies: %s\n") % ' '.join(copies),
label='ui.note log.copies')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Adrian Buehlmann
cmdutil: minor refactoring of changeset_printer._show...
r9637 extra = ctx.extra()
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 if extra and self.ui.debugflag:
Matt Mackall
replace util.sort with sorted built-in...
r8209 for key, value in sorted(extra.items()):
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui.write(_("extra: %s=%s\n")
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 % (key, value.encode('string_escape')),
label='ui.debug log.extra')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Greg Ward
cmdutil: changeset_printer: use methods of filectx/changectx....
r9547 description = ctx.description().strip()
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 if description:
if self.ui.verbose:
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 self.ui.write(_("description:\n"),
label='ui.note log.description')
self.ui.write(description,
label='ui.note log.description')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui.write("\n\n")
else:
FUJIWARA Katsunori
i18n: add "i18n" comment to column positioning messages of "hg log"...
r17891 # i18n: column positioning for "hg log"
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui.write(_("summary: %s\n") %
Brodie Rao
cmdutil: make use of output labeling in changeset_printer
r10819 description.splitlines()[0],
label='log.summary')
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 self.ui.write("\n")
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 self.showpatch(changenode, matchfn)
Matt Mackall
Refactor log ui buffering and patch display
r3645
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 def showpatch(self, node, matchfn):
if not matchfn:
matchfn = self.patch
if matchfn:
Yuya Nishihara
log: add --stat for diffstat output...
r11061 stat = self.diffopts.get('stat')
Alecs King
log: fix the bug 'hg log --stat -p == hg log --stat'...
r11950 diff = self.diffopts.get('patch')
Yuya Nishihara
log: add --stat for diffstat output...
r11061 diffopts = patch.diffopts(self.ui, self.diffopts)
Matt Mackall
Refactor log ui buffering and patch display
r3645 prev = self.repo.changelog.parents(node)[0]
Alecs King
log: fix the bug 'hg log --stat -p == hg log --stat'...
r11950 if stat:
diffordiffstat(self.ui, self.repo, diffopts, prev, node,
match=matchfn, stat=True)
if diff:
if stat:
self.ui.write("\n")
diffordiffstat(self.ui, self.repo, diffopts, prev, node,
match=matchfn, stat=False)
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])
Patrick Mezard
Make {file_copies} usable as a --template key...
r10061 defaulttempl = {
'parent': '{rev}:{node|formatnode} ',
'manifest': '{rev}:{node|formatnode}',
'file_copy': '{name} ({source})',
'extra': '{key}={value|stringescape}'
}
# filecopy is preserved for compatibility reasons
defaulttempl['filecopy'] = defaulttempl['file_copy']
Dirkjan Ochtman
templater: provide the standard template filters by default
r8360 self.t = templater.templater(mapfile, {'formatnode': formatnode},
Patrick Mezard
Make {file_copies} usable as a --template key...
r10061 cache=defaulttempl)
Patrick Mezard
cmdutil: extract latest tags closures in templatekw
r10057 self.cache = {}
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
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 def _show(self, ctx, copies, matchfn, props):
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 '''show a single changeset or file revision'''
Patrick Mezard
cmdutil: replace showlist() closure with a function
r10053 showlist = templatekw.showlist
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Patrick Mezard
cmdutil: extract file copies closure into templatekw
r10058 # showparents() behaviour depends on ui trace level which
# causes unexpected behaviours at templating level and makes
# it harder to extract it in a standalone function. Its
# behaviour cannot be changed so leave it here for now.
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643 def showparents(**args):
Patrick Mezard
templatekw: fix extras, manifest and showlist args (issue1989)...
r10260 ctx = args['ctx']
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)
props = props.copy()
Patrick Mezard
cmdutil: extract ctx dependent closures into templatekw
r10054 props.update(templatekw.keywords)
Patrick Mezard
cmdutil: extract file copies closure into templatekw
r10058 props['parents'] = showparents
Patrick Mezard
cmdutil: replace showlist() closure with a function
r10053 props['templ'] = self.t
Patrick Mezard
cmdutil: extract ctx dependent closures into templatekw
r10054 props['ctx'] = ctx
Patrick Mezard
cmdutil: extract repo dependent closures in templatekw
r10055 props['repo'] = self.repo
Patrick Mezard
cmdutil: extract file copies closure into templatekw
r10058 props['revcache'] = {'copies': copies}
Patrick Mezard
cmdutil: extract latest tags closures in templatekw
r10057 props['cache'] = self.cache
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
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'),
]
Robert Bachmann
Added support for templatevar "footer" to cmdutil.py
r10152 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
Dirkjan Ochtman
cmdutil: prevent code repetition by abstraction in changeset_templater
r8013 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:
Simon Howkins
heads: fix templating of headers again (issue2130)...
r11465 if self.lastheader != h:
self.lastheader = h
Simon Howkins
cmdutil: only output style header once in non-buffered mode (issue2130)
r11441 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)))
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 self.showpatch(ctx.node(), matchfn)
Dirkjan Ochtman
cmdutil: prevent code repetition by abstraction in changeset_templater
r8013
Robert Bachmann
Bugfix and test for hg log XML output
r10160 if types['footer']:
Robert Bachmann
Added support for templatevar "footer" to cmdutil.py
r10152 if not self.footer:
self.footer = templater.stringify(self.t(types['footer'],
**props))
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:
Martin Geisler
cmdutil: do not translate trivial string
r10829 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
Matt Mackall
templates: move changeset templating bits to cmdutils
r3643
Mads Kiilerich
log: follow filenames through renames (issue647)...
r11488 def show_changeset(ui, repo, opts, buffered=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
Yuya Nishihara
log: add --stat for diffstat output...
r11061 if opts.get('patch') or opts.get('stat'):
Matt Mackall
scmutil: drop aliases in cmdutil for match functions
r14322 patch = scmutil.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:
Martin Geisler
templater: handle SyntaxError when parsing ui.logtemplate...
r16678 try:
tmpl = templater.parsestring(tmpl)
except SyntaxError:
tmpl = templater.parsestring(tmpl, quoted=False)
Dirkjan Ochtman
cmdutil: refactor handling of templating in show_changeset()
r7967 else:
Patrick Mezard
cmdutil: expand style paths (issue1948)...
r10249 style = util.expandpath(ui.config('ui', 'style', ''))
Dirkjan Ochtman
cmdutil: refactor handling of templating in show_changeset()
r7967
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))
Matt Mackall
many, many trivial check-code fixups
r10282 if mapname:
mapfile = mapname
Dirkjan Ochtman
cmdutil: refactor handling of templating in show_changeset()
r7967
try:
t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
except SyntaxError, inst:
raise util.Abort(inst.args[0])
Matt Mackall
many, many trivial check-code fixups
r10282 if tmpl:
t.use_template(tmpl)
Dirkjan Ochtman
cmdutil: refactor handling of templating in show_changeset()
r7967 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"""
Dirkjan Ochtman
merge changes from mpm
r9667
mark.williamson@cl.cam.ac.uk
Tweak finddate to pass date directly....
r5836 df = util.matchdate(date)
Matt Mackall
scmutil: drop aliases in cmdutil for match functions
r14322 m = scmutil.matchall(repo)
Matt Mackall
Add --date support to update and revert...
r3814 results = {}
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662
def prep(ctx, fns):
d = ctx.date()
if df(d[0]):
Dirkjan Ochtman
cmdutil: fix bug in finddate() implementation
r9668 results[ctx.rev()] = d
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662
Dirkjan Ochtman
merge changes from mpm
r9667 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662 rev = ctx.rev()
if rev in results:
Martin Geisler
cmdutil: lowercase finddate status message...
r16937 ui.status(_("found revision %s from %s\n") %
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662 (rev, util.datestr(results[rev])))
return str(rev)
Matt Mackall
Add --date support to update and revert...
r3814
raise util.Abort(_("revision matching date not found"))
Patrick Mezard
cmdutil: extract increasing_windows() from walkchangerevs()...
r16776 def increasingwindows(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
Durham Goode
log: move log file walk to its own function...
r19290 class FileWalkError(Exception):
pass
def walkfilerevs(repo, match, follow, revs, fncache):
'''Walks the file history for the matched files.
Returns the changeset revs that are involved in the file history.
Throws FileWalkError if the file history can't be walked using
filelogs alone.
'''
wanted = set()
copies = []
minrev, maxrev = min(revs), max(revs)
def filerevgen(filelog, last):
"""
Only files, no patterns. Check the history of each file.
Examines filelog entries within minrev, maxrev linkrev range
Returns an iterator yielding (linkrev, parentlinkrevs, copied)
tuples in backwards order
"""
cl_count = len(repo)
revs = []
for j in xrange(0, last + 1):
linkrev = filelog.linkrev(j)
if linkrev < minrev:
continue
# only yield rev for which we have the changelog, it can
# happen while doing "hg log" during a pull or commit
if linkrev >= cl_count:
break
parentlinkrevs = []
for p in filelog.parentrevs(j):
if p != nullrev:
parentlinkrevs.append(filelog.linkrev(p))
n = filelog.node(j)
revs.append((linkrev, parentlinkrevs,
follow and filelog.renamed(n)))
return reversed(revs)
def iterfiles():
pctx = repo['.']
for filename in match.files():
if follow:
if filename not in pctx:
raise util.Abort(_('cannot follow file not in parent '
'revision: "%s"') % filename)
yield filename, pctx[filename].filenode()
else:
yield filename, None
for filename_node in copies:
yield filename_node
for file_, node in iterfiles():
filelog = repo.file(file_)
if not len(filelog):
if node is None:
# A zero count may be a directory or deleted file, so
# try to find matching entries on the slow path.
if follow:
raise util.Abort(
_('cannot follow nonexistent file: "%s"') % file_)
raise FileWalkError("Cannot walk via filelog")
else:
continue
if node is None:
last = len(filelog) - 1
else:
last = filelog.rev(node)
# keep track of all ancestors of the file
ancestors = set([filelog.linkrev(last)])
# iterate from latest to oldest revision
for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
if not follow:
if rev > maxrev:
continue
else:
# Note that last might not be the first interesting
# rev to us:
# if the file has been changed after maxrev, we'll
# have linkrev(last) > maxrev, and we still need
# to explore the file graph
if rev not in ancestors:
continue
# XXX insert 1327 fix here
if flparentlinkrevs:
ancestors.update(flparentlinkrevs)
fncache.setdefault(rev, []).append(file_)
wanted.add(rev)
if copied:
copies.append(copied)
return wanted
Matt Mackall
walkchangerevs: drop ui arg
r9665 def walkchangerevs(repo, match, opts, prepare):
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.
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662 This function returns an iterator yielding contexts. Before
yielding each context, the iterator will first call the prepare
function on each context in the window in forward order.'''
Matt Mackall
move walkchangerevs to cmdutils
r3650
follow = opts.get('follow') or opts.get('follow_first')
Pierre-Yves David
clfilter: remove any explicit revision number from default cmdutil range...
r17676 if opts.get('rev'):
revs = scmutil.revrange(repo, opts.get('rev'))
elif follow:
revs = repo.revs('reverse(:.)')
Matt Mackall
move walkchangerevs to cmdutils
r3650 else:
Pierre-Yves David
clfilter: remove any explicit revision number from default cmdutil range...
r17676 revs = list(repo)
revs.reverse()
Matt Mackall
walkchangerevs: allow empty query sets
r11281 if not revs:
return []
Martin Geisler
replace set-like dictionaries with real sets...
r8152 wanted = set()
Matt Mackall
walkchangerevs: pull out matchfn...
r9652 slowpath = match.anypats() or (match.files() and opts.get('removed'))
Matt Mackall
move walkchangerevs to cmdutils
r3650 fncache = {}
Matt Mackall
log: remove caching of all visited revisions (issue3253)...
r16108 change = repo.changectx
Matt Mackall
move walkchangerevs to cmdutils
r3650
Nicolas Dumazet
log: document the different phases in walkchangerevs
r11632 # First step is to fill wanted, the set of revisions that we want to yield.
# When it does not induce extra cost, we also fill fncache for revisions in
# wanted: a cache of filenames that were changed (ctx.files()) and that
# match the file filtering conditions.
Matt Mackall
walkchangerevs: pull out matchfn...
r9652 if not slowpath and not match.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
walkchangerevs: drop ui arg
r9665
Matt Mackall
log: bypass file scan part of fastpath when no files...
r16381 if not slowpath and match.files():
Nicolas Dumazet
log: document the different phases in walkchangerevs
r11632 # We only have to read through the filelog to find wanted revisions
Durham Goode
log: move log file walk to its own function...
r19290 try:
wanted = walkfilerevs(repo, match, follow, revs, fncache)
except FileWalkError:
slowpath = True
Nicolas Dumazet
log: remove increasing windows usage in fastpath...
r11608
Durham Goode
log: move log file walk to its own function...
r19290 # We decided to fall back to the slowpath because at least one
# of the paths was not a file. Check to see if at least one of them
# existed in history, otherwise simply return
smuralid
log: speed up hg log for untracked files (issue1340)...
r17746 for path in match.files():
if path == '.' or path in repo.store:
break
Mads Kiilerich
log: make log work even if first parameter doesn't exist...
r18340 else:
return []
smuralid
log: speed up hg log for untracked files (issue1340)...
r17746
Matt Mackall
move walkchangerevs to cmdutils
r3650 if slowpath:
Nicolas Dumazet
log: document the different phases in walkchangerevs
r11632 # We have to read the changelog to match filenames against
# changed files
Matt Mackall
move walkchangerevs to cmdutils
r3650 if follow:
raise util.Abort(_('can only follow copies/renames for explicit '
timeless
Generally replace "file name" with "filename" in help and comments.
r8761 'filenames'))
Matt Mackall
move walkchangerevs to cmdutils
r3650
# The slow path checks files modified in every changeset.
Durham Goode
log: make file log slow path usable on large repos...
r19730 # This is really slow on large repos, so compute the set lazily.
class lazywantedset(object):
def __init__(self):
self.set = set()
self.revs = set(revs)
# No need to worry about locality here because it will be accessed
# in the same order as the increasing window below.
def __contains__(self, value):
if value in self.set:
return True
elif not value in self.revs:
return False
else:
self.revs.discard(value)
ctx = change(value)
matches = filter(match, ctx.files())
if matches:
fncache[value] = matches
self.set.add(value)
return True
return False
def discard(self, value):
self.revs.discard(value)
self.set.discard(value)
wanted = lazywantedset()
Matt Mackall
move walkchangerevs to cmdutils
r3650
Benoit Boissinot
use new style classes
r8778 class followfilter(object):
Matt Mackall
move walkchangerevs to cmdutils
r3650 def __init__(self, onlyfirst=False):
self.startrev = nullrev
Benoit Boissinot
log --follow: use a set instead of a list...
r10024 self.roots = set()
Matt Mackall
move walkchangerevs to cmdutils
r3650 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:
Benoit Boissinot
log --follow: use a set instead of a list...
r10024 self.roots.add(self.startrev)
Matt Mackall
move walkchangerevs to cmdutils
r3650 for parent in realparents(rev):
if parent in self.roots:
Benoit Boissinot
log --follow: use a set instead of a list...
r10024 self.roots.add(rev)
Matt Mackall
move walkchangerevs to cmdutils
r3650 return True
else:
# backwards: all parents
if not self.roots:
Benoit Boissinot
log --follow: use a set instead of a list...
r10024 self.roots.update(realparents(self.startrev))
Matt Mackall
move walkchangerevs to cmdutils
r3650 if rev in self.roots:
self.roots.remove(rev)
Benoit Boissinot
log --follow: use a set instead of a list...
r10024 self.roots.update(realparents(rev))
Matt Mackall
move walkchangerevs to cmdutils
r3650 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', ()):
Matt Mackall
cmdutil: use context instead of lookup
r16380 rev = repo[rev].rev()
Matt Mackall
move walkchangerevs to cmdutils
r3650 ff = followfilter()
stop = min(revs[0], revs[-1])
Matt Mackall
many, many trivial check-code fixups
r10282 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
Bryan O'Sullivan
cmdutil: use a small initial window with --limit...
r18710 # Choose a small initial window if we will probably only visit a
# few commits.
limit = loglimit(opts)
windowsize = 8
if limit:
windowsize = min(limit, windowsize)
Nicolas Dumazet
log: document the different phases in walkchangerevs
r11632 # Now that wanted is correctly initialized, we can iterate over the
# revision range, yielding only revisions in wanted.
Matt Mackall
move walkchangerevs to cmdutils
r3650 def iterate():
Matt Mackall
walkchangerevs: pull out matchfn...
r9652 if follow and not match.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
Bryan O'Sullivan
cmdutil: use a small initial window with --limit...
r18710 for i, window in increasingwindows(0, len(revs), windowsize):
Matt Mackall
many, many trivial check-code fixups
r10282 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)
Matt Mackall
walkchangerevs: yield contexts
r9654 ctx = change(rev)
Matt Mackall
move walkchangerevs to cmdutils
r3650 if not fns:
def fns_generator():
Matt Mackall
walkchangerevs: yield contexts
r9654 for f in ctx.files():
Matt Mackall
walkchangerevs: pull out matchfn...
r9652 if match(f):
Matt Mackall
move walkchangerevs to cmdutils
r3650 yield f
fns = fns_generator()
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662 prepare(ctx, fns)
Matt Mackall
move walkchangerevs to cmdutils
r3650 for rev in nrevs:
Matt Mackall
walkchangerevs: move 'add' to callback...
r9662 yield change(rev)
Matt Mackall
walkchangerevs: pull out matchfn...
r9652 return iterate()
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 def _makegraphfilematcher(repo, pats, followfirst):
# 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
def _makegraphlogrevset(repo, pats, opts, revs):
"""Return (expr, filematcher) where expr is a revset string built
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.
"""
opt2revset = {
'no_merges': ('not merge()', None),
'only_merges': ('merge()', None),
'_ancestors': ('ancestors(%(val)s)', None),
'_fancestors': ('_firstancestors(%(val)s)', None),
'_descendants': ('descendants(%(val)s)', None),
'_fdescendants': ('_firstdescendants(%(val)s)', None),
'_matchfiles': ('_matchfiles(%(val)s)', None),
'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 '),
}
opts = dict(opts)
# follow or not follow?
follow = opts.get('follow') or opts.get('follow_first')
followfirst = opts.get('follow_first') and 1 or 0
# --follow with FILE behaviour depends on revs...
startrev = revs[0]
followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
# branch and only_branch are really aliases and must be handled at
# the same time
opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
# pats/include/exclude are passed to match.match() directly in
Mads Kiilerich
fix trivial spelling errors
r17424 # _matchfiles() revset but walkchangerevs() builds its matcher with
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 # scmutil.match(). The difference is input pats are globbed on
# platforms without shell expansion (windows).
pctx = repo[None]
match, pats = scmutil.matchandpats(pctx, pats, opts)
slowpath = match.anypats() or (match.files() and opts.get('removed'))
if not slowpath:
for f in match.files():
if follow and f not in pctx:
raise util.Abort(_('cannot follow file not in parent '
'revision: "%s"') % f)
filelog = repo.file(f)
Durham Goode
filelog: switch 'not len(filerevlog)' to 'not filerevlog'...
r19293 if not filelog:
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 # A zero count may be a directory or deleted file, so
# try to find matching entries on the slow path.
if follow:
raise util.Abort(
_('cannot follow nonexistent file: "%s"') % f)
slowpath = True
smuralid
log: speed up hg log for untracked files (issue1340)...
r17746
# We decided to fall back to the slowpath because at least one
# of the paths was not a file. Check to see if at least one of them
# existed in history - in that case, we'll continue down the
# slowpath; otherwise, we can turn off the slowpath
if slowpath:
for path in match.files():
if path == '.' or path in repo.store:
break
else:
slowpath = False
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 if slowpath:
# See walkchangerevs() slow path.
#
if follow:
raise util.Abort(_('can only follow copies/renames for explicit '
'filenames'))
# 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
# "a" and "b" while "file(a) and not file(b)" does
# not. Besides, filesets are evaluated against the working
# directory.
matchargs = ['r:', 'd:relpath']
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)
opts['_matchfiles'] = matchargs
else:
if follow:
fpats = ('_patsfollow', '_patsfollowfirst')
fnopats = (('_ancestors', '_fancestors'),
('_descendants', '_fdescendants'))
if pats:
Mads Kiilerich
fix trivial spelling errors
r17424 # follow() revset interprets its file argument as a
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 # manifest entry, so use match.files(), not pats.
opts[fpats[followfirst]] = list(match.files())
else:
opts[fnopats[followdescendants][followfirst]] = str(startrev)
else:
opts['_patslog'] = list(pats)
filematcher = None
if opts.get('patch') or opts.get('stat'):
if follow:
filematcher = _makegraphfilematcher(repo, pats, followfirst)
else:
filematcher = lambda rev: match
expr = []
for op, val in opts.iteritems():
if not val:
continue
if op not in opt2revset:
continue
revop, andor = opt2revset[op]
if '%(val)' not in revop:
expr.append(revop)
else:
if not isinstance(val, list):
e = revop % {'val': val}
else:
e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
expr.append(e)
if expr:
expr = '(' + ' and '.join(expr) + ')'
else:
expr = None
return expr, filematcher
def getgraphlogrevs(repo, pats, opts):
"""Return (revs, expr, filematcher) where revs is an iterable of
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.
"""
if not len(repo):
Siddharth Agarwal
cmdutil: stop pretending we can calculate revs for graphlog lazily...
r18171 return [], None, None
Siddharth Agarwal
cmdutil: make getgraphlogrevs limit-aware...
r18172 limit = loglimit(opts)
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 # Default --rev value depends on --follow but --follow behaviour
# depends on revisions resolved from --rev...
follow = opts.get('follow') or opts.get('follow_first')
Siddharth Agarwal
cmdutil: make getgraphlogrevs return revs in descending order
r18169 possiblyunsorted = False # whether revs might need sorting
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 if opts.get('rev'):
revs = scmutil.revrange(repo, opts['rev'])
Siddharth Agarwal
cmdutil: make getgraphlogrevs return revs in descending order
r18169 # Don't sort here because _makegraphlogrevset might depend on the
# order of revs
possiblyunsorted = True
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 else:
if follow and len(repo) > 0:
Pierre-Yves David
clfilter: remove any explicit revision number from default cmdutil range...
r17676 revs = repo.revs('reverse(:.)')
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 else:
Pierre-Yves David
clfilter: remove usage of `range` in favor of iteration over changelog...
r17675 revs = list(repo.changelog)
revs.reverse()
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 if not revs:
Siddharth Agarwal
cmdutil: stop pretending we can calculate revs for graphlog lazily...
r18171 return [], None, None
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
Siddharth Agarwal
cmdutil: make getgraphlogrevs return revs in descending order
r18169 if possiblyunsorted:
revs.sort(reverse=True)
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 if expr:
Siddharth Agarwal
cmdutil: stop pretending we can calculate revs for graphlog lazily...
r18171 # Revset matchers often operate faster on revisions in changelog
# order, because most filters deal with the changelog.
revs.reverse()
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 matcher = revset.match(repo.ui, expr)
Siddharth Agarwal
cmdutil: stop pretending we can calculate revs for graphlog lazily...
r18171 # Revset matches can reorder revisions. "A or B" typically returns
# returns the revision matching A then the revision matching B. Sort
# again to fix that.
revs = matcher(repo, revs)
revs.sort(reverse=True)
Pierre-Yves David
log: use "hidden" filtering instead of manual check at display time...
r18243 if limit is not None:
Siddharth Agarwal
cmdutil: make getgraphlogrevs limit-aware...
r18172 revs = revs[:limit]
Patrick Mezard
graphlog: extract revset/support functions into cmdutil
r17180 return revs, expr, filematcher
def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
filematcher=None):
seen, state = [], graphmod.asciistate()
for rev, type, ctx, parents in dag:
char = 'o'
if ctx.node() in showparents:
char = '@'
elif ctx.obsolete():
char = 'x'
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]))
revmatchfn = None
if filematcher is not None:
revmatchfn = filematcher(ctx.rev())
displayer.show(ctx, copies=copies, matchfn=revmatchfn)
lines = displayer.hunk.pop(rev).split('\n')
if not lines[-1]:
del lines[-1]
displayer.flush(rev)
edges = edgefn(type, char, lines, seen, rev, parents)
for type, char, lines, coldata in edges:
graphmod.ascii(ui, state, type, char, lines, coldata)
displayer.close()
Patrick Mezard
log: support --graph without graphlog extension...
r17181 def graphlog(ui, repo, *pats, **opts):
# Parameters are identical to log command ones
revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
revdag = graphmod.dagwalker(repo, revs)
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)
displayer = show_changeset(ui, repo, opts, buffered=True)
showparents = [ctx.node() for ctx in repo[None].parents()]
displaygraph(ui, revdag, displayer, showparents,
graphmod.asciiedges, getrenamed, filematcher)
Patrick Mezard
incoming/outgoing: handle --graph in core
r17182 def checkunsupportedgraphflags(pats, opts):
for op in ["newest_first"]:
if op in opts and opts[op]:
raise util.Abort(_("-G/--graph option is incompatible with --%s")
% op.replace("_", "-"))
def graphrevs(repo, nodes, opts):
limit = loglimit(opts)
nodes.reverse()
if limit is not None:
nodes = nodes[:limit]
return graphmod.nodes(repo, nodes)
David M. Carr
add: fix subrepo recursion for explicit path handling...
r15911 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 join = lambda f: os.path.join(prefix, f)
Martin Geisler
add: move main part to cmdutil to make it easier to reuse
r12269 bad = []
oldbad = match.bad
match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
names = []
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 wctx = repo[None]
Adrian Buehlmann
scmutil: introduce casecollisionauditor...
r14138 cca = None
abort, warn = scmutil.checkportabilityalert(ui)
if abort or warn:
Joshua Redstone
scmutil: 25% speedup in casecollisionauditor...
r17201 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
Martin Geisler
add: move main part to cmdutil to make it easier to reuse
r12269 for f in repo.walk(match):
exact = match.exact(f)
David M. Carr
add: fix subrepo recursion for explicit path handling...
r15911 if exact or not explicitonly and f not in repo.dirstate:
Adrian Buehlmann
scmutil: introduce casecollisionauditor...
r14138 if cca:
cca(f)
Martin Geisler
add: move main part to cmdutil to make it easier to reuse
r12269 names.append(f)
if ui.verbose or not exact:
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 ui.status(_('adding %s\n') % match.rel(join(f)))
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 for subpath in sorted(wctx.substate):
David M. Carr
add: support adding explicit files in subrepos...
r15410 sub = wctx.sub(subpath)
try:
submatch = matchmod.narrowmatcher(subpath, match)
if listsubrepos:
David M. Carr
add: fix subrepo recursion for explicit path handling...
r15911 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
False))
David M. Carr
add: support adding explicit files in subrepos...
r15410 else:
David M. Carr
add: fix subrepo recursion for explicit path handling...
r15911 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
True))
David M. Carr
add: support adding explicit files in subrepos...
r15410 except error.LookupError:
ui.status(_("skipping missing subrepository: %s\n")
% join(subpath))
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270
Martin Geisler
add: move main part to cmdutil to make it easier to reuse
r12269 if not dryrun:
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270 rejected = wctx.add(names, prefix)
Martin Geisler
add: move main part to cmdutil to make it easier to reuse
r12269 bad.extend(f for f in rejected if f in match.files())
return bad
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 def forget(ui, repo, match, prefix, explicitonly):
join = lambda f: os.path.join(prefix, f)
bad = []
oldbad = match.bad
match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
wctx = repo[None]
forgot = []
s = repo.status(match=match, clean=True)
forget = sorted(s[0] + s[1] + s[3] + s[6])
if explicitonly:
forget = [f for f in forget if match.exact(f)]
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 for subpath in sorted(wctx.substate):
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 sub = wctx.sub(subpath)
try:
submatch = matchmod.narrowmatcher(subpath, match)
subbad, subforgot = sub.forget(ui, submatch, prefix)
bad.extend([subpath + '/' + f for f in subbad])
forgot.extend([subpath + '/' + f for f in subforgot])
except error.LookupError:
ui.status(_("skipping missing subrepository: %s\n")
% join(subpath))
FUJIWARA Katsunori
forget: show warning messages for forgetting in subrepo correctly...
r16070 if not explicitonly:
for f in match.files():
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
if f not in forgot:
if os.path.exists(match.rel(join(f))):
ui.warn(_('not removing %s: '
'file is already untracked\n')
% match.rel(join(f)))
bad.append(f)
for f in forget:
if ui.verbose or not match.exact(f):
ui.status(_('removing %s\n') % match.rel(join(f)))
rejected = wctx.forget(forget, prefix)
bad.extend(f for f in rejected if f in match.files())
forgot.extend(forget)
return bad, forgot
Siddharth Agarwal
duplicatecopies: fix arg name and docstring...
r18852 def duplicatecopies(repo, rev, fromrev):
'''reproduce copies from fromrev to rev in the dirstate'''
for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
Siddharth Agarwal
duplicatecopies: do not mark items not in the dirstate as copies...
r18853 # copies.pathcopies returns backward renames, so dst might not
# actually be in the dirstate
if repo.dirstate[dst] in "nma":
repo.dirstate.copy(src, dst)
Matt Mackall
rebase: move updatedirstate into cmdutil so it can be shared
r15214
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)
Idan Kamara
cmdutil, logmessage: use ui.fin when reading from '-'
r14635 message = logmessage(ui, opts)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034
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'):
Matt Mackall
scmutil: drop some aliases in cmdutil
r14321 scmutil.addremove(repo, pats, opts)
Kirill Smelkov
cmdutil.commit: extract 'addremove' from opts carefully...
r5829
Matt Mackall
scmutil: switch match users to supplying contexts...
r14671 return commitfunc(ui, repo, message,
scmutil.match(repo[None], pats, opts), opts)
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407
Idan Kamara
commit: add option to amend the working dir parent...
r16458 def amend(ui, repo, commitfunc, old, extra, pats, opts):
ui.note(_('amending changeset %s\n') % old)
base = old.p1()
Pierre-Yves David
amend: invalidate dirstate in case of failure (issue3670)...
r18197 wlock = lock = newid = None
Idan Kamara
commit: add option to amend the working dir parent...
r16458 try:
Pierre-Yves David
amend: lock the repository during the whole process...
r17471 wlock = repo.wlock()
lock = repo.lock()
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 tr = repo.transaction('amend')
Idan Kamara
amend: disable hooks when creating intermediate commit (issue3501)
r17049 try:
Pierre-Yves David
amend: use an explicit commit message for temporary amending commit...
r17473 # See if we got a message from -m or -l, if not, open the editor
# with the message of the changeset to amend
message = logmessage(ui, opts)
Pierre-Yves David
amend: fix incompatibity between logfile and message option (issue3675)...
r17863 # ensure logfile does not conflict with later enforcement of the
# message. potential logfile content has been processed by
# `logmessage` anyway.
opts.pop('logfile')
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 # First, do a regular commit to record all changes in the working
# directory (if there are any)
ui.callhooks = False
Pierre-Yves David
amend: prevent loss of bookmark on failed amend...
r18198 currentbookmark = repo._bookmarkcurrent
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 try:
Pierre-Yves David
amend: prevent loss of bookmark on failed amend...
r18198 repo._bookmarkcurrent = None
Pierre-Yves David
amend: use an explicit commit message for temporary amending commit...
r17473 opts['message'] = 'temporary amend commit for %s' % old
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 node = commit(ui, repo, commitfunc, pats, opts)
finally:
Pierre-Yves David
amend: prevent loss of bookmark on failed amend...
r18198 repo._bookmarkcurrent = currentbookmark
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 ui.callhooks = True
ctx = repo[node]
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 # Participating changesets:
#
# node/ctx o - new (intermediate) commit that contains changes
# | from working dir to go into amending commit
# | (or a workingctx if there were no changes)
# |
# old o - changeset to amend
# |
# base o - parent of amending changeset
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 # Update extra dict from amended commit (e.g. to preserve graft
# source)
extra.update(old.extra())
Idan Kamara
amend: preserve extra dict (issue3430)
r16630
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 # Also update it from the intermediate commit or from the wctx
extra.update(ctx.extra())
Idan Kamara
amend: preserve extra dict (issue3430)
r16630
Brodie Rao
amend: support amending merge changesets (issue3778)
r18909 if len(old.parents()) > 1:
# ctx.files() isn't reliable for merges, so fall back to the
# slower repo.status() method
files = set([fn for st in repo.status(base, old)[:3]
for fn in st])
else:
files = set(old.files())
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 # Second, we use either the commit we just did, or if there were no
# changes the parent of the working directory as the version of the
# files in the final amend commit
if node:
ui.note(_('copying changeset %s to %s\n') % (ctx, base))
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 user = ctx.user()
date = ctx.date()
# Recompute copies (avoid recording a -> b -> a)
copied = copies.pathcopies(base, ctx)
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 # Prune files which were reverted by the updates: if old
# introduced file X and our intermediate commit, node,
# renamed that file, then those two files are the same and
# we can discard X from our list of files. Likewise if X
# was deleted, it's no longer relevant
files.update(ctx.files())
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 def samefile(f):
if f in ctx.manifest():
a = ctx.filectx(f)
if f in base.manifest():
b = base.filectx(f)
return (not a.cmp(b)
and a.flags() == b.flags())
else:
return False
Idan Kamara
commit: add option to amend the working dir parent...
r16458 else:
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 return f not in base.manifest()
files = [f for f in files if not samefile(f)]
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 def filectxfn(repo, ctx_, path):
try:
fctx = ctx[path]
flags = fctx.flags()
mctx = context.memfilectx(fctx.path(), fctx.data(),
islink='l' in flags,
isexec='x' in flags,
copied=copied.get(path))
return mctx
except KeyError:
raise IOError
else:
ui.note(_('copying changeset %s to %s\n') % (old, base))
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 # Use version of files as in the old cset
def filectxfn(repo, ctx_, path):
try:
return old.filectx(path)
except KeyError:
raise IOError
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 user = opts.get('user') or old.user()
date = opts.get('date') or old.date()
Pierre-Yves David
amend: force editor only if old message is reused (issue3698)...
r17924 editmsg = False
Pierre-Yves David
amend: use an explicit commit message for temporary amending commit...
r17473 if not message:
Pierre-Yves David
amend: force editor only if old message is reused (issue3698)...
r17924 editmsg = True
Pierre-Yves David
amend: use an explicit commit message for temporary amending commit...
r17473 message = old.description()
Idan Kamara
commit: add option to amend the working dir parent...
r16458
Pierre-Yves David
amend: add noise in extra to avoid creating obsolescence cycle (issue3664)...
r17811 pureextra = extra.copy()
extra['amend_source'] = old.hex()
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 new = context.memctx(repo,
Brodie Rao
amend: support amending merge changesets (issue3778)
r18909 parents=[base.node(), old.p2().node()],
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 text=message,
files=files,
filectxfn=filectxfn,
user=user,
date=date,
extra=extra)
Pierre-Yves David
amend: force editor only if old message is reused (issue3698)...
r17924 if editmsg:
new._text = commitforceeditor(repo, new, [])
Pierre-Yves David
amend: add noise in extra to avoid creating obsolescence cycle (issue3664)...
r17811
newdesc = changelog.stripdesc(new.description())
if ((not node)
and newdesc == old.description()
and user == old.user()
and date == old.date()
and pureextra == old.extra()):
# nothing changed. continuing here would create a new node
# anyway because of the amend_source noise.
#
# This not what we expect from amend.
return old.node()
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 ph = repo.ui.config('phases', 'new-commit', phases.draft)
try:
repo.ui.setconfig('phases', 'new-commit', old.phase())
newid = repo.commitctx(new)
finally:
repo.ui.setconfig('phases', 'new-commit', ph)
if newid != old.node():
# Reroute the working copy parent to the new changeset
repo.setparents(newid, nullid)
# Move bookmarks from old parent to amend commit
bms = repo.nodebookmarks(old.node())
if bms:
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 marks = repo._bookmarks
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 for bm in bms:
Augie Fackler
bookmarks: introduce a bmstore to manage bookmark persistence...
r17922 marks[bm] = newid
marks.write()
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 #commit the whole amend process
Pierre-Yves David
amend: add obsolete support...
r17475 if obsolete._enabled and newid != old.node():
# mark the new changeset as successor of the rewritten one
new = repo[newid]
obs = [(old, (new,))]
if node:
Pierre-Yves David
amend: do a bare kill of temporary changeset...
r17812 obs.append((ctx, ()))
Pierre-Yves David
amend: add obsolete support...
r17475
obsolete.createmarkers(repo, obs)
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 tr.close()
Pierre-Yves David
amend: preserve phase of amended revision (issue3602)...
r17461 finally:
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 tr.release()
Pierre-Yves David
amend: add obsolete support...
r17475 if (not obsolete._enabled) and newid != old.node():
# Strip the intermediate commit (if there was one) and the amended
# commit
Pierre-Yves David
amend: lock the repository during the whole process...
r17471 if node:
ui.note(_('stripping intermediate changeset %s\n') % ctx)
ui.note(_('stripping amended changeset %s\n') % old)
repair.strip(ui, repo, old.node(), topic='amend-backup')
Idan Kamara
commit: add option to amend the working dir parent...
r16458 finally:
Pierre-Yves David
amend: invalidate dirstate in case of failure (issue3670)...
r18197 if newid is None:
repo.dirstate.invalidate()
Mads Kiilerich
amend: fix unlocking order - first lock then wlock
r19024 lockmod.release(lock, wlock)
Idan Kamara
commit: add option to amend the working dir parent...
r16458 return newid
Matt Mackall
commit: report modified subrepos in commit editor
r8994 def commiteditor(repo, ctx, subs):
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 if ctx.description():
return ctx.description()
Matt Mackall
commit: report modified subrepos in commit editor
r8994 return commitforceeditor(repo, ctx, subs)
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407
Matt Mackall
commit: report modified subrepos in commit editor
r8994 def commitforceeditor(repo, ctx, subs):
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 edittext = []
Matt Mackall
commit: editor reads file lists from provided context
r8707 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 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():
Matt Mackall
branch: operate on branch names in local string space where possible...
r13047 edittext.append(_("HG: branch '%s'") % ctx.branch())
Antonio Zanardo
commit: show active bookmark in commit editor helper text...
r18538 if bookmarks.iscurrent(repo):
edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
Matt Mackall
commit: report modified subrepos in commit editor
r8994 edittext.extend([_("HG: subrepo %s") % s for s in subs])
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 edittext.extend([_("HG: added %s") % f for f in added])
Matt Mackall
commit: editor reads file lists from provided context
r8707 edittext.extend([_("HG: changed %s") % f for f in modified])
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 edittext.extend([_("HG: removed %s") % f for f in removed])
Matt Mackall
commit: editor reads file lists from provided context
r8707 if not added and not modified and not removed:
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 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
commit: handle missing newline on last commit comment
r12900 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
Adrian Buehlmann
commands: use a decorator to build table incrementally...
r14297
Kevin Bullock
commit: factor out status printing into a helper function...
r18688 def commitstatus(repo, node, branch, bheads=None, opts={}):
ctx = repo[node]
parents = ctx.parents()
if (not opts.get('amend') and bheads and node not in bheads and not
[x for x in parents if x.node() in bheads and x.branch() == branch]):
repo.ui.status(_('created new head\n'))
# The message is not printed for initial roots. For the other
# changesets, it is printed in the following situations:
#
# Par column: for the 2 parents with ...
# N: null or no parent
# B: parent is on another named branch
# C: parent is a regular non head changeset
# H: parent was a branch head of the current branch
# Msg column: whether we print "created new head" message
# In the following, it is assumed that there already exists some
# initial branch heads of the current branch, otherwise nothing is
# printed anyway.
#
# Par Msg Comment
# N N y additional topo root
#
# B N y additional branch root
# C N y additional topo head
# H N n usual case
#
# B B y weird additional branch root
# C B y branch merge
# H B n merge with named branch
#
# C C y additional head from merge
# C H n merge with a head
#
# H H n head merge: head count decreases
if not opts.get('close_branch'):
for r in parents:
if r.closesbranch() and r.branch() == branch:
repo.ui.status(_('reopening closed branch head %d\n') % r)
if repo.ui.debugflag:
repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
elif repo.ui.verbose:
repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 def revert(ui, repo, ctx, parents, *pats, **opts):
parent, p2 = parents
node = ctx.node()
mf = ctx.manifest()
if node == parent:
pmf = mf
else:
pmf = None
# need all matching names in dirstate and manifest of target rev,
# so have to walk both. do not print errors if files exist in one
# but not other.
names = {}
wlock = repo.wlock()
try:
# walk dirstate.
m = scmutil.match(repo[None], pats, opts)
m.bad = lambda x, y: False
for abs in repo.walk(m):
names[abs] = m.rel(abs), m.exact(abs)
# walk target manifest.
def badfn(path, msg):
if path in names:
return
Kevin Bullock
revert: don't re-create changeset context
r16583 if path in ctx.substate:
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 return
path_ = path + '/'
for f in names:
if f.startswith(path_):
return
ui.warn("%s: %s\n" % (m.rel(path), msg))
Kevin Bullock
revert: don't re-create changeset context
r16583 m = scmutil.match(ctx, pats, opts)
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 m.bad = badfn
Kevin Bullock
revert: don't re-create changeset context
r16583 for abs in ctx.walk(m):
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 if abs not in names:
names[abs] = m.rel(abs), m.exact(abs)
Angel Ezquerra
revert: add support for reverting subrepos without --no-backup and/or --all...
r16430 # get the list of subrepos that must be reverted
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 targetsubs = sorted(s for s in ctx.substate if m(s))
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 m = scmutil.matchfiles(repo, names)
changes = repo.status(match=m)[:4]
modified, added, removed, deleted = map(set, changes)
# if f is a rename, also revert the source
cwd = repo.getcwd()
for f in added:
src = repo.dirstate.copied(f)
if src and src not in names and repo.dirstate[src] == 'r':
removed.add(src)
names[src] = (repo.pathto(src, cwd), True)
def removeforget(abs):
if repo.dirstate[abs] == 'a':
return _('forgetting %s\n')
return _('removing %s\n')
revert = ([], _('reverting %s\n'))
add = ([], _('adding %s\n'))
remove = ([], removeforget)
undelete = ([], _('undeleting %s\n'))
disptable = (
# dispatch table:
# file state
# action if in target manifest
# action if not in target manifest
# make backup if in target manifest
# make backup if not in target manifest
(modified, revert, remove, True, True),
(added, revert, remove, True, False),
Matt Mackall
revert: make backup when unforgetting a file (issue3423)...
r19510 (removed, undelete, None, True, False),
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 (deleted, revert, remove, False, False),
)
for abs, (rel, exact) in sorted(names.items()):
mfentry = mf.get(abs)
target = repo.wjoin(abs)
def handle(xlist, dobackup):
xlist[0].append(abs)
if (dobackup and not opts.get('no_backup') and
Matt Mackall
revert: make backup when unforgetting a file (issue3423)...
r19510 os.path.lexists(target) and
Matt Mackall
revert: fix largefiles breakage
r19511 abs in ctx and repo[None][abs].cmp(ctx[abs])):
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 bakname = "%s.orig" % rel
ui.note(_('saving current version of %s as %s\n') %
(rel, bakname))
if not opts.get('dry_run'):
util.rename(target, bakname)
if ui.verbose or not exact:
msg = xlist[1]
if not isinstance(msg, basestring):
msg = msg(abs)
ui.status(msg % rel)
for table, hitlist, misslist, backuphit, backupmiss in disptable:
if abs not in table:
continue
# file has changed in dirstate
if mfentry:
handle(hitlist, backuphit)
elif misslist is not None:
handle(misslist, backupmiss)
break
else:
if abs not in repo.dirstate:
if mfentry:
handle(add, True)
elif exact:
ui.warn(_('file not managed: %s\n') % rel)
continue
# file has not changed in dirstate
if node == parent:
if exact:
ui.warn(_('no changes needed to %s\n') % rel)
continue
if pmf is None:
# only need parent manifest in this unlikely case,
# so do not read by default
pmf = repo[parent].manifest()
if abs in pmf and mfentry:
# if version of file is same in parent and target
# manifests, do nothing
if (pmf[abs] != mfentry or
pmf.flags(abs) != mf.flags(abs)):
handle(revert, False)
else:
handle(remove, False)
if not opts.get('dry_run'):
def checkout(f):
fc = ctx[f]
repo.wwrite(f, fc.data(), fc.flags())
audit_path = scmutil.pathauditor(repo.root)
for f in remove[0]:
if repo.dirstate[f] == 'a':
repo.dirstate.drop(f)
continue
audit_path(f)
try:
util.unlinkpath(repo.wjoin(f))
except OSError:
pass
repo.dirstate.remove(f)
normal = None
if node == parent:
# We're reverting to our parent. If possible, we'd like status
# to report the file as clean. We have to use normallookup for
# merges to avoid losing information about merged/dirty files.
if p2 != nullid:
normal = repo.dirstate.normallookup
else:
normal = repo.dirstate.normal
for f in revert[0]:
checkout(f)
if normal:
normal(f)
for f in add[0]:
checkout(f)
repo.dirstate.add(f)
normal = repo.dirstate.normallookup
if node == parent and p2 == nullid:
normal = repo.dirstate.normal
for f in undelete[0]:
checkout(f)
normal(f)
Bryan O'Sullivan
revert: ensure that copies and renames are honored (issue3920)...
r19129 copied = copies.pathcopies(repo[parent], ctx)
for f in add[0] + undelete[0] + revert[0]:
if f in copied:
repo.dirstate.copy(copied[f], f)
Angel Ezquerra
revert: add support for reverting subrepos...
r16429 if targetsubs:
# Revert the subrepos on the revert list
for sub in targetsubs:
ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 finally:
wlock.release()
Adrian Buehlmann
commands: use a decorator to build table incrementally...
r14297 def command(table):
'''returns a function object bound to table which can be used as
a decorator for populating table as a command table'''
Pierre-Yves David
cmdutil: make options argument optional...
r18235 def cmd(name, options=(), synopsis=None):
Adrian Buehlmann
commands: use a decorator to build table incrementally...
r14297 def decorator(func):
if synopsis:
Pierre-Yves David
cmdutil: make options argument optional...
r18235 table[name] = func, list(options), synopsis
Adrian Buehlmann
commands: use a decorator to build table incrementally...
r14297 else:
Pierre-Yves David
cmdutil: make options argument optional...
r18235 table[name] = func, list(options)
Adrian Buehlmann
commands: use a decorator to build table incrementally...
r14297 return func
return decorator
return cmd
Bryan O'Sullivan
summary: augment output with info from extensions
r19211
# a list of (ui, repo) functions called by commands.summary
summaryhooks = util.hooks()
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474
# A list of state files kept by multistep operations like graft.
# Since graft cannot be aborted, it is considered 'clearable' by update.
# note: bisect is intentionally excluded
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 # (state file, clearable, allowcommit, error, hint)
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474 unfinishedstates = [
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 ('graftstate', True, False, _('graft in progress'),
Matt Mackall
update: add tracking of interrupted updates (issue3113)...
r19482 _("use 'hg graft --continue' or 'hg update' to abort")),
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 ('updatestate', True, False, _('last update was interrupted'),
Matt Mackall
update: add tracking of interrupted updates (issue3113)...
r19482 _("use 'hg update' to get a consistent checkout"))
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474 ]
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 def checkunfinished(repo, commit=False):
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474 '''Look for an unfinished multistep operation, like graft, and abort
if found. It's probably good to check this right before
bailifchanged().
'''
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 for f, clearable, allowcommit, msg, hint in unfinishedstates:
if commit and allowcommit:
continue
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474 if repo.vfs.exists(f):
raise util.Abort(msg, hint=hint)
def clearunfinished(repo):
'''Check for unfinished operations (as above), and clear the ones
that are clearable.
'''
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 for f, clearable, allowcommit, msg, hint in unfinishedstates:
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474 if not clearable and repo.vfs.exists(f):
raise util.Abort(msg, hint=hint)
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 for f, clearable, allowcommit, msg, hint in unfinishedstates:
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474 if clearable and repo.vfs.exists(f):
util.unlink(repo.join(f))