##// END OF EJS Templates
templatekw: alias {name} of file copies dict to {path}...
templatekw: alias {name} of file copies dict to {path} For the same reason as the previous patch. We might want some hack to support {source.path}, {source.rev}, etc., but that's a different issue.

File last commit:

r39386:5b92a717 default
r39404:5b1d406b default
Show More
cmdutil.py
3297 lines | 118.4 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
Gregory Szorc
cmdutil: use absolute_import...
r28322 from __future__ import absolute_import
import errno
import os
import re
from .i18n import _
from .node import (
hex,
nullid,
nullrev,
short,
)
from . import (
bookmarks,
changelog,
copies,
crecord as crecordmod,
Martin von Zweigbergk
commit: don't let failed commit with --addremove update dirstate (issue5645)...
r33619 dirstateguard,
Gregory Szorc
cmdutil: use absolute_import...
r28322 encoding,
error,
formatter,
Yuya Nishihara
cmdutil: split functions of log-like commands to new module (API)...
r35903 logcmdutil,
Gregory Szorc
cmdutil: use absolute_import...
r28322 match as matchmod,
Yuya Nishihara
merge: cut import cycle at merge -> extensions...
r36027 merge as mergemod,
Yuya Nishihara
amend: abort if unresolved merge conflicts found (issue5805)...
r36927 mergeutil,
Gregory Szorc
cmdutil: use absolute_import...
r28322 obsolete,
patch,
pathutil,
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 phases,
Pulkit Goyal
py3: use pycompat.getcwd() instead of os.getcwd()...
r30519 pycompat,
Gregory Szorc
cmdutil: use absolute_import...
r28322 revlog,
Pulkit Goyal
branch: add a --rev flag to change branch name of given revisions...
r35763 rewriteutil,
Gregory Szorc
cmdutil: use absolute_import...
r28322 scmutil,
Yuya Nishihara
revset: import set classes directly from smartset module...
r31023 smartset,
Yuya Nishihara
subrepo: split non-core functions to new module...
r36026 subrepoutil,
Gregory Szorc
cmdutil: use absolute_import...
r28322 templatekw,
templater,
util,
Pierre-Yves David
vfs: use 'vfs' module directly in 'mercurial.cmdutil'...
r31237 vfs as vfsmod,
Gregory Szorc
cmdutil: use absolute_import...
r28322 )
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102
from .utils import (
dateutil,
stringutil,
)
timeless
pycompat: switch to util.stringio for py3 compat
r28861 stringio = util.stringio
Vadim Gelfer
refactor text diff/patch code....
r2874
Yuya Nishihara
commands: move templates of common command options to cmdutil (API)...
r32375 # templates of common command options
dryrunopts = [
('n', 'dry-run', None,
_('do not perform actions, just print output')),
]
Sushil khanchi
rebase: add --confirm option...
r38689 confirmopts = [
('', 'confirm', None,
_('ask before applying actions')),
]
Yuya Nishihara
commands: move templates of common command options to cmdutil (API)...
r32375 remoteopts = [
('e', 'ssh', '',
_('specify ssh command to use'), _('CMD')),
('', 'remotecmd', '',
_('specify hg command to run on the remote side'), _('CMD')),
('', 'insecure', None,
_('do not verify server certificate (ignoring web.cacerts config)')),
]
walkopts = [
('I', 'include', [],
_('include names matching the given patterns'), _('PATTERN')),
('X', 'exclude', [],
_('exclude names matching the given patterns'), _('PATTERN')),
]
commitopts = [
('m', 'message', '',
_('use text as commit message'), _('TEXT')),
('l', 'logfile', '',
_('read commit message from file'), _('FILE')),
]
commitopts2 = [
('d', 'date', '',
_('record the specified date as commit date'), _('DATE')),
('u', 'user', '',
_('record the specified user as committer'), _('USER')),
]
# hidden for now
formatteropts = [
('T', 'template', '',
_('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
]
templateopts = [
('', 'style', '',
_('display using template map file (DEPRECATED)'), _('STYLE')),
('T', 'template', '',
_('display with template'), _('TEMPLATE')),
]
logopts = [
('p', 'patch', None, _('show patch')),
('g', 'git', None, _('use git extended diff format')),
('l', 'limit', '',
_('limit number of changes displayed'), _('NUM')),
('M', 'no-merges', None, _('do not show merges')),
('', 'stat', None, _('output diffstat-style summary of changes')),
('G', 'graph', None, _("show the revision DAG")),
] + templateopts
diffopts = [
('a', 'text', None, _('treat all files as text')),
('g', 'git', None, _('use git extended diff format')),
('', 'binary', None, _('generate binary diffs in git mode (default)')),
('', 'nodates', None, _('omit dates from diff headers'))
]
diffwsopts = [
('w', 'ignore-all-space', None,
_('ignore white space when comparing lines')),
('b', 'ignore-space-change', None,
_('ignore changes in the amount of white space')),
('B', 'ignore-blank-lines', None,
_('ignore changes whose lines are all blank')),
David Soria Parra
mdiff: add a --ignore-space-at-eol option...
r34015 ('Z', 'ignore-space-at-eol', None,
_('ignore changes in whitespace at EOL')),
Yuya Nishihara
commands: move templates of common command options to cmdutil (API)...
r32375 ]
diffopts2 = [
('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
('p', 'show-function', None, _('show which function each change is in')),
('', 'reverse', None, _('produce a diff that undoes the changes')),
] + diffwsopts + [
('U', 'unified', '',
_('number of lines of context to show'), _('NUM')),
('', 'stat', None, _('output diffstat-style summary of changes')),
('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
]
mergetoolopts = [
('t', 'tool', '', _('specify merge tool')),
]
similarityopts = [
('s', 'similarity', '',
_('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
]
subrepoopts = [
('S', 'subrepos', None,
_('recurse into subrepositories'))
]
debugrevlogopts = [
('c', 'changelog', False, _('open changelog')),
('m', 'manifest', False, _('open manifest')),
('', 'dir', '', _('open directory manifest')),
]
Sean Farley
cmdutil: add special string that ignores rest of text...
r30703 # special string such that everything below this line will be ingored in the
# editor text
_linebelow = "^HG: ------------------------ >8 ------------------------$"
Laurent Charignon
record: extract ishunk to a function...
r25256 def ishunk(x):
hunkclasses = (crecordmod.uihunk, patch.recordhunk)
return isinstance(x, hunkclasses)
Laurent Charignon
record: extract code to compute newly added and modified files...
r25257 def newandmodified(chunks, originalchunks):
newlyaddedandmodifiedfiles = set()
for chunk in chunks:
if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
originalchunks:
newlyaddedandmodifiedfiles.add(chunk.header.filename())
return newlyaddedandmodifiedfiles
Brendan Cully
mq: add -Q option to all commands not in norepo
r10401 def parsealiases(cmd):
return cmd.lstrip("^").split("|")
Laurent Charignon
record: consolidate ui.write wrapping in a function
r24356 def setupwrapcolorwrite(ui):
# wrap ui.write so diff output can be labeled/colorized
def wrapwrite(orig, *args, **kw):
Pulkit Goyal
py3: handle keyword arguments correctly in cmdutil.py...
r35351 label = kw.pop(r'label', '')
Laurent Charignon
record: consolidate ui.write wrapping in a function
r24356 for chunk, l in patch.difflabel(lambda: args):
orig(chunk, label=label + l)
oldwrite = ui.write
def wrap(*args, **kwargs):
return wrapwrite(oldwrite, *args, **kwargs)
setattr(ui, 'write', wrap)
return oldwrite
Laurent Charignon
record: add an operation arguments to customize recording ui...
r25310 def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
Kyle Lippincott
crecord: fallback to text mode if diffs are too big for curses mode...
r38058 try:
if usecurses:
if testfile:
recordfn = crecordmod.testdecorator(
testfile, crecordmod.testchunkselector)
else:
recordfn = crecordmod.chunkselector
return crecordmod.filterpatch(ui, originalhunks, recordfn,
operation)
except crecordmod.fallbackerror as e:
ui.warn('%s\n' % e.message)
ui.warn(_('falling back to text mode\n'))
return patch.filterpatch(ui, originalhunks, operation)
Laurent Charignon
record: add an operation arguments to customize recording ui...
r25310
def recordfilter(ui, originalhunks, operation=None):
""" Prompts the user to filter the originalhunks and return a list of
selected hunks.
Denis Laxalde
patch: define full messages for interactive record/revert...
r29326 *operation* is used for to build ui messages to indicate the user what
kind of filtering they are doing: reverting, committing, shelving, etc.
(see patch.filterpatch).
Laurent Charignon
record: add an operation arguments to customize recording ui...
r25310 """
Sean Farley
cmdutil: use crecordmod.checkcurses...
r27531 usecurses = crecordmod.checkcurses(ui)
Jun Wu
codemod: register core configitems using a script...
r33499 testfile = ui.config('experimental', 'crecordtest')
Laurent Charignon
record: move ui.write wrapping where it should be...
r24358 oldwrite = setupwrapcolorwrite(ui)
try:
Laurent Charignon
commit: add a way to return more information from the chunkselector...
r27155 newchunks, newopts = filterchunks(ui, originalhunks, usecurses,
testfile, operation)
Laurent Charignon
record: move ui.write wrapping where it should be...
r24358 finally:
ui.write = oldwrite
Laurent Charignon
commit: add a way to return more information from the chunkselector...
r27155 return newchunks, newopts
Laurent Charignon
record: refactor the filtering code
r24357
Laurent Charignon
record: change interface of dorecord to accept new filters...
r24309 def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
filterfn, *pats, **opts):
Pulkit Goyal
py3: convert opts to bytes in cmdutil.dorecord()...
r32144 opts = pycompat.byteskwargs(opts)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 if not ui.interactive():
FUJIWARA Katsunori
cmdutil: allow callers of cmdutil.dorecord to omit suggestion...
r25795 if cmdsuggest:
msg = _('running non-interactively, use %s instead') % cmdsuggest
else:
msg = _('running non-interactively')
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(msg)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272
# make sure username is set before going interactive
if not opts.get('user'):
ui.username() # raise exception, username not provided
def recordfunc(ui, repo, message, match, opts):
"""This is generic record driver.
Its job is to interactively filter local changes, and
accordingly prepare working directory into a state in which the
job can be delegated to a non-interactive commit command such as
'commit' or 'qrefresh'.
After the actual job is done by non-interactive command, the
working directory is restored to its original state.
In the end we'll record interesting changes, and everything else
will be left in place, so the user can continue working.
"""
checkunfinished(repo, commit=True)
timeless
crecord: check for untracked arguments...
r28815 wctx = repo[None]
merge = len(wctx.parents()) > 1
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 if merge:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('cannot partially commit a merge '
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 '(use "hg commit" instead)'))
timeless
crecord: check for untracked arguments...
r28815 def fail(f, msg):
raise error.Abort('%s: %s' % (f, msg))
force = opts.get('force')
if not force:
vdirs = []
match.explicitdir = vdirs.append
match.bad = fail
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 status = repo.status(match=match)
timeless
crecord: check for untracked arguments...
r28815 if not force:
repo.checkcommitpatterns(wctx, vdirs, match, status, fail)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 diffopts = patch.difffeatureopts(ui, opts=opts, whitespace=True)
diffopts.nodates = True
diffopts.git = True
timeless
record: turn on showfunc...
r27411 diffopts.showfunc = True
timeless
cleanup: remove superfluous space after space after equals (python)
r27637 originaldiff = patch.diff(repo, changes=status, opts=diffopts)
Laurent Charignon
record: change interface of the filtering function...
r24341 originalchunks = patch.parsepatch(originaldiff)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272
Jordi Gutiérrez Hermoso
crecord: rewrite a comment about filtering patches...
r28570 # 1. filter patch, since we are intending to apply subset of it
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 try:
Laurent Charignon
commit: add a way to return more information from the chunkselector...
r27155 chunks, newopts = filterfn(ui, originalchunks)
Yuya Nishihara
error: move patch.PatchError so it can easily implement __bytes__ (API)
r34252 except error.PatchError as err:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('error parsing patch: %s') % err)
Laurent Charignon
commit: add a way to return more information from the chunkselector...
r27155 opts.update(newopts)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272
Laurent Charignon
record: edit patch of newly added files (issue4304)...
r24845 # We need to keep a backup of files that have been newly added and
# modified during the recording process because there is a previous
# version without the edit in the workdir
Laurent Charignon
record: extract code to compute newly added and modified files...
r25257 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 contenders = set()
for h in chunks:
try:
contenders.update(set(h.files()))
except AttributeError:
pass
changed = status.modified + status.added + status.removed
newfiles = [f for f in changed if f in contenders]
if not newfiles:
ui.status(_('no changes to record\n'))
return 0
modified = set(status.modified)
# 2. backup changed files, so we can restore them in the end
if backupall:
tobackup = changed
else:
Laurent Charignon
record: edit patch of newly added files (issue4304)...
r24845 tobackup = [f for f in newfiles if f in modified or f in \
newlyaddedandmodifiedfiles]
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 backups = {}
if tobackup:
Pierre-Yves David
cmdutil: directly use repo.vfs.join...
r31320 backupdir = repo.vfs.join('record-backups')
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 try:
os.mkdir(backupdir)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as err:
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 if err.errno != errno.EEXIST:
raise
try:
# backup continues
for f in tobackup:
Yuya Nishihara
py3: wrap tempfile.mkstemp() to use bytes path...
r38182 fd, tmpname = pycompat.mkstemp(prefix=f.replace('/', '_') + '.',
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 dir=backupdir)
os.close(fd)
ui.debug('backup %r as %r\n' % (f, tmpname))
Siddharth Agarwal
record: don't dereference symlinks while copying over stat data...
r27370 util.copyfile(repo.wjoin(f), tmpname, copystat=True)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 backups[f] = tmpname
timeless
pycompat: switch to util.stringio for py3 compat
r28861 fp = stringio()
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 for c in chunks:
fname = c.filename()
Laurent Charignon
record: fix record with change on moved file crashes (issue4619)...
r24837 if fname in backups:
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 c.write(fp)
dopatch = fp.tell()
fp.seek(0)
Jordi Gutiérrez Hermoso
crecord: re-enable reviewing a patch before comitting it...
r28638 # 2.5 optionally review / modify patch in text editor
if opts.get('review', False):
patchtext = (crecordmod.diffhelptext
+ crecordmod.patchhelptext
+ fp.read())
reviewedpatch = ui.edit(patchtext, "",
Michael Bolin
editor: use an unambiguous path suffix for editor files...
r34030 action="diff",
Sean Farley
ui: rename tmpdir parameter to more specific repopath...
r30848 repopath=repo.path)
Jordi Gutiérrez Hermoso
crecord: re-enable reviewing a patch before comitting it...
r28638 fp.truncate(0)
fp.write(reviewedpatch)
fp.seek(0)
Laurent Charignon
record: fix adding new file with record from within a subdir (issue4626)...
r24866 [os.unlink(repo.wjoin(c)) for c in newlyaddedandmodifiedfiles]
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 # 3a. apply filtered patch to clean repo (clean)
if backups:
# Equivalent to hg.revert
Augie Fackler
merge: have merge.update use a matcher instead of partial fn...
r27344 m = scmutil.matchfiles(repo, backups.keys())
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 mergemod.update(repo, repo.dirstate.p1(),
Augie Fackler
merge: have merge.update use a matcher instead of partial fn...
r27344 False, True, matcher=m)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272
# 3b. (apply)
if dopatch:
try:
ui.debug('applying patch\n')
ui.debug(fp.getvalue())
patch.internalpatch(ui, repo, fp, 1, eolmode=None)
Yuya Nishihara
error: move patch.PatchError so it can easily implement __bytes__ (API)
r34252 except error.PatchError as err:
Pulkit Goyal
py3: use pycompat.bytestr instead of str...
r36736 raise error.Abort(pycompat.bytestr(err))
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 del fp
# 4. We prepared working directory according to filtered
# patch. Now is the time to delegate the job to
# commit/qrefresh or the like!
# Make all of the pathnames absolute.
newfiles = [repo.wjoin(nf) for nf in newfiles]
Pulkit Goyal
py3: handle keyword arguments correctly in cmdutil.py...
r35351 return commitfunc(ui, repo, *newfiles, **pycompat.strkwargs(opts))
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 finally:
# 5. finally restore backed-up files
try:
FUJIWARA Katsunori
cmdutil: apply dirstate.normallookup on (maybe partially) committed files...
r25759 dirstate = repo.dirstate
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 for realname, tmpname in backups.iteritems():
ui.debug('restoring %r to %r\n' % (tmpname, realname))
FUJIWARA Katsunori
cmdutil: apply dirstate.normallookup on (maybe partially) committed files...
r25759
if dirstate[realname] == 'n':
# without normallookup, restoring timestamp
# may cause partially committed files
# to be treated as unmodified
dirstate.normallookup(realname)
Siddharth Agarwal
record: don't dereference symlinks while copying over stat data...
r27370 # copystat=True here and above are a hack to trick any
# editors that have f open that we haven't modified them.
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 #
Siddharth Agarwal
record: don't dereference symlinks while copying over stat data...
r27370 # Also note that this racy as an editor could notice the
# file's mtime before we've finished writing it.
util.copyfile(tmpname, repo.wjoin(realname), copystat=True)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272 os.unlink(tmpname)
if tobackup:
os.rmdir(backupdir)
except OSError:
pass
FUJIWARA Katsunori
cmdutil: put recordfunc invocation into wlock scope for consistency...
r25758 def recordinwlock(ui, repo, message, match, opts):
Bryan O'Sullivan
with: use context manager for wlock in recordinwlock
r27801 with repo.wlock():
FUJIWARA Katsunori
cmdutil: put recordfunc invocation into wlock scope for consistency...
r25758 return recordfunc(ui, repo, message, match, opts)
return commit(ui, repo, recordinwlock, pats, opts)
Laurent Charignon
record: move dorecord from record to cmdutil...
r24272
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683 class dirnode(object):
Pulkit Goyal
status: add a flag to terse the output (issue4119)...
r33548 """
Denis Laxalde
tersestatus: rework dirnode and tersedir docstrings...
r34699 Represent a directory in user working copy with information required for
the purpose of tersing its status.
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
Matt Harbison
cmdutil: use internal separators when building the terse list...
r38221 path is the path to the directory, without a trailing '/'
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
statuses is a set of statuses of all files in this directory (this includes
all the files in all the subdirectories too)
files is a list of files which are direct child of this directory
subdirs is a dictionary of sub-directory name as the key and it's own
dirnode object as the value
"""
def __init__(self, dirpath):
self.path = dirpath
self.statuses = set([])
self.files = []
self.subdirs = {}
def _addfileindir(self, filename, status):
Denis Laxalde
tersestatus: rework dirnode and tersedir docstrings...
r34699 """Add a file in this directory as a direct child."""
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683 self.files.append((filename, status))
def addfile(self, filename, status):
Pulkit Goyal
status: add a flag to terse the output (issue4119)...
r33548 """
Denis Laxalde
tersestatus: rework dirnode and tersedir docstrings...
r34699 Add a file to this directory or to its direct parent directory.
If the file is not direct child of this directory, we traverse to the
directory of which this file is a direct child of and add the file
there.
Pulkit Goyal
status: add a flag to terse the output (issue4119)...
r33548 """
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
# the filename contains a path separator, it means it's not the direct
# child of this directory
Matt Harbison
terse: split on repo separator instead of os.sep (issue5715)...
r34929 if '/' in filename:
subdir, filep = filename.split('/', 1)
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
# does the dirnode object for subdir exists
if subdir not in self.subdirs:
Matt Harbison
cmdutil: use internal separators when building the terse list...
r38221 subdirpath = pathutil.join(self.path, subdir)
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683 self.subdirs[subdir] = dirnode(subdirpath)
# try adding the file in subdir
self.subdirs[subdir].addfile(filep, status)
else:
self._addfileindir(filename, status)
if status not in self.statuses:
self.statuses.add(status)
Denis Laxalde
tersestatus: avoid modifying tersedict...
r34685 def iterfilepaths(self):
Denis Laxalde
tersestatus: rework dirnode and tersedir docstrings...
r34699 """Yield (status, path) for files directly under this directory."""
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684 for f, st in self.files:
Matt Harbison
cmdutil: use internal separators when building the terse list...
r38221 yield st, pathutil.join(self.path, f)
Denis Laxalde
tersestatus: avoid modifying tersedict...
r34685
def tersewalk(self, terseargs):
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684 """
Denis Laxalde
tersestatus: rework dirnode and tersedir docstrings...
r34699 Yield (status, path) obtained by processing the status of this
dirnode.
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684
terseargs is the string of arguments passed by the user with `--terse`
flag.
Following are the cases which can happen:
1) All the files in the directory (including all the files in its
subdirectories) share the same status and the user has asked us to terse
Matt Harbison
cmdutil: use internal separators when building the terse list...
r38221 that status. -> yield (status, dirpath). dirpath will end in '/'.
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684
Denis Laxalde
tersestatus: rework dirnode and tersedir docstrings...
r34699 2) Otherwise, we do following:
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684
Denis Laxalde
tersestatus: avoid modifying tersedict...
r34685 a) Yield (status, filepath) for all the files which are in this
directory (only the ones in this directory, not the subdirs)
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684
b) Recurse the function on all the subdirectories of this
directory
"""
if len(self.statuses) == 1:
onlyst = self.statuses.pop()
# Making sure we terse only when the status abbreviation is
# passed as terse argument
if onlyst in terseargs:
Matt Harbison
cmdutil: use internal separators when building the terse list...
r38221 yield onlyst, self.path + '/'
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684 return
# add the files to status list
Denis Laxalde
tersestatus: avoid modifying tersedict...
r34685 for st, fpath in self.iterfilepaths():
yield st, fpath
Denis Laxalde
tersestatus: make methods part of the dirnode class...
r34684
#recurse on the subdirs
for dirobj in self.subdirs.values():
Denis Laxalde
tersestatus: avoid modifying tersedict...
r34685 for st, fpath in dirobj.tersewalk(terseargs):
yield st, fpath
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
def tersedir(statuslist, terseargs):
"""
Denis Laxalde
tersestatus: rework dirnode and tersedir docstrings...
r34699 Terse the status if all the files in a directory shares the same status.
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
statuslist is scmutil.status() object which contains a list of files for
each status.
terseargs is string which is passed by the user as the argument to `--terse`
flag.
The function makes a tree of objects of dirnode class, and at each node it
stores the information required to know whether we can terse a certain
directory or not.
"""
# the order matters here as that is used to produce final list
allst = ('m', 'a', 'r', 'd', 'u', 'i', 'c')
# checking the argument validity
Augie Fackler
cmdutil: fix status tersing on Python 3...
r34894 for s in pycompat.bytestr(terseargs):
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683 if s not in allst:
raise error.Abort(_("'%s' not recognized") % s)
# creating a dirnode object for the root of the repo
rootobj = dirnode('')
pstatus = ('modified', 'added', 'deleted', 'clean', 'unknown',
'ignored', 'removed')
tersedict = {}
for attrname in pstatus:
Augie Fackler
cmdutil: fix status tersing on Python 3...
r34894 statuschar = attrname[0:1]
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683 for f in getattr(statuslist, attrname):
Augie Fackler
cmdutil: fix status tersing on Python 3...
r34894 rootobj.addfile(f, statuschar)
tersedict[statuschar] = []
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
# we won't be tersing the root dir, so add files in it
Denis Laxalde
tersestatus: avoid modifying tersedict...
r34685 for st, fpath in rootobj.iterfilepaths():
tersedict[st].append(fpath)
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
# process each sub-directory and build tersedict
for subdir in rootobj.subdirs.values():
Denis Laxalde
tersestatus: avoid modifying tersedict...
r34685 for st, f in subdir.tersewalk(terseargs):
tersedict[st].append(f)
Pulkit Goyal
tersestatus: re-implement the functionality to terse the status...
r34683
tersedlist = []
for st in allst:
tersedict[st].sort()
tersedlist.append(tersedict[st])
return tersedlist
Pulkit Goyal
status: add a flag to terse the output (issue4119)...
r33548
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766 def _commentlines(raw):
'''Surround lineswith a comment char and a new line'''
lines = raw.splitlines()
commentedlines = ['# %s' % line for line in lines]
return '\n'.join(commentedlines) + '\n'
def _conflictsmsg(repo):
mergestate = mergemod.mergestate.read(repo)
if not mergestate.active():
return
m = scmutil.match(repo[None])
Martin von Zweigbergk
morestatus: simplify check for unresolved merge conflicts...
r34003 unresolvedlist = [f for f in mergestate.unresolved() if m(f)]
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766 if unresolvedlist:
mergeliststr = '\n'.join(
Matt Harbison
morestatus: don't crash with different drive letters for repo.root and CWD...
r34982 [' %s' % util.pathto(repo.root, pycompat.getcwd(), path)
for path in unresolvedlist])
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766 msg = _('''Unresolved merge conflicts:
%s
To mark files as resolved: hg resolve --mark FILE''') % mergeliststr
else:
msg = _('No unresolved merge conflicts.')
return _commentlines(msg)
def _helpmessage(continuecmd, abortcmd):
Pulkit Goyal
morestatus: remove some extra spaces...
r38360 msg = _('To continue: %s\n'
'To abort: %s') % (continuecmd, abortcmd)
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766 return _commentlines(msg)
def _rebasemsg():
return _helpmessage('hg rebase --continue', 'hg rebase --abort')
def _histeditmsg():
return _helpmessage('hg histedit --continue', 'hg histedit --abort')
def _unshelvemsg():
return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
def _graftmsg():
# tweakdefaults requires `update` to have a rev hence the `.`
Pulkit Goyal
status: advertise --abort instead of 'update -C .' to abort graft...
r39002 return _helpmessage('hg graft --continue', 'hg graft --abort')
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766
def _mergemsg():
# tweakdefaults requires `update` to have a rev hence the `.`
Yuya Nishihara
cmdutil: fix weird indent in _mergemsg()
r39111 return _helpmessage('hg commit', 'hg merge --abort')
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766
def _bisectmsg():
msg = _('To mark the changeset good: hg bisect --good\n'
'To mark the changeset bad: hg bisect --bad\n'
'To abort: hg bisect --reset\n')
return _commentlines(msg)
def fileexistspredicate(filename):
return lambda repo: repo.vfs.exists(filename)
def _mergepredicate(repo):
return len(repo[None].parents()) > 1
STATES = (
# (state, predicate to detect states, helpful message function)
('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
('graft', fileexistspredicate('graftstate'), _graftmsg),
Boris Feld
shelve: check the actual shelvestate in morestatus...
r38479 ('unshelve', fileexistspredicate('shelvedstate'), _unshelvemsg),
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
# The merge state is part of a list that will be iterated over.
# They need to be last because some of the other unfinished states may also
# be in a merge or update state (eg. rebase, histedit, graft, etc).
# We want those to have priority.
('merge', _mergepredicate, _mergemsg),
)
def _getrepostate(repo):
# experimental config: commands.status.skipstates
skip = set(repo.ui.configlist('commands', 'status.skipstates'))
for state, statedetectionpredicate, msgfn in STATES:
if state in skip:
continue
if statedetectionpredicate(repo):
return (state, statedetectionpredicate, msgfn)
def morestatus(repo, fm):
statetuple = _getrepostate(repo)
label = 'status.morestatus'
if statetuple:
fm.startitem()
state, statedetectionpredicate, helpfulmsg = statetuple
statemsg = _('The repository is in an unfinished *%s* state.') % state
fm.write('statemsg', '%s\n', _commentlines(statemsg), label=label)
conmsg = _conflictsmsg(repo)
Pulkit Goyal
morestatus: check whether the conflict message is None before printing...
r33885 if conmsg:
fm.write('conflictsmsg', '%s\n', conmsg, label=label)
Pulkit Goyal
morestatus: move fb extension to core by plugging to `hg status --verbose`...
r33766 if helpfulmsg:
helpmsg = helpfulmsg()
fm.write('helpmsg', '%s\n', helpmsg, label=label)
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()
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 allcmds = []
Matt Mackall
alias: shortcut command matching show shadowing works properly (issue3104)...
r15600 for e in keys:
Brendan Cully
mq: add -Q option to all commands not in norepo
r10401 aliases = parsealiases(e)
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 allcmds.extend(aliases)
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
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 return choice, allcmds
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
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."""
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 choice, allcmds = 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:
Augie Fackler
cmdutil: use sorted(dict) instead of x = dict.keys(); x.sort()...
r32528 clist = sorted(choice)
Matt Mackall
error: move UnknownCommand and AmbiguousCommand
r7643 raise error.AmbiguousCommand(cmd, clist)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
if choice:
Pulkit Goyal
py3: explicitly convert dict.values() to a list on py3...
r32862 return list(choice.values())[0]
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
Augie Fackler
dispatch: offer suggestions of similar-named commands...
r24222 raise error.UnknownCommand(cmd, allcmds)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549
Pulkit Goyal
branch: add a --rev flag to change branch name of given revisions...
r35763 def changebranch(ui, repo, revs, label):
""" Change the branch name of given revs to label """
with repo.wlock(), repo.lock(), repo.transaction('branches'):
# abort in case of uncommitted merge or dirty wdir
bailifchanged(repo)
revs = scmutil.revrange(repo, revs)
if not revs:
raise error.Abort("empty revision set")
roots = repo.revs('roots(%ld)', revs)
if len(roots) > 1:
raise error.Abort(_("cannot change branch of non-linear revisions"))
rewriteutil.precheck(repo, revs, 'change branch of')
Pulkit Goyal
branch: allow changing branch name to existing name if possible...
r35764
root = repo[roots.first()]
if not root.p1().branch() == label and label in repo.branchmap():
raise error.Abort(_("a branch of the same name already exists"))
Pulkit Goyal
branch: add a --rev flag to change branch name of given revisions...
r35763 if repo.revs('merge() and %ld', revs):
raise error.Abort(_("cannot change branch of a merge commit"))
if repo.revs('obsolete() and %ld', revs):
raise error.Abort(_("cannot change branch of a obsolete changeset"))
# make sure only topological heads
if repo.revs('heads(%ld) - head()', revs):
raise error.Abort(_("cannot change branch in middle of a stack"))
replacements = {}
# avoid import cycle mercurial.cmdutil -> mercurial.context ->
# mercurial.subrepo -> mercurial.cmdutil
from . import context
for rev in revs:
ctx = repo[rev]
oldbranch = ctx.branch()
# check if ctx has same branch
if oldbranch == label:
continue
def filectxfn(repo, newctx, path):
try:
return ctx[path]
except error.ManifestLookupError:
return None
ui.debug("changing branch of '%s' from '%s' to '%s'\n"
% (hex(ctx.node()), oldbranch, label))
extra = ctx.extra()
extra['branch_change'] = hex(ctx.node())
# While changing branch of set of linear commits, make sure that
# we base our commits on new parent rather than old parent which
# was obsoleted while changing the branch
p1 = ctx.p1().node()
p2 = ctx.p2().node()
if p1 in replacements:
p1 = replacements[p1][0]
if p2 in replacements:
p2 = replacements[p2][0]
mc = context.memctx(repo, (p1, p2),
ctx.description(),
ctx.files(),
filectxfn,
user=ctx.user(),
date=ctx.date(),
extra=extra,
branch=label)
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 newnode = repo.commitctx(mc)
Pulkit Goyal
branch: add a --rev flag to change branch name of given revisions...
r35763 replacements[ctx.node()] = (newnode,)
ui.debug('new node id is %s\n' % hex(newnode))
# create obsmarkers and move bookmarks
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 scmutil.cleanupnodes(repo, replacements, 'branch-change', fixphase=True)
Pulkit Goyal
branch: add a --rev flag to change branch name of given revisions...
r35763
# move the working copy too
wctx = repo[None]
# in-progress merge is a bit too complex for now.
if len(wctx.parents()) == 1:
newid = replacements.get(wctx.p1().node())
if newid is not None:
# avoid import cycle mercurial.cmdutil -> mercurial.hg ->
# mercurial.cmdutil
from . import hg
hg.update(repo, newid[0], quietempty=True)
ui.status(_("changed branch on %d changesets\n") % len(replacements))
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
Valters Vingolds
rebase: provide detailed hint to abort message if working dir is not clean...
r30755 def bailifchanged(repo, merge=True, hint=None):
""" enforce the precondition that working directory must be clean.
'merge' can be set to false if a pending uncommitted merge should be
ignored (such as when 'update --check' runs).
'hint' is the usual hint given to Abort exception.
"""
FUJIWARA Katsunori
cmdutil: allow bailifchanged to ignore merging in progress...
r24472 if merge and repo.dirstate.p2() != nullid:
Valters Vingolds
rebase: provide detailed hint to abort message if working dir is not clean...
r30755 raise error.Abort(_('outstanding uncommitted merge'), hint=hint)
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 modified, added, removed, deleted = repo.status()[:4]
if modified or added or removed or deleted:
Valters Vingolds
rebase: provide detailed hint to abort message if working dir is not clean...
r30755 raise error.Abort(_('uncommitted changes'), hint=hint)
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):
Valters Vingolds
rebase: provide detailed hint to abort message if working dir is not clean...
r30755 ctx.sub(s).bailifchanged(hint=hint)
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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('options --message and --logfile are mutually '
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 'exclusive'))
if not message and logfile:
try:
Yuya Nishihara
cmdutil: use isstdiofilename() where appropriate
r32618 if isstdiofilename(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())
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("can't read commit message '%s': %s") %
Augie Fackler
python3: wrap all uses of <exception>.strerror with strtolocal...
r34024 (logfile, encoding.strtolocal(inst.strerror)))
Matt Mackall
dispatch: move dispatching code to cmdutil
r4549 return message
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r24180 def mergeeditform(ctxorbool, baseformname):
"""return appropriate editform name (referencing a committemplate)
'ctxorbool' is either a ctx to be committed, or a bool indicating whether
FUJIWARA Katsunori
commit: change "editform" to distinguish merge commits from others...
r22248 merging is committed.
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r24180 This returns baseformname with '.merge' appended if it is a merge,
otherwise '.normal' is appended.
FUJIWARA Katsunori
commit: change "editform" to distinguish merge commits from others...
r22248 """
if isinstance(ctxorbool, bool):
if ctxorbool:
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r24180 return baseformname + ".merge"
FUJIWARA Katsunori
commit: change "editform" to distinguish merge commits from others...
r22248 elif 1 < len(ctxorbool.parents()):
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r24180 return baseformname + ".merge"
return baseformname + ".normal"
FUJIWARA Katsunori
commit: change "editform" to distinguish merge commits from others...
r22248
FUJIWARA Katsunori
cmdutil: introduce 'editform' to distinguish the purpose of commit text editing...
r21999 def getcommiteditor(edit=False, finishdesc=None, extramsg=None,
editform='', **opts):
FUJIWARA Katsunori
cmdutil: enhance "getcommiteditor()" for specific usages in MQ...
r21419 """get appropriate commit message editor according to '--edit' option
'finishdesc' is a function to be called with edited commit message
(= 'description' of the new changeset) just after editing, but
before checking empty-ness. It should return actual text to be
stored into history. This allows to change description before
storing.
'extramsg' is a extra message to be shown in the editor instead of
'Leave message empty to abort commit' line. 'HG: ' prefix and EOL
is automatically added.
FUJIWARA Katsunori
cmdutil: introduce 'editform' to distinguish the purpose of commit text editing...
r21999 'editform' is a dot-separated list of names, to distinguish
the purpose of commit text editing.
FUJIWARA Katsunori
cmdutil: enhance "getcommiteditor()" for specific usages in MQ...
r21419 'getcommiteditor' returns 'commitforceeditor' regardless of
'edit', if one of 'finishdesc' or 'extramsg' is specified, because
they are specific for usage in MQ.
"""
if edit or finishdesc or extramsg:
return lambda r, c, s: commitforceeditor(r, c, s,
finishdesc=finishdesc,
FUJIWARA Katsunori
cmdutil: introduce 'editform' to distinguish the purpose of commit text editing...
r21999 extramsg=extramsg,
editform=editform)
elif editform:
return lambda r, c, s: commiteditor(r, c, s, editform=editform)
FUJIWARA Katsunori
cmdutil: introduce "getcommiteditor()" to simplify code paths to choose editor...
r21405 else:
return commiteditor
Yuya Nishihara
fix: use templater to substitute values in command string...
r37792 def _escapecommandtemplate(tmpl):
parts = []
for typ, start, end in templater.scantemplate(tmpl, raw=True):
if typ == b'string':
parts.append(stringutil.escapestr(tmpl[start:end]))
else:
parts.append(tmpl[start:end])
return b''.join(parts)
def rendercommandtemplate(ui, tmpl, props):
r"""Expand a literal template 'tmpl' in a way suitable for command line
'\' in outermost string is not taken as an escape character because it
is a directory separator on Windows.
>>> from . import ui as uimod
>>> ui = uimod.ui()
>>> rendercommandtemplate(ui, b'c:\\{path}', {b'path': b'foo'})
'c:\\foo'
>>> rendercommandtemplate(ui, b'{"c:\\{path}"}', {'path': b'foo'})
'c:{path}'
"""
if not tmpl:
return tmpl
t = formatter.maketemplater(ui, _escapecommandtemplate(tmpl))
return t.renderdefault(props)
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 def rendertemplate(ctx, tmpl, props=None):
"""Expand a literal template 'tmpl' byte-string against one changeset
Each props item must be a stringify-able value or a callable returning
such value, i.e. no bare list nor dict should be passed.
"""
repo = ctx.repo()
tres = formatter.templateresources(repo.ui, repo)
t = formatter.maketemplater(repo.ui, tmpl, defaults=templatekw.keywords,
resources=tres)
Yuya Nishihara
templater: switch 'revcache' based on new mapping items...
r37121 mapping = {'ctx': ctx}
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 if props:
mapping.update(props)
Yuya Nishihara
templater: rename .render(mapping) to .renderdefault(mapping) (API)...
r37003 return t.renderdefault(mapping)
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528
def _buildfntemplate(pat, total=None, seqno=None, revwidth=None, pathname=None):
r"""Convert old-style filename format string to template string
>>> _buildfntemplate(b'foo-%b-%n.patch', seqno=0)
'foo-{reporoot|basename}-{seqno}.patch'
>>> _buildfntemplate(b'%R{tags % "{tag}"}%H')
'{rev}{tags % "{tag}"}{node}'
'\' in outermost strings has to be escaped because it is a directory
separator on Windows:
>>> _buildfntemplate(b'c:\\tmp\\%R\\%n.patch', seqno=0)
'c:\\\\tmp\\\\{rev}\\\\{seqno}.patch'
>>> _buildfntemplate(b'\\\\foo\\bar.patch')
'\\\\\\\\foo\\\\bar.patch'
>>> _buildfntemplate(b'\\{tags % "{tag}"}')
'\\\\{tags % "{tag}"}'
but inner strings follow the template rules (i.e. '\' is taken as an
escape character):
>>> _buildfntemplate(br'{"c:\tmp"}', seqno=0)
'{"c:\\tmp"}'
"""
Vadim Gelfer
refactor text diff/patch code....
r2874 expander = {
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 b'H': b'{node}',
b'R': b'{rev}',
b'h': b'{node|short}',
b'm': br'{sub(r"[^\w]", "_", desc|firstline)}',
b'r': b'{if(revwidth, pad(rev, revwidth, "0", left=True), rev)}',
b'%': b'%',
b'b': b'{reporoot|basename}',
}
Yuya Nishihara
cmdutil: narrow scope of KeyError in makefilename()...
r36257 if total is not None:
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 expander[b'N'] = b'{total}'
Yuya Nishihara
cmdutil: narrow scope of KeyError in makefilename()...
r36257 if seqno is not None:
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 expander[b'n'] = b'{seqno}'
Yuya Nishihara
cmdutil: narrow scope of KeyError in makefilename()...
r36257 if total is not None and seqno is not None:
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 expander[b'n'] = b'{pad(seqno, total|stringify|count, "0", left=True)}'
Yuya Nishihara
cmdutil: narrow scope of KeyError in makefilename()...
r36257 if pathname is not None:
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 expander[b's'] = b'{pathname|basename}'
expander[b'd'] = b'{if(pathname|dirname, pathname|dirname, ".")}'
expander[b'p'] = b'{pathname}'
Yuya Nishihara
cmdutil: narrow scope of KeyError in makefilename()...
r36257
newname = []
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 for typ, start, end in templater.scantemplate(pat, raw=True):
if typ != b'string':
newname.append(pat[start:end])
continue
i = start
while i < end:
n = pat.find(b'%', i, end)
if n < 0:
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 newname.append(stringutil.escapestr(pat[i:end]))
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 break
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 newname.append(stringutil.escapestr(pat[i:n]))
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 if n + 2 > end:
raise error.Abort(_("incomplete format spec in output "
"filename"))
c = pat[n + 1:n + 2]
i = n + 2
Yuya Nishihara
cmdutil: narrow scope of KeyError in makefilename()...
r36257 try:
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 newname.append(expander[c])
Yuya Nishihara
cmdutil: narrow scope of KeyError in makefilename()...
r36257 except KeyError:
raise error.Abort(_("invalid format spec '%%%s' in output "
"filename") % c)
return ''.join(newname)
Vadim Gelfer
refactor text diff/patch code....
r2874
Yuya Nishihara
cmdutil: expand filename format string by templater (BC)...
r36528 def makefilename(ctx, pat, **props):
if not pat:
return pat
tmpl = _buildfntemplate(pat, **props)
# BUG: alias expansion shouldn't be made against template fragments
# rewritten from %-format strings, but we have no easy way to partially
# disable the expansion.
return rendertemplate(ctx, tmpl, pycompat.byteskwargs(props))
Vadim Gelfer
refactor text diff/patch code....
r2874
Yuya Nishihara
cmdutil: extract function checking if pattern should be taken as stdin/out...
r32539 def isstdiofilename(pat):
"""True if the given pat looks like a filename denoting stdin/stdout"""
return not pat or pat == '-'
Yuya Nishihara
cmdutil: reimplement file wrapper that disables close()...
r27418 class _unclosablefile(object):
def __init__(self, fp):
self._fp = fp
def close(self):
pass
def __iter__(self):
return iter(self._fp)
def __getattr__(self, attr):
return getattr(self._fp, attr)
Mads Kiilerich
largefiles: use context for file closing...
r30142 def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_tb):
pass
Yuya Nishihara
export: serialize revisions to be exported per destination file...
r37619 def makefileobj(ctx, pat, mode='wb', **props):
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
Yuya Nishihara
cmdutil: extract function checking if pattern should be taken as stdin/out...
r32539 if isstdiofilename(pat):
Yuya Nishihara
cmdutil: pass ctx to makefileobj() in place of repo/node pair (API)
r36223 repo = ctx.repo()
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if writable:
fp = repo.ui.fout
else:
fp = repo.ui.fin
Yuya Nishihara
cmdutil: do not duplicate stdout by makefileobj()...
r27419 return _unclosablefile(fp)
Yuya Nishihara
cmdutil: reorder optional arguments passed to makefileobj()...
r36526 fn = makefilename(ctx, pat, **props)
Augie Fackler
export: clobber files with -o (bc) (issue3652)...
r18613 return open(fn, mode)
Vadim Gelfer
move walk and matchpats from commands to cmdutil.
r2882
Gregory Szorc
cmdutil: return a revlog from openrevlog() and split function...
r39314 def openstorage(repo, cmd, file_, opts, returnrevlog=False):
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 """opens the changelog, manifest, a filelog or a given revlog"""
cl = opts['changelog']
mf = opts['manifest']
Martin von Zweigbergk
treemanifest: add --dir option to debug{revlog,data,index}...
r25119 dir = opts['dir']
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 msg = None
if cl and mf:
msg = _('cannot specify --changelog and --manifest at the same time')
Martin von Zweigbergk
treemanifest: add --dir option to debug{revlog,data,index}...
r25119 elif cl and dir:
msg = _('cannot specify --changelog and --dir at the same time')
Martin von Zweigbergk
debug: make debug{revlog,index,data} --dir not just a flag...
r29427 elif cl or mf or dir:
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 if file_:
msg = _('cannot specify filename with --changelog or --manifest')
elif not repo:
Martin von Zweigbergk
treemanifest: add --dir option to debug{revlog,data,index}...
r25119 msg = _('cannot specify --changelog or --manifest or --dir '
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 'without a repository')
if msg:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(msg)
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323
r = None
if repo:
if cl:
Matt Mackall
debugrevlog: use unfiltered view for changelog
r21033 r = repo.unfiltered().changelog
Martin von Zweigbergk
treemanifest: add --dir option to debug{revlog,data,index}...
r25119 elif dir:
if 'treemanifest' not in repo.requirements:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("--dir can only be used on repos with "
Martin von Zweigbergk
treemanifest: add --dir option to debug{revlog,data,index}...
r25119 "treemanifest enabled"))
Martin von Zweigbergk
narrow: add trailing slash to dir earlier for debug{revlog,index,data}...
r37287 if not dir.endswith('/'):
dir = dir + '/'
Gregory Szorc
manifest: add getstorage() to manifestlog and use it globally...
r39280 dirlog = repo.manifestlog.getstorage(dir)
Martin von Zweigbergk
treemanifest: add --dir option to debug{revlog,data,index}...
r25119 if len(dirlog):
r = dirlog
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 elif mf:
Gregory Szorc
manifest: add getstorage() to manifestlog and use it globally...
r39280 r = repo.manifestlog.getstorage(b'')
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 elif file_:
filelog = repo.file(file_)
if len(filelog):
r = filelog
Gregory Szorc
cmdutil: return a revlog from openrevlog() and split function...
r39314
# Not all storage may be revlogs. If requested, try to return an actual
# revlog instance.
if returnrevlog:
if isinstance(r, revlog.revlog):
pass
elif util.safehasattr(r, '_revlog'):
r = r._revlog
elif r is not None:
raise error.Abort(_('%r does not appear to be a revlog') % r)
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 if not r:
Gregory Szorc
cmdutil: return a revlog from openrevlog() and split function...
r39314 if not returnrevlog:
raise error.Abort(_('cannot give path to non-revlog'))
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 if not file_:
raise error.CommandError(cmd, _('invalid arguments'))
if not os.path.isfile(file_):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("revlog '%s' not found") % file_)
Pierre-Yves David
vfs: use 'vfs' module directly in 'mercurial.cmdutil'...
r31237 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
Sune Foldager
debugindex etc.: add --changelog and --manifest options...
r14323 file_[:-2] + ".i")
return r
Gregory Szorc
cmdutil: return a revlog from openrevlog() and split function...
r39314 def openrevlog(repo, cmd, file_, opts):
"""Obtain a revlog backing storage of an item.
This is similar to ``openstorage()`` except it always returns a revlog.
In most cases, a caller cares about the main storage object - not the
revlog backing it. Therefore, this function should only be used by code
that needs to examine low-level revlog implementation details. e.g. debug
commands.
"""
return openstorage(repo, cmd, file_, opts, returnrevlog=True)
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 = []
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if after:
badstates = '?'
else:
badstates = '?r'
Martin von Zweigbergk
cleanup: reuse existing wctx variables instead of calling repo[None]...
r32382 m = scmutil.match(wctx, [pat], opts, globbed=True)
for abs in wctx.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):
Augie Fackler
pathutil: tease out a new library to break an import cycle from canonpath use
r20033 abstarget = pathutil.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)))
Martin von Zweigbergk
rename: return error status if any rename/copy failed...
r39386 return True # report a failure
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)
Martin von Zweigbergk
rename: return error status if any rename/copy failed...
r39386 return True # report a failure
Matt Mackall
rename: handle case-changing (issue1717)
r16283 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']:
Augie Fackler
copy: distinguish "file exists" cases and add a hint (BC)...
r30151 if state in 'mn':
msg = _('%s: not overwriting - file already committed\n')
if after:
flags = '--after --force'
else:
flags = '--force'
if rename:
Martin von Zweigbergk
rename: quote hg commands in warnings...
r39384 hint = _("('hg rename %s' to replace the file by "
Augie Fackler
copy: distinguish "file exists" cases and add a hint (BC)...
r30151 'recording a rename)\n') % flags
else:
Martin von Zweigbergk
rename: quote hg commands in warnings...
r39384 hint = _("('hg copy %s' to replace the file by "
Augie Fackler
copy: distinguish "file exists" cases and add a hint (BC)...
r30151 'recording a copy)\n') % flags
else:
msg = _('%s: not overwriting - file exists\n')
if rename:
Martin von Zweigbergk
rename: quote hg commands in warnings...
r39384 hint = _("('hg rename --after' to record the rename)\n")
Augie Fackler
copy: distinguish "file exists" cases and add a hint (BC)...
r30151 else:
Martin von Zweigbergk
rename: quote hg commands in warnings...
r39384 hint = _("('hg copy --after' to record the copy)\n")
Augie Fackler
copy: distinguish "file exists" cases and add a hint (BC)...
r30151 ui.warn(msg % reltarget)
ui.warn(hint)
Martin von Zweigbergk
rename: return error status if any rename/copy failed...
r39386 return True # report a failure
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))
Martin von Zweigbergk
rename: return error status if any rename/copy failed...
r39386 return True # report a failure
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:
Kyle Lippincott
copyfile: preserve stat info (mtime, etc.) when doing copies/renames...
r37106 # Preserve stat info on renames, not on copies; this matches
# Linux CLI behavior.
util.copyfile(src, target, copystat=rename)
Adrian Buehlmann
workingctx: eliminate remove function...
r14518 srcexists = True
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if inst.errno == errno.ENOENT:
Yuya Nishihara
commands: replace "working copy" with "working directory" in help/messages...
r24364 ui.warn(_('%s: deleted in working directory\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') %
Augie Fackler
python3: wrap all uses of <exception>.strerror with strtolocal...
r34024 (relsrc, encoding.strtolocal(inst.strerror)))
Martin von Zweigbergk
rename: emit hint about using --after consistently...
r39385 if rename:
hint = _("('hg rename --after' to record the rename)\n")
else:
hint = _("('hg copy --after' to record the copy)\n")
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:
Kyle Lippincott
unlinkpath: make empty directory removal optional (issue5901) (issue5826)...
r38512 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
repo.wvfs.unlinkpath(abssrc, rmdir=rmdir)
Adrian Buehlmann
workingctx: eliminate remove function...
r14518 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):
Augie Fackler
pathutil: tease out a new library to break an import cycle from canonpath use
r20033 abspfx = pathutil.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:
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 3 of 4)
r30615 striplen += len(pycompat.ossep)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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:
Augie Fackler
pathutil: tease out a new library to break an import cycle from canonpath use
r20033 abspfx = pathutil.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:
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 3 of 4)
r30615 striplen += len(pycompat.ossep)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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:
Pulkit Goyal
py3: replace os.sep with pycompat.ossep (part 3 of 4)
r30615 striplen1 += len(pycompat.ossep)
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('no source or destination specified'))
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 if len(pats) == 1:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('no destination specified'))
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 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]):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('with multiple sources, destination must be an '
Matt Mackall
move commands.docopy to cmdutil.copy
r5589 'existing directory'))
Shun-ichi GOTO
Add endswithsep() and use it instead of using os.sep and os.altsep directly....
r5843 if util.endswithsep(dest):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('no files to copy'))
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
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
Matt Mackall
commands: initial audit of exit codes...
r11177 return errors != 0
Matt Mackall
move commands.docopy to cmdutil.copy
r5589
Pierre-Yves David
import: allow processing of extra part header during import...
r26561 ## facility to let extension process additional data into an import patch
# list of identifier to be executed in order
extrapreimport = [] # run before commit
Pierre-Yves David
import: allow processing of extra part header after import...
r26562 extrapostimport = [] # run after commit
Pierre-Yves David
import: allow processing of extra part header during import...
r26561 # mapping from identifier to actual import function
#
# 'preimport' are run before the commit is made and are provided the following
# arguments:
# - repo: the localrepository instance,
# - patchdata: data extracted from patch header (cf m.patch.patchheadermap),
Mads Kiilerich
spelling: trivial spell checking
r26781 # - extra: the future extra dictionary of the changeset, please mutate it,
Pierre-Yves David
import: allow processing of extra part header during import...
r26561 # - opts: the import options.
# XXX ideally, we would just pass an ctx ready to be computed, that would allow
# mutation of in memory commit and more. Feel free to rework the code to get
# there.
extrapreimportmap = {}
Pierre-Yves David
import: allow processing of extra part header after import...
r26562 # 'postimport' are run after the commit is made and are provided the following
# argument:
# - ctx: the changectx created by import.
extrapostimportmap = {}
Pierre-Yves David
import: allow processing of extra part header during import...
r26561
Gregory Szorc
cmdutil: pass in parsed patch to tryimportone() (API)...
r37638 def tryimportone(ui, repo, patchdata, parents, opts, msgs, updatefunc):
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 """Utility function used by commands.import to import a single patch
This function is explicitly defined here to help the evolve extension to
wrap this part of the import logic.
The API is currently a bit ugly because it a simple code translation from
the import command. Feel free to make it better.
Gregory Szorc
cmdutil: pass in parsed patch to tryimportone() (API)...
r37638 :patchdata: a dictionary containing parsed patch data (such as from
``patch.extract()``)
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 :parents: nodes that will be parent of the created commit
:opts: the full dict of option passed to the import command
:msgs: list to save commit message to.
(used in case we need to save it when failing)
:updatefunc: a function that update a repo to a given node
updatefunc(<repo>, <node>)
"""
Gregory Szorc
cmdutil: break import cycle...
r25930 # avoid cycle context -> subrepo -> cmdutil
Gregory Szorc
cmdutil: use absolute_import...
r28322 from . import context
Gregory Szorc
cmdutil: pass in parsed patch to tryimportone() (API)...
r37638
tmpname = patchdata.get('filename')
message = patchdata.get('message')
user = opts.get('user') or patchdata.get('user')
date = opts.get('date') or patchdata.get('date')
branch = patchdata.get('branch')
nodeid = patchdata.get('nodeid')
p1 = patchdata.get('p1')
p2 = patchdata.get('p2')
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500
timeless
import: refactor nocommit and importbranch handling
r27613 nocommit = opts.get('no_commit')
importbranch = opts.get('import_branch')
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 update = not opts.get('bypass')
strip = opts["strip"]
Siddharth Agarwal
cmdutil.tryimportone: allow importing relative patches into the working dir...
r24259 prefix = opts["prefix"]
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 sim = float(opts.get('similarity') or 0)
Gregory Szorc
patch: make extract() a context manager (API)...
r37639
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 if not tmpname:
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 return None, None, False
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500
Pierre-Yves David
import: add --partial flag to create a changeset despite failed hunks...
r21553 rejects = False
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 cmdline_message = logmessage(ui, opts)
if cmdline_message:
# pickup the cmdline msg
message = cmdline_message
elif message:
# pickup the patch msg
message = message.strip()
else:
# launch the editor
message = None
ui.debug('message:\n%s\n' % (message or ''))
if len(parents) == 1:
parents.append(repo[nullid])
if opts.get('exact'):
if not nodeid or not p1:
raise error.Abort(_('not a Mercurial patch'))
p1 = repo[p1]
p2 = repo[p2 or nullid]
elif p2:
try:
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 p1 = repo[p1]
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 p2 = repo[p2]
# Without any options, consider p2 only if the
# patch is being applied on top of the recorded
# first parent.
if p1 != parents[0]:
p1 = parents[0]
p2 = repo[nullid]
except error.RepoError:
p1, p2 = parents
if p2.node() == nullid:
ui.warn(_("warning: import the patch as a normal revision\n"
"(use --exact to import the patch as a merge)\n"))
else:
p1, p2 = parents
n = None
if update:
if p1 != parents[0]:
updatefunc(repo, p1.node())
if p2 != parents[1]:
repo.setparents(p1.node(), p2.node())
if opts.get('exact') or importbranch:
repo.dirstate.setbranch(branch or 'default')
partial = opts.get('partial', False)
files = set()
try:
patch.patch(ui, repo, tmpname, strip=strip, prefix=prefix,
files=files, eolmode=None, similarity=sim / 100.0)
except error.PatchError as e:
if not partial:
raise error.Abort(pycompat.bytestr(e))
if partial:
rejects = True
files = list(files)
if nocommit:
if message:
msgs.append(message)
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 else:
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 if opts.get('exact') or p2:
# If you got here, you either use --force and know what
# you are doing or used --exact or a merge patch while
# being updated to its first parent.
m = None
else:
m = scmutil.matchfiles(repo, files or [])
editform = mergeeditform(repo[None], 'import.normal')
if opts.get('exact'):
editor = None
else:
editor = getcommiteditor(editform=editform,
**pycompat.strkwargs(opts))
extra = {}
for idfunc in extrapreimport:
extrapreimportmap[idfunc](repo, patchdata, extra, opts)
overrides = {}
if partial:
overrides[('ui', 'allowemptycommit')] = True
with repo.ui.configoverride(overrides, 'import'):
n = repo.commit(message, user,
date, match=m,
editor=editor, extra=extra)
for idfunc in extrapostimport:
extrapostimportmap[idfunc](repo[n])
else:
if opts.get('exact') or importbranch:
branch = branch or 'default'
else:
branch = p1.branch()
store = patch.filestore()
try:
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 files = set()
Pierre-Yves David
import: add --partial flag to create a changeset despite failed hunks...
r21553 try:
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 patch.patchrepo(ui, repo, p1, store, tmpname, strip, prefix,
files, eolmode=None)
Yuya Nishihara
error: move patch.PatchError so it can easily implement __bytes__ (API)
r34252 except error.PatchError as e:
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 raise error.Abort(stringutil.forcebytestr(e))
if opts.get('exact'):
editor = None
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500 else:
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 editor = getcommiteditor(editform='import.bypass')
memctx = context.memctx(repo, (p1.node(), p2.node()),
message,
files=files,
filectxfn=store,
user=user,
date=date,
branch=branch,
editor=editor)
n = memctx.commit()
finally:
store.close()
if opts.get('exact') and nocommit:
# --exact with --no-commit is still useful in that it does merge
# and branch bits
ui.warn(_("warning: can't check exact import with --no-commit\n"))
Yuya Nishihara
import: fix crash on --exact check of empty commit (issue5702)
r37833 elif opts.get('exact') and (not n or hex(n) != nodeid):
Gregory Szorc
patch: make extract() a context manager (API)...
r37639 raise error.Abort(_('patch is damaged or loses information'))
msg = _('applied to working directory')
if n:
# i18n: refers to a short changeset id
msg = _('created %s') % short(n)
return msg, n, rejects
Pierre-Yves David
import: move tryone closure in cmdutil...
r20500
Pierre-Yves David
export: introduce a generic way to add patch header on export...
r26545 # facility to let extensions include additional data in an exported patch
# list of identifiers to be executed in order
extraexport = []
# mapping from identifier to actual export function
# function as to return a string to be added to the header or None
# it is given two arguments (sequencenumber, changectx)
extraexportmap = {}
Yuya Nishihara
export: port _exportsingle() to formatter...
r37620 def _exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts):
Yuya Nishihara
export: map wctx.node() to 'ff...' node id (issue5438)
r32660 node = scmutil.binnode(ctx)
Augie Fackler
cmdutil: extract closure that performs the actual export formatting...
r32433 parents = [p.node() for p in ctx.parents() if p]
branch = ctx.branch()
if switch_parent:
parents.reverse()
if parents:
prev = parents[0]
else:
prev = nullid
Yuya Nishihara
export: port _exportsingle() to formatter...
r37620 fm.context(ctx=ctx)
fm.plain('# HG changeset patch\n')
fm.write('user', '# User %s\n', ctx.user())
fm.plain('# Date %d %d\n' % ctx.date())
fm.write('date', '# %s\n', fm.formatdate(ctx.date()))
fm.condwrite(branch and branch != 'default',
'branch', '# Branch %s\n', branch)
fm.write('node', '# Node ID %s\n', hex(node))
fm.plain('# Parent %s\n' % hex(prev))
Augie Fackler
cmdutil: extract closure that performs the actual export formatting...
r32433 if len(parents) > 1:
Yuya Nishihara
export: port _exportsingle() to formatter...
r37620 fm.plain('# Parent %s\n' % hex(parents[1]))
fm.data(parents=fm.formatlist(pycompat.maplist(hex, parents), name='node'))
# TODO: redesign extraexportmap function to support formatter
Augie Fackler
cmdutil: extract closure that performs the actual export formatting...
r32433 for headerid in extraexport:
header = extraexportmap[headerid](seqno, ctx)
if header is not None:
Yuya Nishihara
export: port _exportsingle() to formatter...
r37620 fm.plain('# %s\n' % header)
fm.write('desc', '%s\n', ctx.description().rstrip())
fm.plain('\n')
if fm.isplain():
chunkiter = patch.diffui(repo, prev, node, match, opts=diffopts)
for chunk, label in chunkiter:
fm.plain(chunk, label=label)
else:
chunkiter = patch.diff(repo, prev, node, match, opts=diffopts)
# TODO: make it structured?
fm.data(diff=b''.join(chunkiter))
Augie Fackler
cmdutil: extract closure that performs the actual export formatting...
r32433
Yuya Nishihara
export: enable formatter support (API)...
r37622 def _exportfile(repo, revs, fm, dest, switch_parent, diffopts, match):
Yuya Nishihara
export: split cmdutil.export() to single-file and maybe-multiple-files cases...
r37618 """Export changesets to stdout or a single file"""
for seqno, rev in enumerate(revs, 1):
ctx = repo[rev]
if not dest.startswith('<'):
repo.ui.note("%s\n" % dest)
Yuya Nishihara
export: port _exportsingle() to formatter...
r37620 fm.startitem()
_exportsingle(repo, ctx, fm, match, switch_parent, seqno, diffopts)
Yuya Nishihara
export: enable formatter support (API)...
r37622
def _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, diffopts,
match):
Yuya Nishihara
export: split cmdutil.export() to single-file and maybe-multiple-files cases...
r37618 """Export changesets to possibly multiple files"""
total = len(revs)
revwidth = max(len(str(rev)) for rev in revs)
Yuya Nishihara
export: serialize revisions to be exported per destination file...
r37619 filemap = util.sortdict() # filename: [(seqno, rev), ...]
Yuya Nishihara
export: split cmdutil.export() to single-file and maybe-multiple-files cases...
r37618
for seqno, rev in enumerate(revs, 1):
ctx = repo[rev]
Yuya Nishihara
export: serialize revisions to be exported per destination file...
r37619 dest = makefilename(ctx, fntemplate,
total=total, seqno=seqno, revwidth=revwidth)
filemap.setdefault(dest, []).append((seqno, rev))
for dest in filemap:
Yuya Nishihara
export: enable formatter support (API)...
r37622 with formatter.maybereopen(basefm, dest) as fm:
Yuya Nishihara
export: serialize revisions to be exported per destination file...
r37619 repo.ui.note("%s\n" % dest)
for seqno, rev in filemap[dest]:
Yuya Nishihara
export: port _exportsingle() to formatter...
r37620 fm.startitem()
Yuya Nishihara
export: serialize revisions to be exported per destination file...
r37619 ctx = repo[rev]
Yuya Nishihara
export: port _exportsingle() to formatter...
r37620 _exportsingle(repo, ctx, fm, match, switch_parent, seqno,
Yuya Nishihara
export: serialize revisions to be exported per destination file...
r37619 diffopts)
Yuya Nishihara
export: split cmdutil.export() to single-file and maybe-multiple-files cases...
r37618
Yuya Nishihara
export: enable formatter support (API)...
r37622 def export(repo, revs, basefm, fntemplate='hg-%h.patch', switch_parent=False,
Matt Harbison
extdiff: enable -I/-X with --patch...
r26229 opts=None, match=None):
Augie Fackler
cmdutil: comprehensively document the interface of export...
r32430 '''export changesets as hg patches
Args:
repo: The repository from which we're exporting revisions.
revs: A list of revisions to export as revision numbers.
Yuya Nishihara
export: enable formatter support (API)...
r37622 basefm: A formatter to which patches should be written.
Augie Fackler
cmdutil: rename template param to export to fntemplate...
r32431 fntemplate: An optional string to use for generating patch file names.
Augie Fackler
cmdutil: comprehensively document the interface of export...
r32430 switch_parent: If True, show diffs against second parent when not nullid.
Default is false, which always shows diff against p1.
opts: diff options to use for generating the patch.
match: If specified, only export changes to files matching this matcher.
Returns:
Nothing.
Side Effect:
"HG Changeset Patch" data is emitted to one of the following
destinations:
Augie Fackler
cmdutil: rename template param to export to fntemplate...
r32431 fntemplate specified: Each rev is written to a unique file named using
Augie Fackler
cmdutil: comprehensively document the interface of export...
r32430 the given template.
Yuya Nishihara
export: enable formatter support (API)...
r37622 Otherwise: All revs will be written to basefm.
Augie Fackler
cmdutil: comprehensively document the interface of export...
r32430 '''
Matt Harbison
export: invoke the file prefetch hook...
r37781 scmutil.prefetchfiles(repo, revs, match)
Yuya Nishihara
export: extract function to write patch to file object (API)...
r37621 if not fntemplate:
Yuya Nishihara
export: enable formatter support (API)...
r37622 _exportfile(repo, revs, basefm, '<unnamed>', switch_parent, opts, match)
Yuya Nishihara
export: split cmdutil.export() to single-file and maybe-multiple-files cases...
r37618 else:
Yuya Nishihara
export: enable formatter support (API)...
r37622 _exportfntemplate(repo, revs, basefm, fntemplate, switch_parent, opts,
match)
Benoit Boissinot
patch/diff: move patch.export() to cmdutil.export()...
r10611
Yuya Nishihara
export: extract function to write patch to file object (API)...
r37621 def exportfile(repo, revs, fp, switch_parent=False, opts=None, match=None):
"""Export changesets to the given file stream"""
Matt Harbison
export: invoke the file prefetch hook...
r37781 scmutil.prefetchfiles(repo, revs, match)
Yuya Nishihara
export: enable formatter support (API)...
r37622 dest = getattr(fp, 'name', '<unnamed>')
with formatter.formatter(repo.ui, fp, 'export', {}) as fm:
_exportfile(repo, revs, fm, dest, switch_parent, opts, match)
Yuya Nishihara
export: extract function to write patch to file object (API)...
r37621
Yuya Nishihara
debugobsolete: add formatter support (issue5134)...
r29795 def showmarker(fm, marker, index=None):
Pierre-Yves David
debugobsolete: extract marker display in a dedicated function...
r20470 """utility function to display obsolescence marker in a readable way
To be used by debug function."""
Kostia Balytskyi
debugobsolete: add an option to show marker index...
r28613 if index is not None:
Yuya Nishihara
debugobsolete: add formatter support (issue5134)...
r29795 fm.write('index', '%i ', index)
Boris Feld
obsmarker: precnode was renamed into prednode...
r33856 fm.write('prednode', '%s ', hex(marker.prednode()))
Yuya Nishihara
debugobsolete: add formatter support (issue5134)...
r29795 succs = marker.succnodes()
fm.condwrite(succs, 'succnodes', '%s ',
fm.formatlist(map(hex, succs), name='node'))
fm.write('flag', '%X ', marker.flags())
Pierre-Yves David
debugobsolete: display parents information from markers...
r22260 parents = marker.parentnodes()
if parents is not None:
Yuya Nishihara
debugobsolete: add formatter support (issue5134)...
r29795 fm.write('parentnodes', '{%s} ',
fm.formatlist(map(hex, parents), name='node', sep=', '))
fm.write('date', '(%s) ', fm.formatdate(marker.date()))
meta = marker.metadata().copy()
meta.pop('date', None)
Yuya Nishihara
pycompat: move rapply() from util...
r38594 smeta = pycompat.rapply(pycompat.maybebytestr, meta)
Augie Fackler
cmdutil: add a kludge to make bytes repr() the same on 2 and 3...
r35892 fm.write('metadata', '{%s}', fm.formatdict(smeta, fmt='%r: %r', sep=', '))
Yuya Nishihara
debugobsolete: add formatter support (issue5134)...
r29795 fm.plain('\n')
Pierre-Yves David
debugobsolete: extract marker display in a dedicated function...
r20470
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
Boris Feld
util: extract all date-related utils in utils/dateutil module...
r36625 df = dateutil.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") %
Boris Feld
util: extract all date-related utils in utils/dateutil module...
r36625 (rev, dateutil.datestr(results[rev])))
Pulkit Goyal
py3: use %d to format integers into bytestrings
r32155 return '%d' % rev
Matt Mackall
Add --date support to update and revert...
r3814
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("revision matching date not found"))
Matt Mackall
Add --date support to update and revert...
r3814
Lucas Moscovicz
cmdutil: implemented new lazy increasingwindows...
r20553 def increasingwindows(windowsize=8, sizelimit=512):
while True:
yield windowsize
if windowsize < sizelimit:
windowsize *= 2
Patrick Mezard
cmdutil: extract increasing_windows() from walkchangerevs()...
r16776
Yuya Nishihara
log: duplicate _logrevs() dedicated for walkchangerevs()...
r35700 def _walkrevs(repo, opts):
# Default --rev value depends on --follow but --follow behavior
# depends on revisions resolved from --rev...
follow = opts.get('follow') or opts.get('follow_first')
if opts.get('rev'):
revs = scmutil.revrange(repo, opts['rev'])
elif follow and repo.dirstate.p1() == nullid:
revs = smartset.baseset()
elif follow:
revs = repo.revs('reverse(:.)')
else:
revs = smartset.spanset(repo)
revs.reverse()
return revs
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 = []
Gregory Szorc
global: use pycompat.xrange()...
r38806 for j in pycompat.xrange(0, last + 1):
Durham Goode
log: move log file walk to its own function...
r19290 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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('cannot follow file not in parent '
Durham Goode
log: move log file walk to its own function...
r19290 '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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(
Durham Goode
log: move log file walk to its own function...
r19290 _('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
Martin von Zweigbergk
cleanup: use set literals...
r32291 ancestors = {filelog.linkrev(last)}
Durham Goode
log: move log file walk to its own function...
r19290
# 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
Martin von Zweigbergk
walkchangerevs: make followfilter a top-level class...
r24391 class _followfilter(object):
def __init__(self, repo, onlyfirst=False):
self.repo = repo
self.startrev = nullrev
self.roots = set()
self.onlyfirst = onlyfirst
def match(self, rev):
def realparents(rev):
if self.onlyfirst:
return self.repo.changelog.parentrevs(rev)[0:1]
else:
return filter(lambda x: x != nullrev,
self.repo.changelog.parentrevs(rev))
if self.startrev == nullrev:
self.startrev = rev
return True
if rev > self.startrev:
# forward: all descendants
if not self.roots:
self.roots.add(self.startrev)
for parent in realparents(rev):
if parent in self.roots:
self.roots.add(rev)
return True
else:
# backwards: all parents
if not self.roots:
self.roots.update(realparents(self.startrev))
if rev in self.roots:
self.roots.remove(rev)
self.roots.update(realparents(rev))
return True
return False
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
Yuya Nishihara
grep: rename --allfiles to --all-files...
r38670 allfiles = opts.get('all_files')
Matt Mackall
move walkchangerevs to cmdutils
r3650 follow = opts.get('follow') or opts.get('follow_first')
Yuya Nishihara
log: duplicate _logrevs() dedicated for walkchangerevs()...
r35700 revs = _walkrevs(repo, opts)
Matt Mackall
walkchangerevs: allow empty query sets
r11281 if not revs:
return []
Martin Geisler
replace set-like dictionaries with real sets...
r8152 wanted = set()
Yuya Nishihara
log: make "slowpath" condition slightly more readable...
r35474 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
Matt Mackall
move walkchangerevs to cmdutils
r3650 fncache = {}
Martin von Zweigbergk
log: remove dependence on repo.changectx()...
r37319 change = repo.__getitem__
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.
Sangeet Kumar Mishra
grep: search all commits in allfiles mode...
r38996 if match.always() or allfiles:
Matt Mackall
move walkchangerevs to cmdutils
r3650 # No files, no patterns. Display all revs.
Lucas Moscovicz
cmdutil: implemented new lazy increasingwindows...
r20553 wanted = revs
Martin von Zweigbergk
walkchangerevs: simplify with an 'elif'...
r25271 elif not slowpath:
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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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)
Augie Fackler
py3: use list comprehensions instead of filter where we need to eagerly filter...
r36364 matches = [f for f in ctx.files() if match(f)]
Durham Goode
log: make file log slow path usable on large repos...
r19730 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
# 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()
Martin von Zweigbergk
walkchangerevs: make followfilter a top-level class...
r24391 ff = _followfilter(repo)
Matt Mackall
move walkchangerevs to cmdutils
r3650 stop = min(revs[0], revs[-1])
Gregory Szorc
global: use pycompat.xrange()...
r38806 for x in pycompat.xrange(rev, stop - 1, -1):
Martin Geisler
replace set-like dictionaries with real sets...
r8152 if ff.match(x):
Lucas Moscovicz
cmdutil: implemented new lazy increasingwindows...
r20553 wanted = wanted - [x]
Bryan O'Sullivan
cmdutil: use a small initial window with --limit...
r18710
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():
Martin von Zweigbergk
walkchangerevs: avoid match.files() in conditions...
r25272 if follow and match.always():
Martin von Zweigbergk
walkchangerevs: make followfilter a top-level class...
r24391 ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
Matt Mackall
move walkchangerevs to cmdutils
r3650 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
Lucas Moscovicz
cmdutil: implemented new lazy increasingwindows...
r20553 it = iter(revs)
stopiteration = False
for windowsize in increasingwindows():
nrevs = []
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(windowsize):
Pierre-Yves David
walkchangerevs: replace try/except with 'next'...
r25147 rev = next(it, None)
if rev is None:
Lucas Moscovicz
cmdutil: implemented new lazy increasingwindows...
r20553 stopiteration = True
break
Pierre-Yves David
walkchangerevs: replace try/except with 'next'...
r25147 elif want(rev):
nrevs.append(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():
Sangeet Kumar Mishra
grep: adds allfiles mode...
r38361 if allfiles:
fiter = iter(ctx)
else:
fiter = ctx.files()
for f in fiter:
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)
Lucas Moscovicz
cmdutil: implemented new lazy increasingwindows...
r20553
if stopiteration:
break
Matt Mackall
walkchangerevs: pull out matchfn...
r9652 return iterate()
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034
Matt Harbison
add: pass options via keyword args...
r23885 def add(ui, repo, match, prefix, explicitonly, **opts):
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 = []
Matt Harbison
add: replace match.bad() monkey patching with match.badmatch()...
r25436
badfn = lambda x, y: bad.append(x) or match.bad(x, y)
Martin Geisler
add: move main part to cmdutil to make it easier to reuse
r12269 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)
Matt Harbison
add: replace match.bad() monkey patching with match.badmatch()...
r25436
Durham Goode
add: pass full=False to dirstate walk...
r26206 badmatch = matchmod.badmatch(match, badfn)
dirstate = repo.dirstate
# We don't want to just call wctx.walk here, since it would return a lot of
# clean files, which we aren't interested in and takes time.
Martin von Zweigbergk
dirstate: use keyword arguments to clarify walk()'s callers...
r34344 for f in sorted(dirstate.walk(badmatch, subrepos=sorted(wctx.substate),
unknown=True, ignored=False, full=False)):
Martin Geisler
add: move main part to cmdutil to make it easier to reuse
r12269 exact = match.exact(f)
John Coomes
add: use lexists so that broken symbolic links are added...
r23462 if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
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:
Boris Feld
add: add a label for messages about added files...
r39124 ui.status(_('adding %s\n') % match.rel(f),
label='addremove.added')
Martin Geisler
add: recurse into subrepositories with --subrepos/-S flag
r12270
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:
Martin von Zweigbergk
match: rename "narrowmatcher" to "subdirmatcher" (API)...
r28017 submatch = matchmod.subdirmatcher(subpath, match)
Pulkit Goyal
py3: handle opts correctly for `hg add`...
r32147 if opts.get(r'subrepos'):
Matt Harbison
add: pass options via keyword args...
r23885 bad.extend(sub.add(ui, submatch, prefix, False, **opts))
David M. Carr
add: support adding explicit files in subrepos...
r15410 else:
Matt Harbison
add: pass options via keyword args...
r23885 bad.extend(sub.add(ui, submatch, prefix, True, **opts))
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
Pulkit Goyal
py3: handle opts correctly for `hg add`...
r32147 if not opts.get(r'dry_run'):
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
Matt Harbison
serve: add support for Mercurial subrepositories...
r32005 def addwebdirpath(repo, serverpath, webconf):
webconf[serverpath] = repo.root
repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root))
for r in repo.revs('filelog("path:.hgsub")'):
ctx = repo[r]
for subpath in ctx.substate:
ctx.sub(subpath).addwebdirpath(serverpath, webconf)
Sushil khanchi
forget: rename --confirm to --interactive...
r37796 def forget(ui, repo, match, prefix, explicitonly, dryrun, interactive):
if dryrun and interactive:
raise error.Abort(_("cannot specify both --dry-run and --interactive"))
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 join = lambda f: os.path.join(prefix, f)
bad = []
Matt Harbison
forget: replace match.bad() monkey patching with match.badmatch()...
r25437 badfn = lambda x, y: bad.append(x) or match.bad(x, y)
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 wctx = repo[None]
forgot = []
Matt Harbison
forget: replace match.bad() monkey patching with match.badmatch()...
r25437
s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
Martin von Zweigbergk
forget: access status fields by name, not index
r32174 forget = sorted(s.modified + s.added + s.deleted + s.clean)
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 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:
Martin von Zweigbergk
match: rename "narrowmatcher" to "subdirmatcher" (API)...
r28017 submatch = matchmod.subdirmatcher(subpath, match)
Sushil khanchi
forget: rename --confirm to --interactive...
r37796 subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun,
interactive=interactive)
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 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():
Matt Harbison
forget: use vfs instead of os.path + match.rel() for filesystem checks
r23673 if f not in repo.dirstate and not repo.wvfs.isdir(f):
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 if f not in forgot:
Matt Harbison
forget: use vfs instead of os.path + match.rel() for filesystem checks
r23673 if repo.wvfs.exists(f):
Matt Harbison
forget: cleanup the output for an inexact case match on icasefs...
r24548 # Don't complain if the exact case match wasn't given.
# But don't do this until after checking 'forgot', so
# that subrepo files aren't normalized, and this op is
# purely from data cached by the status walk above.
if repo.dirstate.normalize(f) in repo.dirstate:
continue
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 ui.warn(_('not removing %s: '
'file is already untracked\n')
Matt Harbison
narrowmatcher: propagate the rel() method...
r23686 % match.rel(f))
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 bad.append(f)
Sushil khanchi
forget: rename --confirm to --interactive...
r37796 if interactive:
Sushil khanchi
forget: add --confirm option...
r37774 responses = _('[Ynsa?]'
'$$ &Yes, forget this file'
'$$ &No, skip this file'
'$$ &Skip remaining files'
'$$ Include &all remaining files'
'$$ &? (display help)')
for filename in forget[:]:
r = ui.promptchoice(_('forget %s %s') % (filename, responses))
if r == 4: # ?
while r == 4:
for c, t in ui.extractchoices(responses)[1]:
ui.write('%s - %s\n' % (c, encoding.lower(t)))
r = ui.promptchoice(_('forget %s %s') % (filename,
responses))
if r == 0: # yes
continue
elif r == 1: # no
forget.remove(filename)
elif r == 2: # Skip
fnindex = forget.index(filename)
del forget[fnindex:]
break
elif r == 3: # All
break
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 for f in forget:
Sushil khanchi
forget: rename --confirm to --interactive...
r37796 if ui.verbose or not match.exact(f) or interactive:
Boris Feld
remove: add a label for messages about removed files...
r39125 ui.status(_('removing %s\n') % match.rel(f),
label='addremove.removed')
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912
Sushil khanchi
forget: add --dry-run mode
r36957 if not dryrun:
rejected = wctx.forget(forget, prefix)
bad.extend(f for f in rejected if f in match.files())
forgot.extend(f for f in forget if f not in rejected)
David M. Carr
forget: fix subrepo recursion for explicit path handling...
r15912 return bad, forgot
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413 def files(ui, ctx, m, fm, fmt, subrepos):
Matt Harbison
files: split reusable implementation into cmdutil for subrepo support
r24275 ret = 1
Yuya Nishihara
files: automatically populate fields referenced from template
r38559 needsfctx = ui.verbose or {'size', 'flags'} & fm.datahint()
Matt Harbison
files: split reusable implementation into cmdutil for subrepo support
r24275 for f in ctx.matches(m):
fm.startitem()
Yuya Nishihara
files: add support for log-like template keywords and functions...
r38560 fm.context(ctx=ctx)
Yuya Nishihara
files: automatically populate fields referenced from template
r38559 if needsfctx:
Matt Harbison
files: split reusable implementation into cmdutil for subrepo support
r24275 fc = ctx[f]
fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
fm.data(abspath=f)
fm.write('path', fmt, m.rel(f))
ret = 0
Matt Harbison
files: recurse into subrepos automatically with an explicit path
r25228 for subpath in sorted(ctx.substate):
Hannes Oldenburg
subrepo: cleanup of subrepo filematcher logic...
r29802 submatch = matchmod.subdirmatcher(subpath, m)
if (subrepos or m.exact(subpath) or any(submatch.files())):
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413 sub = ctx.sub(subpath)
try:
Matt Harbison
files: don't recurse into subrepos without a path or -S (issue5127)...
r28387 recurse = m.exact(subpath) or subrepos
if sub.printfiles(ui, submatch, fm, fmt, recurse) == 0:
Matt Harbison
subrepo: add basic support to hgsubrepo for the files command...
r24413 ret = 0
except error.LookupError:
ui.status(_("skipping missing subrepository: %s\n")
% m.abs(subpath))
Matt Harbison
files: split reusable implementation into cmdutil for subrepo support
r24275 return ret
Sushil khanchi
remove: add dry-run functionality
r37168 def remove(ui, repo, m, prefix, after, force, subrepos, dryrun, warnings=None):
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 join = lambda f: os.path.join(prefix, f)
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 ret = 0
s = repo.status(match=m, clean=True)
modified, added, deleted, clean = s[0], s[1], s[3], s[6]
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 wctx = repo[None]
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 if warnings is None:
warnings = []
warn = True
else:
warn = False
timeless
remove: add progress support
r28608 subs = sorted(wctx.substate)
Martin von Zweigbergk
remove: use progress helper...
r38366 progress = ui.makeprogress(_('searching'), total=len(subs),
unit=_('subrepos'))
timeless
remove: add progress support
r28608 for subpath in subs:
Hannes Oldenburg
subrepo: cleanup of subrepo filematcher logic...
r29802 submatch = matchmod.subdirmatcher(subpath, m)
if subrepos or m.exact(subpath) or any(submatch.files()):
Martin von Zweigbergk
remove: use progress helper...
r38366 progress.increment()
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 sub = wctx.sub(subpath)
try:
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 if sub.removefiles(submatch, prefix, after, force, subrepos,
Sushil khanchi
remove: add dry-run functionality
r37168 dryrun, warnings):
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 ret = 1
except error.LookupError:
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 warnings.append(_("skipping missing subrepository: %s\n")
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 % join(subpath))
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392 progress.complete()
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 # warn about failure to delete explicit files/dirs
Drew Gottlieb
util: move dirs() and finddirs() from scmutil to util...
r24635 deleteddirs = util.dirs(deleted)
timeless
remove: add progress support
r28608 files = m.files()
Martin von Zweigbergk
remove: use progress helper...
r38366 progress = ui.makeprogress(_('deleting'), total=len(files),
unit=_('files'))
timeless
remove: add progress support
r28608 for f in files:
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 def insubrepo():
for subpath in wctx.substate:
Hannes Oldenburg
cmdutil: warnings not issued in remove if subrepopath overlaps...
r29622 if f.startswith(subpath + '/'):
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325 return True
return False
Martin von Zweigbergk
remove: use progress helper...
r38366 progress.increment()
Martin von Zweigbergk
remove: use ctx.hasdir(f) instead of 'f in ctx.dirs()'...
r24955 isdir = f in deleteddirs or wctx.hasdir(f)
Hannes Oldenburg
cmdutil: warnings not issued in remove if subrepopath overlaps...
r29622 if (f in repo.dirstate or isdir or f == '.'
or insubrepo() or f in subs):
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 continue
Matt Harbison
remove: recurse into subrepositories with --subrepos/-S flag...
r23325
Matt Harbison
remove: use vfs instead of os.path + match.rel() for filesystem checks
r23674 if repo.wvfs.exists(f):
if repo.wvfs.isdir(f):
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 warnings.append(_('not removing %s: no tracked files\n')
Matt Harbison
narrowmatcher: propagate the rel() method...
r23686 % m.rel(f))
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 else:
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 warnings.append(_('not removing %s: file is untracked\n')
Matt Harbison
narrowmatcher: propagate the rel() method...
r23686 % m.rel(f))
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 # missing files will generate a warning elsewhere
ret = 1
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392 progress.complete()
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289
if force:
list = modified + deleted + clean + added
elif after:
list = deleted
timeless
remove: add progress support
r28608 remaining = modified + added + clean
Martin von Zweigbergk
remove: use progress helper...
r38366 progress = ui.makeprogress(_('skipping'), total=len(remaining),
unit=_('files'))
timeless
remove: add progress support
r28608 for f in remaining:
Martin von Zweigbergk
remove: use progress helper...
r38366 progress.increment()
pavanpc@fb.com
remove: print message for each file in verbose mode only while using `-A` (BC)...
r35120 if ui.verbose or (f in files):
warnings.append(_('not removing %s: file still exists\n')
% m.rel(f))
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 ret = 1
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392 progress.complete()
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 else:
list = deleted + clean
Martin von Zweigbergk
remove: use progress helper...
r38366 progress = ui.makeprogress(_('skipping'),
total=(len(modified) + len(added)),
unit=_('files'))
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 for f in modified:
Martin von Zweigbergk
remove: use progress helper...
r38366 progress.increment()
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 warnings.append(_('not removing %s: file is modified (use -f'
Matt Harbison
narrowmatcher: propagate the rel() method...
r23686 ' to force removal)\n') % m.rel(f))
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 ret = 1
for f in added:
Martin von Zweigbergk
remove: use progress helper...
r38366 progress.increment()
timeless
remove: specify hg in added warning
r29963 warnings.append(_("not removing %s: file has been marked for add"
" (use 'hg forget' to undo add)\n") % m.rel(f))
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 ret = 1
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392 progress.complete()
timeless
remove: add progress support
r28608
list = sorted(list)
Martin von Zweigbergk
remove: use progress helper...
r38366 progress = ui.makeprogress(_('deleting'), total=len(list),
unit=_('files'))
timeless
remove: add progress support
r28608 for f in list:
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 if ui.verbose or not m.exact(f):
Martin von Zweigbergk
remove: use progress helper...
r38366 progress.increment()
Boris Feld
remove: add a label for messages about removed files...
r39125 ui.status(_('removing %s\n') % m.rel(f),
label='addremove.removed')
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392 progress.complete()
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289
Sushil khanchi
remove: add dry-run functionality
r37168 if not dryrun:
with repo.wlock():
if not after:
for f in list:
if f in added:
continue # we never unlink added files on remove
Kyle Lippincott
unlinkpath: make empty directory removal optional (issue5901) (issue5826)...
r38512 rmdir = repo.ui.configbool('experimental',
'removeemptydirs')
repo.wvfs.unlinkpath(f, ignoremissing=True, rmdir=rmdir)
Sushil khanchi
remove: add dry-run functionality
r37168 repo[None].forget(list)
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289
timeless
remove: queue warnings until after status messages (issue5140) (API)...
r28607 if warn:
for warning in warnings:
ui.warn(warning)
Matt Harbison
remove: move most of the implementation into cmdutils.remove()...
r23289 return ret
Matt Harbison
cat: factor out a function that populates the formatter...
r35680 def _updatecatformatter(fm, ctx, matcher, path, decode):
"""Hook for adding data to the formatter used by ``hg cat``.
Extensions (e.g., lfs) can wrap this to inject keywords/data, but must call
this method first."""
data = ctx[path].data()
if decode:
data = ctx.repo().wwritedata(path, data)
fm.startitem()
Yuya Nishihara
cat: add support for log-like template keywords and functions
r38557 fm.context(ctx=ctx)
Matt Harbison
cat: factor out a function that populates the formatter...
r35680 fm.write('data', '%s', data)
fm.data(abspath=path, path=matcher.rel(path))
Yuya Nishihara
cat: add formatter support...
r32578 def cat(ui, repo, ctx, matcher, basefm, fntemplate, prefix, **opts):
Matt Harbison
cat: move most of the implementation into cmdutils.cat()...
r21040 err = 1
Pulkit Goyal
py3: handle keyword arguments correctly in cmdutil.py...
r35351 opts = pycompat.byteskwargs(opts)
Matt Harbison
cat: move most of the implementation into cmdutils.cat()...
r21040
def write(path):
Yuya Nishihara
cat: add formatter support...
r32578 filename = None
Yuya Nishihara
cat: stop using makefileobj()...
r32576 if fntemplate:
Yuya Nishihara
cmdutil: pass ctx to makefilename() in place of repo/node pair (API)
r36222 filename = makefilename(ctx, fntemplate,
Yuya Nishihara
cat: stop using makefileobj()...
r32576 pathname=os.path.join(prefix, path))
Ryan McElroy
cmdutil: create dirs for templated cat file output...
r35010 # attempt to create the directory if it does not already exist
try:
os.makedirs(os.path.dirname(filename))
except OSError:
pass
Yuya Nishihara
formatter: carry opts to file-based formatters by basefm...
r37615 with formatter.maybereopen(basefm, filename) as fm:
Matt Harbison
cat: factor out a function that populates the formatter...
r35680 _updatecatformatter(fm, ctx, matcher, path, opts.get('decode'))
Matt Harbison
cat: move most of the implementation into cmdutils.cat()...
r21040
# Automation often uses hg cat on single files, so special case it
# for performance to avoid the cost of parsing the manifest.
if len(matcher.files()) == 1 and not matcher.anypats():
file = matcher.files()[0]
Durham Goode
manifest: remove manifest.find...
r30340 mfl = repo.manifestlog
Yuya Nishihara
cat: use ctx.manifestnode() in place of ctx._changeset[0]
r24718 mfnode = ctx.manifestnode()
Durham Goode
manifest: remove manifest.find...
r30340 try:
if mfnode and mfl[mfnode].find(file)[0]:
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
Durham Goode
manifest: remove manifest.find...
r30340 write(file)
return 0
except KeyError:
pass
Matt Harbison
cat: move most of the implementation into cmdutils.cat()...
r21040
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780 scmutil.prefetchfiles(repo, [ctx.rev()], matcher)
for abs in ctx.walk(matcher):
Matt Harbison
cat: move most of the implementation into cmdutils.cat()...
r21040 write(abs)
err = 0
Matt Harbison
cat: support cat with explicit paths in subrepos...
r21041
for subpath in sorted(ctx.substate):
sub = ctx.sub(subpath)
try:
Martin von Zweigbergk
match: rename "narrowmatcher" to "subdirmatcher" (API)...
r28017 submatch = matchmod.subdirmatcher(subpath, matcher)
Matt Harbison
cat: support cat with explicit paths in subrepos...
r21041
Yuya Nishihara
cat: add formatter support...
r32578 if not sub.cat(submatch, basefm, fntemplate,
Pulkit Goyal
py3: handle keyword arguments correctly in cmdutil.py...
r35351 os.path.join(prefix, sub._path),
**pycompat.strkwargs(opts)):
Matt Harbison
cat: support cat with explicit paths in subrepos...
r21041 err = 0
except error.RepoLookupError:
ui.status(_("skipping missing subrepository: %s\n")
% os.path.join(prefix, subpath))
Matt Harbison
cat: move most of the implementation into cmdutils.cat()...
r21040 return err
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:
Boris Feld
util: extract all date-related utils in utils/dateutil module...
r36625 opts['date'] = dateutil.parsedate(date)
Idan Kamara
cmdutil, logmessage: use ui.fin when reading from '-'
r14635 message = logmessage(ui, opts)
Matt Harbison
scmutil: pass a matcher to scmutil.addremove() instead of a list of patterns...
r23533 matcher = scmutil.match(repo[None], pats, opts)
Bryan O'Sullivan
commands: move commit to cmdutil as wrapper for commit-like functions
r5034
Martin von Zweigbergk
commit: don't let failed commit with --addremove update dirstate (issue5645)...
r33619 dsguard = None
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
Martin von Zweigbergk
commit: move dirstateguard creation out of try-block...
r33822 if opts.get('addremove'):
dsguard = dirstateguard.dirstateguard(repo, 'commit')
Martin von Zweigbergk
commit: use context manager with dirstateguard...
r33823 with dsguard or util.nullcontextmanager():
Martin von Zweigbergk
commit: move dirstateguard creation out of try-block...
r33822 if dsguard:
Martin von Zweigbergk
commit: don't let failed commit with --addremove update dirstate (issue5645)...
r33619 if scmutil.addremove(repo, matcher, "", opts) != 0:
raise error.Abort(
_("failed to mark all new/missing files as added/removed"))
Martin von Zweigbergk
commit: use context manager with dirstateguard...
r33823 return commitfunc(ui, repo, message, matcher, opts)
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407
Hannes Oldenburg
cmdutil: extract samefile function from amend()
r29819 def samefile(f, ctx1, ctx2):
if f in ctx1.manifest():
a = ctx1.filectx(f)
if f in ctx2.manifest():
b = ctx2.filectx(f)
return (not a.cmp(b)
and a.flags() == b.flags())
else:
return False
else:
return f not in ctx2.manifest()
Saurabh Singh
cmdutil: remove redundant commitfunc parameter in amend (API)...
r34088 def amend(ui, repo, old, extra, pats, opts):
Gregory Szorc
cmdutil: break import cycle...
r25930 # avoid cycle context -> subrepo -> cmdutil
Gregory Szorc
cmdutil: use absolute_import...
r28322 from . import context
Gregory Szorc
cmdutil: break import cycle...
r25930
Matt Harbison
amend: abort early if no username is configured with evolve enabled (issue4211)...
r23101 # amend will reuse the existing user if not specified, but the obsolete
# marker creation requires that the current user's name is specified.
Durham Goode
obsolete: remove last instance of _enabled...
r24379 if obsolete.isenabled(repo, obsolete.createmarkersopt):
Matt Harbison
amend: abort early if no username is configured with evolve enabled (issue4211)...
r23101 ui.username() # raise exception if username not set
Idan Kamara
commit: add option to amend the working dir parent...
r16458 ui.note(_('amending changeset %s\n') % old)
base = old.p1()
Boris Feld
bookmark: remove a useless 'recordchange' in the amend code...
r33509 with repo.wlock(), repo.lock(), repo.transaction('amend'):
Jun Wu
codemod: simplify nested withs...
r33438 # Participating changesets:
#
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 # wctx o - workingctx that contains changes from working copy
# | to go into amending commit
Jun Wu
codemod: simplify nested withs...
r33438 # |
# old o - changeset to amend
# |
Saurabh Singh
amend: rectify comment...
r34058 # base o - first parent of the changeset to amend
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 wctx = repo[None]
Jun Wu
codemod: simplify nested withs...
r33438
Martin von Zweigbergk
amend: make a copy of "extra" to avoid mutating an input...
r35197 # Copy to avoid mutating input
extra = extra.copy()
Jun Wu
codemod: simplify nested withs...
r33438 # Update extra dict from amended commit (e.g. to preserve graft
# source)
extra.update(old.extra())
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 # Also update it from the from the wctx
extra.update(wctx.extra())
user = opts.get('user') or old.user()
date = opts.get('date') or old.date()
Jun Wu
codemod: simplify nested withs...
r33438
Boris Feld
cmdutil: fix amend when passing a date...
r34123 # Parse the date to allow comparison between date and old.date()
Boris Feld
util: extract all date-related utils in utils/dateutil module...
r36625 date = dateutil.parsedate(date)
Boris Feld
cmdutil: fix amend when passing a date...
r34123
Jun Wu
codemod: simplify nested withs...
r33438 if len(old.parents()) > 1:
# ctx.files() isn't reliable for merges, so fall back to the
# slower repo.status() method
Martin von Zweigbergk
amend: use ctx1.status(ctx2) instead of repo.status(ctx1, ctx2)...
r38792 files = set([fn for st in base.status(old)[:3]
Jun Wu
codemod: simplify nested withs...
r33438 for fn in st])
else:
files = set(old.files())
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 # add/remove the files to the working copy if the "addremove" option
# was specified.
matcher = scmutil.match(wctx, pats, opts)
if (opts.get('addremove')
and scmutil.addremove(repo, matcher, "", opts)):
raise error.Abort(
_("failed to mark all new/missing files as added/removed"))
Yuya Nishihara
amend: update .hgsubstate before committing a memctx (issue5677)...
r35019 # Check subrepos. This depends on in-place wctx._status update in
# subrepo.precommit(). To minimize the risk of this hack, we do
# nothing if .hgsub does not exist.
if '.hgsub' in wctx or '.hgsub' in old:
Yuya Nishihara
subrepo: split non-core functions to new module...
r36026 subs, commitsubs, newsubstate = subrepoutil.precommit(
Yuya Nishihara
amend: update .hgsubstate before committing a memctx (issue5677)...
r35019 ui, wctx, wctx._status, matcher)
# amend should abort if commitsubrepos is enabled
assert not commitsubs
if subs:
Yuya Nishihara
subrepo: split non-core functions to new module...
r36026 subrepoutil.writestate(repo, newsubstate)
Yuya Nishihara
amend: update .hgsubstate before committing a memctx (issue5677)...
r35019
Yuya Nishihara
amend: abort if unresolved merge conflicts found (issue5805)...
r36927 ms = mergemod.mergestate.read(repo)
mergeutil.checkunresolved(ms)
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 filestoamend = set(f for f in wctx.files() if matcher(f))
changes = (len(filestoamend) > 0)
if changes:
Jun Wu
codemod: simplify nested withs...
r33438 # Recompute copies (avoid recording a -> b -> a)
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 copied = copies.pathcopies(base, wctx, matcher)
Jun Wu
codemod: simplify nested withs...
r33438 if old.p2:
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 copied.update(copies.pathcopies(old.p2(), wctx, matcher))
Jun Wu
codemod: simplify nested withs...
r33438
# Prune files which were reverted by the updates: if old
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 # introduced file X and the file was renamed in the working
# copy, then those two files are the same and
Jun Wu
codemod: simplify nested withs...
r33438 # we can discard X from our list of files. Likewise if X
Yuya Nishihara
amend: do not drop missing files (issue5732)...
r35016 # was removed, it's no longer relevant. If X is missing (aka
# deleted), old X must be preserved.
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 files.update(filestoamend)
Yuya Nishihara
amend: do not drop missing files (issue5732)...
r35016 files = [f for f in files if (not samefile(f, wctx, base)
or f in wctx.deleted())]
Jun Wu
codemod: simplify nested withs...
r33438
def filectxfn(repo, ctx_, path):
try:
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 # If the file being considered is not amongst the files
# to be amended, we should return the file context from the
# old changeset. This avoids issues when only some files in
# the working copy are being amended but there are also
# changes to other files from the old changeset.
if path not in filestoamend:
return old.filectx(path)
Yuya Nishihara
amend: do not take untracked files as modified or clean (issue5732)...
r35015 # Return None for removed files.
if path in wctx.removed():
return None
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 fctx = wctx[path]
Jun Wu
codemod: simplify nested withs...
r33438 flags = fctx.flags()
Martin von Zweigbergk
memfilectx: make changectx argument mandatory in constructor (API)...
r35401 mctx = context.memfilectx(repo, ctx_,
Jun Wu
codemod: simplify nested withs...
r33438 fctx.path(), fctx.data(),
islink='l' in flags,
isexec='x' in flags,
copied=copied.get(path))
return mctx
except KeyError:
return None
else:
ui.note(_('copying changeset %s to %s\n') % (old, base))
# Use version of files as in the old cset
def filectxfn(repo, ctx_, path):
try:
return old.filectx(path)
except KeyError:
return None
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 # 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)
Jun Wu
codemod: simplify nested withs...
r33438 editform = mergeeditform(old, 'commit.amend')
editor = getcommiteditor(editform=editform,
**pycompat.strkwargs(opts))
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087
Jun Wu
codemod: simplify nested withs...
r33438 if not message:
editor = getcommiteditor(edit=True, editform=editform)
message = old.description()
pureextra = extra.copy()
extra['amend_source'] = old.hex()
new = context.memctx(repo,
parents=[base.node(), old.p2().node()],
text=message,
files=files,
filectxfn=filectxfn,
user=user,
date=date,
extra=extra,
editor=editor)
newdesc = changelog.stripdesc(new.description())
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 if ((not changes)
Jun Wu
codemod: simplify nested withs...
r33438 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.
Pierre-Yves David
amend: wrap all commit operations in a single transaction...
r17472 #
Jun Wu
codemod: simplify nested withs...
r33438 # This not what we expect from amend.
return old.node()
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 commitphase = None
Martin von Zweigbergk
amend: use context manager for config override...
r34083 if opts.get('secret'):
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 commitphase = phases.secret
newid = repo.commitctx(new)
Saurabh Singh
amend: removing redundant if condition...
r34057
# Reroute the working copy parent to the new changeset
repo.setparents(newid, nullid)
mapping = {old.node(): (newid,)}
Pulkit Goyal
cmdutil: pass metadata from amend() to cleanupnodes...
r34795 obsmetadata = None
if opts.get('note'):
Yuya Nishihara
obsolete: store user name and note in UTF-8 (issue5754) (BC)...
r38729 obsmetadata = {'note': encoding.fromlocal(opts['note'])}
Sushil khanchi
amend: support "history-editing-backup" config option...
r38853 backup = ui.configbool('ui', 'history-editing-backup')
Martin von Zweigbergk
scmutil: make cleanupnodes optionally also fix the phase...
r38442 scmutil.cleanupnodes(repo, mapping, 'amend', metadata=obsmetadata,
Sushil khanchi
amend: support "history-editing-backup" config option...
r38853 fixphase=True, targetphase=commitphase,
backup=backup)
Saurabh Singh
amend: removing redundant if condition...
r34057
Saurabh Singh
cmdutil: remove the redundant commit during amend...
r34087 # Fixing the dirstate because localrepo.commitctx does not update
# it. This is rather convenient because we did not need to update
# the dirstate for all the files in the new commit which commitctx
# could have done if it updated the dirstate. Now, we can
# selectively update the dirstate only for the amended files.
dirstate = repo.dirstate
# Update the state of the files which were added and
# and modified in the amend to "normal" in the dirstate.
normalfiles = set(wctx.modified() + wctx.added()) & filestoamend
for f in normalfiles:
dirstate.normal(f)
# Update the state of files which were removed in the amend
# to "removed" in the dirstate.
removedfiles = set(wctx.removed()) & filestoamend
for f in removedfiles:
dirstate.drop(f)
Idan Kamara
commit: add option to amend the working dir parent...
r16458 return newid
FUJIWARA Katsunori
cmdutil: introduce 'editform' to distinguish the purpose of commit text editing...
r21999 def commiteditor(repo, ctx, subs, editform=''):
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 if ctx.description():
return ctx.description()
Tony Tung
commit: abort when a committemplate is not changed...
r26742 return commitforceeditor(repo, ctx, subs, editform=editform,
unchangedmessagedetection=True)
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407
FUJIWARA Katsunori
cmdutil: introduce 'editform' to distinguish the purpose of commit text editing...
r21999 def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None,
Tony Tung
commit: abort when a committemplate is not changed...
r26742 editform='', unchangedmessagedetection=False):
Matt Mackall
commiteditor: refactor default extramsg
r21923 if not extramsg:
extramsg = _("Leave message empty to abort commit.")
FUJIWARA Katsunori
cmdutil: look commit template definition up by specified 'editform'...
r22012
forms = [e for e in editform.split('.') if e]
forms.insert(0, 'changeset')
Tony Tung
commit: abort when a committemplate is not changed...
r26742 templatetext = None
FUJIWARA Katsunori
cmdutil: look commit template definition up by specified 'editform'...
r22012 while forms:
Yuya Nishihara
commit: select template by spec.ref name...
r32878 ref = '.'.join(forms)
if repo.ui.config('committemplate', ref):
Tony Tung
commit: abort when a committemplate is not changed...
r26742 templatetext = committext = buildcommittemplate(
Yuya Nishihara
commit: select template by spec.ref name...
r32878 repo, ctx, subs, extramsg, ref)
FUJIWARA Katsunori
cmdutil: look commit template definition up by specified 'editform'...
r22012 break
forms.pop()
FUJIWARA Katsunori
cmdutil: make commit message shown in text editor customizable by template...
r21924 else:
committext = buildcommittext(repo, ctx, subs, extramsg)
FUJIWARA Katsunori
cmdutil: separate building commit text from 'commitforceeditor'...
r21869
# run editor in the repository root
Pulkit Goyal
py3: use pycompat.getcwd() instead of os.getcwd()...
r30519 olddir = pycompat.getcwd()
FUJIWARA Katsunori
cmdutil: separate building commit text from 'commitforceeditor'...
r21869 os.chdir(repo.root)
FUJIWARA Katsunori
cmdutil: make in-memory changes visible to external editor (issue4378)...
r26750
# make in-memory changes visible to external process
tr = repo.currenttransaction()
repo.dirstate.write(tr)
pending = tr and tr.writepending() and repo.root
Tony Tung
commit: abort when a committemplate is not changed...
r26742 editortext = repo.ui.edit(committext, ctx.user(), ctx.extra(),
Sean Farley
cmdutil: add tmpdir parament to ui.edit calls
r30836 editform=editform, pending=pending,
Michael Bolin
editor: use an unambiguous path suffix for editor files...
r34030 repopath=repo.path, action='commit')
Yuya Nishihara
commit: fix unmodified message detection for the "--- >8 ----" magic...
r30724 text = editortext
Sean Farley
cmdutil: add special string that ignores rest of text...
r30703
# strip away anything below this special string (used for editors that want
# to display the diff)
Yuya Nishihara
commit: fix unmodified message detection for the "--- >8 ----" magic...
r30724 stripbelow = re.search(_linebelow, text, flags=re.MULTILINE)
Sean Farley
cmdutil: add special string that ignores rest of text...
r30703 if stripbelow:
Yuya Nishihara
commit: fix unmodified message detection for the "--- >8 ----" magic...
r30724 text = text[:stripbelow.start()]
text = re.sub("(?m)^HG:.*(\n|$)", "", text)
FUJIWARA Katsunori
cmdutil: separate building commit text from 'commitforceeditor'...
r21869 os.chdir(olddir)
if finishdesc:
text = finishdesc(text)
if not text.strip():
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("empty commit message"))
Tony Tung
commit: abort when a committemplate is not changed...
r26742 if unchangedmessagedetection and editortext == templatetext:
raise error.Abort(_("commit message unchanged"))
FUJIWARA Katsunori
cmdutil: separate building commit text from 'commitforceeditor'...
r21869
return text
Yuya Nishihara
commit: select template by spec.ref name...
r32878 def buildcommittemplate(repo, ctx, subs, extramsg, ref):
FUJIWARA Katsunori
cmdutil: make commit message shown in text editor customizable by template...
r21924 ui = repo.ui
Yuya Nishihara
commit: select template by spec.ref name...
r32878 spec = formatter.templatespec(ref, None, None)
Yuya Nishihara
logcmdutil: drop default arguments from changesetdisplayer/templater() calls
r35972 t = logcmdutil.changesettemplater(ui, repo, spec)
Yuya Nishihara
commit: select template by spec.ref name...
r32878 t.t.cache.update((k, templater.unquotestring(v))
for k, v in repo.ui.configitems('committemplate'))
FUJIWARA Katsunori
cmdutil: use '[committemplate]' section like as map file for style definition...
r22013
FUJIWARA Katsunori
cmdutil: make commit message shown in text editor customizable by template...
r21924 if not extramsg:
extramsg = '' # ensure that extramsg is string
ui.pushbuffer()
t.show(ctx, extramsg=extramsg)
return ui.popbuffer()
timeless@mozdev.org
cmdutil: handle multiline translations of HG: messages safely...
r26426 def hgprefix(msg):
return "\n".join(["HG: %s" % a for a in msg.split("\n") if a])
FUJIWARA Katsunori
cmdutil: separate building commit text from 'commitforceeditor'...
r21869 def buildcommittext(repo, ctx, subs, extramsg):
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.
timeless@mozdev.org
cmdutil: handle multiline translations of HG: messages safely...
r26426 edittext.append(hgprefix(_("Enter commit message."
" Lines beginning with 'HG:' are removed.")))
edittext.append(hgprefix(extramsg))
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 edittext.append("HG: --")
timeless@mozdev.org
cmdutil: handle multiline translations of HG: messages safely...
r26426 edittext.append(hgprefix(_("user: %s") % ctx.user()))
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 if ctx.p2():
timeless@mozdev.org
cmdutil: handle multiline translations of HG: messages safely...
r26426 edittext.append(hgprefix(_("branch merge")))
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 if ctx.branch():
timeless@mozdev.org
cmdutil: handle multiline translations of HG: messages safely...
r26426 edittext.append(hgprefix(_("branch '%s'") % ctx.branch()))
Ryan McElroy
bookmarks: simplify iscurrent to isactivewdirparent (API)...
r24986 if bookmarks.isactivewdirparent(repo):
timeless@mozdev.org
cmdutil: handle multiline translations of HG: messages safely...
r26426 edittext.append(hgprefix(_("bookmark '%s'") % repo._activebookmark))
edittext.extend([hgprefix(_("subrepo %s") % s) for s in subs])
edittext.extend([hgprefix(_("added %s") % f) for f in added])
edittext.extend([hgprefix(_("changed %s") % f) for f in modified])
edittext.extend([hgprefix(_("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:
timeless@mozdev.org
cmdutil: handle multiline translations of HG: messages safely...
r26426 edittext.append(hgprefix(_("no files changed")))
Matt Mackall
commit: move commit editor to cmdutil, pass as function
r8407 edittext.append("")
FUJIWARA Katsunori
cmdutil: separate building commit text from 'commitforceeditor'...
r21869 return "\n".join(edittext)
Adrian Buehlmann
commands: use a decorator to build table incrementally...
r14297
Pierre-Yves David
addremove: remove a mutable default argument...
r26324 def commitstatus(repo, node, branch, bheads=None, opts=None):
if opts is None:
opts = {}
Kevin Bullock
commit: factor out status printing into a helper function...
r18688 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:
Gregory Szorc
cmdutil: use ctx.rev() instead of %d % ctx...
r36424 repo.ui.status(_('reopening closed branch head %d\n') % r.rev())
Kevin Bullock
commit: factor out status printing into a helper function...
r18688
if repo.ui.debugflag:
Gregory Szorc
cmdutil: use ctx.rev() instead of int(ctx)...
r36420 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx.hex()))
Kevin Bullock
commit: factor out status printing into a helper function...
r18688 elif repo.ui.verbose:
Gregory Szorc
cmdutil: use ctx.rev() instead of int(ctx)...
r36420 repo.ui.write(_('committed changeset %d:%s\n') % (ctx.rev(), ctx))
Kevin Bullock
commit: factor out status printing into a helper function...
r18688
Matt Harbison
commit: factor the post commit status check into a cmdutil method...
r27943 def postcommitstatus(repo, pats, opts):
return repo.status(match=scmutil.match(repo[None], pats, opts))
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 def revert(ui, repo, ctx, parents, *pats, **opts):
Pulkit Goyal
py3: fix handling of keyword arguments in revert...
r35148 opts = pycompat.byteskwargs(opts)
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 parent, p2 = parents
node = ctx.node()
mf = ctx.manifest()
Pierre-Yves David
revert: use p2 as parent when reverting against it...
r21579 if node == p2:
parent = p2
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
# 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
Yuya Nishihara
revert: comment that filesets are always evaluated against workingctx
r24451 # but not other. in both cases, filesets should be evaluated against
# workingctx to get consistent result (issue4497). this means 'set:**'
# cannot be used to select missing files from target rev.
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
Pierre-Yves David
revert: add some inline comments...
r21575 # `names` is a mapping for all elements in working copy and target revision
# The mapping is in the form:
Sushil khanchi
cmdutil: fix typo in revert()...
r39323 # <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 names = {}
Bryan O'Sullivan
with: use context manager for wlock in revert
r27803 with repo.wlock():
Pierre-Yves David
revert: add some inline comments...
r21575 ## filling of the `names` mapping
# walk dirstate to fill `names`
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
Laurent Charignon
revert: fix --interactive on local modification (issue4576)...
r24475 interactive = opts.get('interactive', False)
Martin von Zweigbergk
revert: define 'wctx' a little earlier and use it more
r24449 wctx = repo[None]
m = scmutil.match(wctx, pats, opts)
Matt Mackall
revert: move calculation of targetsubs earlier
r24479
# we'll need this later
targetsubs = sorted(s for s in wctx.substate if m(s))
Martin von Zweigbergk
revert: take fast path also when not reverting to '.'...
r24450 if not m.always():
Augie Fackler
cmdutil: use repo[None].walk instead of repo.walk
r32362 matcher = matchmod.badmatch(m, lambda x, y: False)
Martin von Zweigbergk
cleanup: reuse existing wctx variables instead of calling repo[None]...
r32382 for abs in wctx.walk(matcher):
Durham Goode
revert: special case 'hg revert --all'...
r22573 names[abs] = m.rel(abs), m.exact(abs)
# walk target manifest to fill `names`
def badfn(path, msg):
if path in names:
return
if path in ctx.substate:
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 return
Durham Goode
revert: special case 'hg revert --all'...
r22573 path_ = path + '/'
for f in names:
if f.startswith(path_):
return
ui.warn("%s: %s\n" % (m.rel(path), msg))
Matt Harbison
revert: replace match.bad() monkey patching with match.badmatch()...
r25439 for abs in ctx.walk(matchmod.badmatch(m, badfn)):
Durham Goode
revert: special case 'hg revert --all'...
r22573 if abs not in names:
names[abs] = m.rel(abs), m.exact(abs)
# Find status of all file in `names`.
m = scmutil.matchfiles(repo, names)
changes = repo.status(node1=node, match=m,
unknown=True, ignored=True, clean=True)
else:
Martin von Zweigbergk
revert: take fast path also when not reverting to '.'...
r24450 changes = repo.status(node1=node, match=m)
Durham Goode
revert: special case 'hg revert --all'...
r22573 for kind in changes:
for abs in kind:
names[abs] = m.rel(abs), m.exact(abs)
m = scmutil.matchfiles(repo, names)
Martin von Zweigbergk
revert: access status fields by name rather than index...
r23374 modified = set(changes.modified)
added = set(changes.added)
removed = set(changes.removed)
_deleted = set(changes.deleted)
unknown = set(changes.unknown)
unknown.update(changes.ignored)
clean = set(changes.clean)
Pierre-Yves David
revert: track added files with local modifications...
r22610 modadded = set()
Pierre-Yves David
revert: triage "deleted" files into more appropriate categories...
r22185
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r24180 # We need to account for the state of the file in the dirstate,
# even when we revert against something else than parent. This will
Pierre-Yves David
revert: call status against revert target too...
r22155 # slightly alter the behavior of revert (doing back up or not, delete
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 # or just forget etc).
Pierre-Yves David
revert: call status against revert target too...
r22155 if parent == node:
dsmodified = modified
dsadded = added
dsremoved = removed
Pierre-Yves David
revert: look for copy information for all local modifications...
r23403 # store all local modifications, useful later for rename detection
localchanges = dsmodified | dsadded
Pierre-Yves David
revert: call status against revert target too...
r22155 modified, added, removed = set(), set(), set()
else:
changes = repo.status(node1=parent, match=m)
Martin von Zweigbergk
revert: access status fields by name rather than index...
r23374 dsmodified = set(changes.modified)
dsadded = set(changes.added)
dsremoved = set(changes.removed)
Pierre-Yves David
revert: look for copy information for all local modifications...
r23403 # store all local modifications, useful later for rename detection
localchanges = dsmodified | dsadded
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
Pierre-Yves David
revert: use "remove" information from both statuses...
r22188 # only take into account for removes between wc and target
clean |= dsremoved - removed
dsremoved &= removed
# distinct between dirstate remove and other
removed -= dsremoved
Pierre-Yves David
revert: track added files with local modifications...
r22610 modadded = added & dsmodified
added -= modadded
Pierre-Yves David
revert: use modified information from both statuses...
r22190 # tell newly modified apart.
dsmodified &= modified
Augie Fackler
cmdutil: typo fix in comment
r29103 dsmodified |= modified & dsadded # dirstate added may need backup
Pierre-Yves David
revert: use modified information from both statuses...
r22190 modified -= dsmodified
Pierre-Yves David
revert: split between newly added file and file added in other changeset...
r22488 # We need to wait for some post-processing to update this set
# before making the distinction. The dirstate will be used for
# that purpose.
Pierre-Yves David
revert: simplify handling of `added` files...
r22208 dsadded = added
Pierre-Yves David
revert: detect files added during a merge...
r22209 # in case of merge, files that are actually added can be reported as
# modified, we need to post process the result
if p2 != nullid:
Durham Goode
revert: remove set(mf) because it's O(manifest)...
r31134 mergeadd = set(dsmodified)
for path in dsmodified:
if path in mf:
mergeadd.remove(path)
Pierre-Yves David
revert: detect files added during a merge...
r22209 dsadded |= mergeadd
dsmodified -= mergeadd
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
Pierre-Yves David
revert: add some inline comments...
r21575 # if f is a rename, update `names` to also revert the source
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 cwd = repo.getcwd()
Pierre-Yves David
revert: look for copy information for all local modifications...
r23403 for f in localchanges:
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 src = repo.dirstate.copied(f)
Pierre-Yves David
revert: add an XXX about rename tracking...
r22213 # XXX should we check for rename down to target node?
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 if src and src not in names and repo.dirstate[src] == 'r':
Pierre-Yves David
revert: prefix variable names for dirstate status with "ds"...
r22154 dsremoved.add(src)
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 names[src] = (repo.pathto(src, cwd), True)
Martin von Zweigbergk
revert: move code dealing with deletions closer together
r31157 # determine the exact nature of the deleted changesets
deladded = set(_deleted)
for path in _deleted:
if path in mf:
deladded.remove(path)
deleted = _deleted - deladded
Pierre-Yves David
revert: split between newly added file and file added in other changeset...
r22488 # distinguish between file to forget and the other
added = set()
for abs in dsadded:
if repo.dirstate[abs] != 'a':
added.add(abs)
dsadded -= added
Pierre-Yves David
revert: explicitly track added but deleted file...
r22490 for abs in deladded:
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 if repo.dirstate[abs] == 'a':
Pierre-Yves David
revert: explicitly track added but deleted file...
r22490 dsadded.add(abs)
deladded -= dsadded
Pierre-Yves David
revert: detect unknown files in the same path as files marked as removed...
r22396 # For files marked as removed, we check if an unknown file is present at
# the same path. If a such file exists it may need to be backed up.
# Making the distinction at this stage helps have simpler backup
# logic.
removunk = set()
for abs in removed:
target = repo.wjoin(abs)
if os.path.lexists(target):
removunk.add(abs)
removed -= removunk
dsremovunk = set()
for abs in dsremoved:
target = repo.wjoin(abs)
if os.path.lexists(target):
dsremovunk.add(abs)
dsremoved -= dsremovunk
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
Pierre-Yves David
revert: add some inline comments...
r21575 # action to be actually performed by revert
# (<list of file>, message>) tuple
Pierre-Yves David
revert: group action into a single dictionary...
r21576 actions = {'revert': ([], _('reverting %s\n')),
'add': ([], _('adding %s\n')),
Pierre-Yves David
revert: have an explicit action for "forget"...
r22489 'remove': ([], _('removing %s\n')),
Pierre-Yves David
revert: add a `drop` action...
r22491 'drop': ([], _('removing %s\n')),
Pierre-Yves David
revert: have an explicit action for "forget"...
r22489 'forget': ([], _('forgetting %s\n')),
Pierre-Yves David
revert: use actions[...] in all disptable cases...
r22231 'undelete': ([], _('undeleting %s\n')),
Pierre-Yves David
revert: add a message to noop action...
r22234 'noop': (None, _('no changes needed to %s\n')),
Pierre-Yves David
revert: handle unknown files through status...
r22236 'unknown': (None, _('file not managed: %s\n')),
Pierre-Yves David
revert: use actions[...] in all disptable cases...
r22231 }
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
Pierre-Yves David
revert: small refactoring in the way backup value are handled...
r22608 # "constant" that convey the backup strategy.
# All set to `discard` if `no-backup` is set do avoid checking
# no_backup lower in the code.
Pierre-Yves David
revert: distinguish between "check" and "backup" strategy...
r22609 # These values are ordered for comparison purposes
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 backupinteractive = 3 # do backup if interactively modified
Pierre-Yves David
revert: small refactoring in the way backup value are handled...
r22608 backup = 2 # unconditionally do backup
Pierre-Yves David
revert: distinguish between "check" and "backup" strategy...
r22609 check = 1 # check if the existing file differs from target
Pierre-Yves David
revert: small refactoring in the way backup value are handled...
r22608 discard = 0 # never do backup
if opts.get('no_backup'):
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 backupinteractive = backup = check = discard
if interactive:
dsmodifiedbackup = backupinteractive
else:
dsmodifiedbackup = backup
tobackup = set()
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
Pierre-Yves David
revert: properly back up added files with local modification...
r22611 backupanddel = actions['remove']
if not opts.get('no_backup'):
backupanddel = actions['drop']
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 disptable = (
# dispatch table:
# file state
Pierre-Yves David
revert: move manifest membership condition outside of the loop...
r22153 # action
# make backup
Pierre-Yves David
revert: add documentation in the dispatch table...
r22371
## Sets that results that will change file on disk
# Modified compared to target, no local change
Pierre-Yves David
revert: add more padding in the dispatch list...
r22372 (modified, actions['revert'], discard),
Pierre-Yves David
revert: distinguish between deleted file and locally modified...
r22397 # Modified compared to target, but local file is deleted
(deleted, actions['revert'], discard),
Pierre-Yves David
revert: add documentation in the dispatch table...
r22371 # Modified compared to target, local change
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 (dsmodified, actions['revert'], dsmodifiedbackup),
Pierre-Yves David
revert: add documentation in the dispatch table...
r22371 # Added since target
Pierre-Yves David
revert: split between newly added file and file added in other changeset...
r22488 (added, actions['remove'], discard),
# Added in working directory
Pierre-Yves David
revert: have an explicit action for "forget"...
r22489 (dsadded, actions['forget'], discard),
Pierre-Yves David
revert: track added files with local modifications...
r22610 # Added since target, have local modification
Pierre-Yves David
revert: properly back up added files with local modification...
r22611 (modadded, backupanddel, backup),
Pierre-Yves David
revert: explicitly track added but deleted file...
r22490 # Added since target but file is missing in working directory
Pierre-Yves David
revert: add a `drop` action...
r22491 (deladded, actions['drop'], discard),
Pierre-Yves David
revert: add documentation in the dispatch table...
r22371 # Removed since target, before working copy parent
Pierre-Yves David
revert: detect unknown files in the same path as files marked as removed...
r22396 (removed, actions['add'], discard),
# Same as `removed` but an unknown file exists at the same path
Pierre-Yves David
revert: distinguish between "check" and "backup" strategy...
r22609 (removunk, actions['add'], check),
Pierre-Yves David
revert: add documentation in the dispatch table...
r22371 # Removed since targe, marked as such in working copy parent
Pierre-Yves David
revert: detect unknown files in the same path as files marked as removed...
r22396 (dsremoved, actions['undelete'], discard),
# Same as `dsremoved` but an unknown file exists at the same path
Pierre-Yves David
revert: distinguish between "check" and "backup" strategy...
r22609 (dsremovunk, actions['undelete'], check),
Pierre-Yves David
revert: add documentation in the dispatch table...
r22371 ## the following sets does not result in any file changes
# File with no modification
Pierre-Yves David
revert: add more padding in the dispatch list...
r22372 (clean, actions['noop'], discard),
Pierre-Yves David
revert: add documentation in the dispatch table...
r22371 # Existing file, not tracked anywhere
Pierre-Yves David
revert: add more padding in the dispatch list...
r22372 (unknown, actions['unknown'], discard),
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 )
for abs, (rel, exact) in sorted(names.items()):
Pierre-Yves David
revert: add some inline comments...
r21575 # target file to be touch on disk (relative to cwd)
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 target = repo.wjoin(abs)
Pierre-Yves David
revert: add some inline comments...
r21575 # search the entry in the dispatch table.
Pierre-Yves David
revert: inline a now useless closure...
r22212 # if the file is in any of these sets, it was touched in the working
Pierre-Yves David
revert: add some inline comments...
r21575 # directory parent and we are sure it needs to be reverted.
Pierre-Yves David
revert: explode the action tuple in the for loop...
r22232 for table, (xlist, msg), dobackup in disptable:
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 if abs not in table:
continue
Pierre-Yves David
revert: simplify loop conditional...
r22233 if xlist is not None:
xlist.append(abs)
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 if dobackup:
# If in interactive mode, don't automatically create
# .orig files (issue4793)
if dobackup == backupinteractive:
tobackup.add(abs)
elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
Siddharth Agarwal
origpath: move from cmdutil to scmutil...
r27651 bakname = scmutil.origpath(ui, repo, rel)
Pierre-Yves David
revert: distinguish between "check" and "backup" strategy...
r22609 ui.note(_('saving current version of %s as %s\n') %
(rel, bakname))
if not opts.get('dry_run'):
Laurent Charignon
revert: fix --interactive on local modification (issue4576)...
r24475 if interactive:
util.copyfile(target, bakname)
else:
util.rename(target, bakname)
Pierre-Yves David
revert: simplify loop conditional...
r22233 if ui.verbose or not exact:
Pulkit Goyal
py3: use bytes in place of basestring...
r35198 if not isinstance(msg, bytes):
Pierre-Yves David
revert: simplify loop conditional...
r22233 msg = msg(abs)
ui.status(msg % rel)
elif exact:
Pierre-Yves David
revert: add a message to noop action...
r22234 ui.warn(msg % rel)
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 break
Pierre-Yves David
revert: add some inline comments...
r21575
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304 if not opts.get('dry_run'):
Durham Goode
revert: move prefetch to after the actions logic...
r23965 needdata = ('revert', 'add', 'undelete')
Matt Harbison
cmdutil: convert _revertprefetch() to a generic stored file hook (API)...
r35941 oplist = [actions[name][0] for name in needdata]
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780 prefetch = scmutil.prefetchfiles
matchfiles = scmutil.matchfiles
prefetch(repo, [ctx.rev()],
matchfiles(repo,
[f for sublist in oplist for f in sublist]))
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 _performrevert(repo, parents, ctx, actions, interactive, tobackup)
Bryan O'Sullivan
revert: ensure that copies and renames are honored (issue3920)...
r19129
Matt Harbison
revert: display full subrepo output with --dry-run...
r24134 if targetsubs:
# Revert the subrepos on the revert list
for sub in targetsubs:
Matt Harbison
revert: handle subrepos missing in the given --rev...
r24463 try:
Pulkit Goyal
py3: fix handling of keyword arguments in revert...
r35148 wctx.sub(sub).revert(ctx.substate[sub], *pats,
**pycompat.strkwargs(opts))
Matt Harbison
revert: handle subrepos missing in the given --rev...
r24463 except KeyError:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort("subrepository '%s' does not exist in %s!"
Matt Harbison
revert: handle subrepos missing in the given --rev...
r24463 % (sub, short(ctx.node())))
Angel Ezquerra
revert: move bulk of revert command from commands to cmdutil...
r16304
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 def _performrevert(repo, parents, ctx, actions, interactive=False,
tobackup=None):
Pierre-Yves David
revert: group action into a single dictionary...
r21576 """function that actually perform all the actions computed for revert
Pierre-Yves David
revert: extract actual revert in its own function...
r20571
This is an independent function to let extension to plug in and react to
the imminent revert.
Mads Kiilerich
spelling: fixes from spell checker
r21024 Make sure you have the working directory locked when calling this function.
Pierre-Yves David
revert: extract actual revert in its own function...
r20571 """
parent, p2 = parents
node = ctx.node()
liscju
revert: makes interactive mode ask to forget added files (issue4936)...
r27985 excluded_files = []
Pierre-Yves David
revert: extract actual revert in its own function...
r20571 def checkout(f):
fc = ctx[f]
FUJIWARA Katsunori
cmdutil: remove useless dirstate.normallookup() invocation in revert()...
r25755 repo.wwrite(f, fc.data(), fc.flags())
Pierre-Yves David
revert: extract actual revert in its own function...
r20571
Denis Laxalde
revert: prompt before removing files in interactive mode...
r30532 def doremove(f):
try:
Kyle Lippincott
unlinkpath: make empty directory removal optional (issue5901) (issue5826)...
r38512 rmdir = repo.ui.configbool('experimental', 'removeemptydirs')
repo.wvfs.unlinkpath(f, rmdir=rmdir)
Denis Laxalde
revert: prompt before removing files in interactive mode...
r30532 except OSError:
pass
repo.dirstate.remove(f)
Yuya Nishihara
pathauditor: disable cache of audited paths by default (issue5628)...
r33722 audit_path = pathutil.pathauditor(repo.root, cached=True)
Pierre-Yves David
revert: have an explicit action for "forget"...
r22489 for f in actions['forget'][0]:
liscju
revert: makes interactive mode ask to forget added files (issue4936)...
r27985 if interactive:
Denis Laxalde
style: avoid an unnecessary line split
r30530 choice = repo.ui.promptchoice(
Denis Laxalde
revert: indicate the default choice when prompting to forget files
r30531 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
liscju
revert: makes interactive mode ask to forget added files (issue4936)...
r27985 if choice == 0:
repo.dirstate.drop(f)
else:
Denis Laxalde
revert: use an exact matcher in interactive diff selection (issue5789)...
r36212 excluded_files.append(f)
liscju
revert: makes interactive mode ask to forget added files (issue4936)...
r27985 else:
repo.dirstate.drop(f)
Pierre-Yves David
revert: group action into a single dictionary...
r21576 for f in actions['remove'][0]:
Pierre-Yves David
revert: extract actual revert in its own function...
r20571 audit_path(f)
Denis Laxalde
revert: prompt before removing files in interactive mode...
r30532 if interactive:
choice = repo.ui.promptchoice(
_("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
if choice == 0:
doremove(f)
else:
Denis Laxalde
revert: use an exact matcher in interactive diff selection (issue5789)...
r36212 excluded_files.append(f)
Denis Laxalde
revert: prompt before removing files in interactive mode...
r30532 else:
doremove(f)
Pierre-Yves David
revert: add a `drop` action...
r22491 for f in actions['drop'][0]:
audit_path(f)
Pierre-Yves David
revert: extract actual revert in its own function...
r20571 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
Laurent Charignon
revert: add flag to make revert interactive
r24359
Laurent Charignon
revert: fix edition of newly added file during --interactive...
r25259 newlyaddedandmodifiedfiles = set()
Laurent Charignon
revert: add flag to make revert interactive
r24359 if interactive:
# Prompt the user for changes to revert
Denis Laxalde
revert: use an exact matcher in interactive diff selection (issue5789)...
r36212 torevert = [f for f in actions['revert'][0] if f not in excluded_files]
m = scmutil.matchfiles(repo, torevert)
Laurent Charignon
revert: make revert --interactive use git style diff...
r25258 diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
diffopts.nodates = True
diffopts.git = True
Denis Laxalde
revert: always display hunks reversed when reverting to parent...
r31196 operation = 'discard'
reversehunks = True
if node != parent:
Denis Laxalde
revert: do not reverse hunks in interactive when REV is not parent (issue5096)...
r34969 operation = 'apply'
reversehunks = False
Laurent Charignon
revert: add an experimental config to use inverted selection...
r25424 if reversehunks:
diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
else:
diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
Laurent Charignon
revert: add flag to make revert interactive
r24359 originalchunks = patch.parsepatch(diff)
Laurent Charignon
revert: add an experimental config to use inverted selection...
r25424
Laurent Charignon
revert: add flag to make revert interactive
r24359 try:
Laurent Charignon
revert: add an experimental config to use inverted selection...
r25424
Denis Laxalde
revert: use "discard"/"revert" verb when reverting interactively (issue5143)...
r29283 chunks, opts = recordfilter(repo.ui, originalchunks,
operation=operation)
Laurent Charignon
revert: add an experimental config to use inverted selection...
r25424 if reversehunks:
chunks = patch.reversehunks(chunks)
Yuya Nishihara
error: move patch.PatchError so it can easily implement __bytes__ (API)
r34252 except error.PatchError as err:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('error parsing patch: %s') % err)
Laurent Charignon
revert: add flag to make revert interactive
r24359
Laurent Charignon
revert: fix edition of newly added file during --interactive...
r25259 newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 if tobackup is None:
tobackup = set()
Laurent Charignon
revert: add flag to make revert interactive
r24359 # Apply changes
timeless
pycompat: switch to util.stringio for py3 compat
r28861 fp = stringio()
Laurent Charignon
revert: add flag to make revert interactive
r24359 for c in chunks:
skarlage
revert: don't backup if no files reverted in interactive mode (issue4793)...
r29498 # Create a backup file only if this hunk should be backed up
if ishunk(c) and c.header.filename() in tobackup:
abs = c.header.filename()
target = repo.wjoin(abs)
bakname = scmutil.origpath(repo.ui, repo, m.rel(abs))
util.copyfile(target, bakname)
tobackup.remove(abs)
Laurent Charignon
revert: add flag to make revert interactive
r24359 c.write(fp)
dopatch = fp.tell()
fp.seek(0)
if dopatch:
try:
patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
Yuya Nishihara
error: move patch.PatchError so it can easily implement __bytes__ (API)
r34252 except error.PatchError as err:
Pulkit Goyal
py3: use pycompat.bytestr instead of str...
r36736 raise error.Abort(pycompat.bytestr(err))
Laurent Charignon
revert: add flag to make revert interactive
r24359 del fp
else:
for f in actions['revert'][0]:
FUJIWARA Katsunori
cmdutil: remove useless dirstate.normallookup() invocation in revert()...
r25755 checkout(f)
Laurent Charignon
revert: add flag to make revert interactive
r24359 if normal:
normal(f)
Pierre-Yves David
revert: extract actual revert in its own function...
r20571
Pierre-Yves David
revert: group action into a single dictionary...
r21576 for f in actions['add'][0]:
Laurent Charignon
revert: fix edition of newly added file during --interactive...
r25259 # Don't checkout modified files, they are already created by the diff
if f not in newlyaddedandmodifiedfiles:
checkout(f)
repo.dirstate.add(f)
Pierre-Yves David
revert: extract actual revert in its own function...
r20571
normal = repo.dirstate.normallookup
if node == parent and p2 == nullid:
normal = repo.dirstate.normal
Pierre-Yves David
revert: group action into a single dictionary...
r21576 for f in actions['undelete'][0]:
Pierre-Yves David
revert: extract actual revert in its own function...
r20571 checkout(f)
normal(f)
copied = copies.pathcopies(repo[parent], ctx)
Pierre-Yves David
revert: group action into a single dictionary...
r21576 for f in actions['add'][0] + actions['undelete'][0] + actions['revert'][0]:
Pierre-Yves David
revert: extract actual revert in its own function...
r20571 if f in copied:
repo.dirstate.copy(copied[f], f)
FUJIWARA Katsunori
outgoing: introduce "outgoinghooks" to avoid redundant outgoing check...
r21051 # a list of (ui, repo, otherpeer, opts, missing) functions called by
# commands.outgoing. "missing" is "missing" of the result of
# "findcommonoutgoing()"
outgoinghooks = util.hooks()
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
FUJIWARA Katsunori
summary: introduce "summaryremotehooks" to avoid redundant incoming/outgoing check...
r21047 # a list of (ui, repo, opts, changes) functions called by commands.summary.
#
# functions should return tuple of booleans below, if 'changes' is None:
# (whether-incomings-are-needed, whether-outgoings-are-needed)
#
# otherwise, 'changes' is a tuple of tuples below:
# - (sourceurl, sourcebranch, sourcepeer, incoming)
# - (desturl, destbranch, destpeer, outgoing)
summaryremotehooks = 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'),
Pulkit Goyal
cmdutil: say that `graft --stop` stops the graft instead of aborting...
r38331 _("use 'hg graft --continue' or 'hg graft --stop' to stop")),
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 Harbison
rebase: prioritize indicating an interrupted rebase over update (issue5838)...
r38220 # Check for non-clearable states first, so things like rebase will take
# precedence over update.
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 for f, clearable, allowcommit, msg, hint in unfinishedstates:
Matt Harbison
rebase: prioritize indicating an interrupted rebase over update (issue5838)...
r38220 if clearable or (commit and allowcommit):
continue
if repo.vfs.exists(f):
raise error.Abort(msg, hint=hint)
for f, clearable, allowcommit, msg, hint in unfinishedstates:
if not clearable or (commit and allowcommit):
Matt Mackall
checkunfinished: accommodate histedit quirk...
r19496 continue
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474 if repo.vfs.exists(f):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(msg, hint=hint)
Matt Mackall
cmdutil: core functionality to block during multistep commands (issue3955)...
r19474
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):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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):
Pierre-Yves David
cmdutil: directly use repo.vfs.join...
r31320 util.unlink(repo.vfs.join(f))
FUJIWARA Katsunori
cmdutil: add class to restore dirstate during unexpected failure...
r24991
timeless
resolve: suggest the next action...
r27624 afterresolvedstates = [
timeless
graft: hook afterresolvedstates
r27625 ('graftstate',
_('hg graft --continue')),
timeless
resolve: suggest the next action...
r27624 ]
timeless
cmdutil: provide a way to report how to continue...
r28120 def howtocontinue(repo):
'''Check for an unfinished operation and return the command to finish
it.
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 afterresolvedstates tuples define a .hg/{file} and the corresponding
timeless
cmdutil: provide a way to report how to continue...
r28120 command needed to finish it.
Returns a (msg, warning) tuple. 'msg' is a string and 'warning' is
a boolean.
'''
contmsg = _("continue: %s")
timeless
resolve: suggest the next action...
r27624 for f, msg in afterresolvedstates:
if repo.vfs.exists(f):
timeless
cmdutil: provide a way to report how to continue...
r28120 return contmsg % msg, True
Matt Harbison
cmdutil: simplify the dirty check in howtocontinue()...
r33362 if repo[None].dirty(missing=True, merge=False, branch=False):
timeless
cmdutil: provide a way to report how to continue...
r28120 return contmsg % _("hg commit"), False
return None, None
def checkafterresolved(repo):
'''Inform the user about the next action after completing hg resolve
If there's a matching afterresolvedstates, howtocontinue will yield
repo.ui.warn as the reporter.
Otherwise, it will yield repo.ui.note.
'''
msg, warning = howtocontinue(repo)
if msg is not None:
if warning:
repo.ui.warn("%s\n" % msg)
else:
repo.ui.note("%s\n" % msg)
def wrongtooltocontinue(repo, task):
'''Raise an abort suggesting how to properly continue if there is an
active task.
Uses howtocontinue() to find the active task.
If there's no task (repo.ui.note for 'hg commit'), it does not offer
a hint.
'''
after = howtocontinue(repo)
hint = None
if after[1]:
hint = after[0]
raise error.Abort(_('no %s in progress') % task, hint=hint)