2014-07-23 20:47:35 +04:00
|
|
|
# tweakdefaults.py
|
|
|
|
#
|
|
|
|
# Copyright 2013 Facebook, Inc.
|
|
|
|
#
|
|
|
|
# This software may be used and distributed according to the terms of the
|
|
|
|
# GNU General Public License version 2 or any later version.
|
2015-03-08 22:22:25 +03:00
|
|
|
"""user friendly defaults
|
2014-10-29 09:06:11 +03:00
|
|
|
|
|
|
|
This extension changes defaults to be more user friendly.
|
|
|
|
|
2016-08-11 20:43:06 +03:00
|
|
|
hg bookmarks always use unfiltered repo (--hidden)
|
2015-08-13 00:53:26 +03:00
|
|
|
hg log always follows history (-f)
|
|
|
|
hg rebase aborts without arguments
|
|
|
|
hg update aborts without arguments
|
|
|
|
aborts if working copy is not clean
|
|
|
|
hg branch aborts and encourages use of bookmarks
|
|
|
|
hg grep greps the working directory instead of history
|
|
|
|
hg histgrep renamed from grep
|
|
|
|
|
2016-11-30 23:58:08 +03:00
|
|
|
Config::
|
|
|
|
|
|
|
|
[tweakdefaults]
|
|
|
|
# default destination used by pull --rebase / --update
|
|
|
|
defaultdest = ''
|
|
|
|
|
|
|
|
# whether to keep the commit date when doing amend / graft / rebase
|
|
|
|
amendkeepdate = False
|
|
|
|
graftkeepdate = False
|
|
|
|
rebasekeepdate = False
|
|
|
|
|
|
|
|
# whether to allow or disable some commands
|
|
|
|
allowbranch = True
|
|
|
|
allowfullrepohistgrep = False
|
|
|
|
allowmerge = True
|
|
|
|
allowrollback = True
|
|
|
|
allowtags = True
|
|
|
|
|
|
|
|
# change rebase exit from 1 to 0 if nothing is rebased
|
|
|
|
nooprebase = True
|
|
|
|
|
|
|
|
# educational messages
|
|
|
|
bmnodesthint = ''
|
|
|
|
bmnodestmsg = ''
|
|
|
|
branchmessage = ''
|
|
|
|
branchesmessage = ''
|
|
|
|
mergemessage = ''
|
|
|
|
nodesthint = ''
|
|
|
|
nodestmsg = ''
|
|
|
|
rollbackhint = ''
|
|
|
|
tagsmessage = ''
|
2014-10-29 09:06:11 +03:00
|
|
|
"""
|
2014-07-23 20:47:35 +04:00
|
|
|
|
|
|
|
from mercurial.i18n import _
|
2016-11-30 23:58:08 +03:00
|
|
|
from mercurial import (
|
|
|
|
bookmarks,
|
|
|
|
cmdutil,
|
|
|
|
commands,
|
|
|
|
error,
|
2017-01-03 16:59:55 +03:00
|
|
|
encoding,
|
2016-11-30 23:58:08 +03:00
|
|
|
extensions,
|
|
|
|
hg,
|
|
|
|
obsolete,
|
|
|
|
scmutil,
|
|
|
|
templater,
|
|
|
|
util,
|
|
|
|
)
|
|
|
|
|
2014-07-23 20:47:35 +04:00
|
|
|
from hgext import rebase
|
2017-01-03 16:59:55 +03:00
|
|
|
import inspect, re, shlex, stat, subprocess, time
|
2014-07-23 20:47:35 +04:00
|
|
|
|
2016-11-30 23:58:08 +03:00
|
|
|
wrapcommand = extensions.wrapcommand
|
|
|
|
wrapfunction = extensions.wrapfunction
|
|
|
|
|
2014-07-23 20:47:35 +04:00
|
|
|
cmdtable = {}
|
|
|
|
command = cmdutil.command(cmdtable)
|
2016-11-29 16:24:07 +03:00
|
|
|
testedwith = 'ships-with-fb-hgext'
|
2014-07-23 20:47:35 +04:00
|
|
|
|
2016-04-25 18:12:10 +03:00
|
|
|
globaldata = 'globaldata'
|
|
|
|
createmarkersoperation = 'createmarkersoperation'
|
|
|
|
|
2014-12-04 02:45:53 +03:00
|
|
|
logopts = [
|
2016-09-21 17:45:25 +03:00
|
|
|
('', 'all', None, _('shows all changesets in the repo')),
|
2014-12-04 02:45:53 +03:00
|
|
|
]
|
|
|
|
|
2015-07-02 21:06:59 +03:00
|
|
|
def uisetup(ui):
|
|
|
|
tweakorder()
|
2016-05-16 18:04:16 +03:00
|
|
|
# if we want to replace command's docstring (not just add stuff to it),
|
|
|
|
# we need to do it in uisetup, not extsetup
|
|
|
|
commands.table['^annotate|blame'][0].__doc__ = blame.__doc__
|
2015-07-02 21:06:59 +03:00
|
|
|
|
2014-09-25 22:34:07 +04:00
|
|
|
def extsetup(ui):
|
2014-12-04 02:45:53 +03:00
|
|
|
entry = wrapcommand(commands.table, 'update', update)
|
|
|
|
options = entry[1]
|
|
|
|
# try to put in alphabetical order
|
|
|
|
options.insert(3, ('n', 'nocheck', None,
|
|
|
|
_('update even with outstanding changes')))
|
|
|
|
|
2016-05-16 18:04:16 +03:00
|
|
|
wrapblame()
|
2016-04-01 17:41:29 +03:00
|
|
|
|
2015-10-20 09:55:23 +03:00
|
|
|
entry = wrapcommand(commands.table, 'commit', commitcmd)
|
|
|
|
options = entry[1]
|
|
|
|
options.insert(9, ('M', 'reuse-message', '',
|
|
|
|
_('reuse commit message from REV'), _('REV')))
|
2016-04-25 18:12:10 +03:00
|
|
|
opawarerebase = markermetadatawritingcommand(ui, _rebase, 'rebase')
|
|
|
|
wrapcommand(rebase.cmdtable, 'rebase', opawarerebase)
|
2015-11-14 05:10:52 +03:00
|
|
|
entry = wrapcommand(commands.table, 'pull', pull)
|
|
|
|
options = entry[1]
|
|
|
|
options.append(
|
|
|
|
('d', 'dest', '', _('destination for rebase or update')))
|
|
|
|
|
2016-06-12 01:25:13 +03:00
|
|
|
try:
|
|
|
|
rebaseext = extensions.find('rebase')
|
|
|
|
# tweakdefaults is already loaded before other extensions
|
|
|
|
# (see tweakorder() function) so if these functions are wrapped
|
|
|
|
# by something else, it's not a problem.
|
|
|
|
wrapfunction(rebaseext, '_computeobsoletenotrebased',
|
|
|
|
_computeobsoletenotrebasedwrapper)
|
|
|
|
wrapfunction(rebaseext, '_checkobsrebase',
|
|
|
|
_checkobsrebasewrapper)
|
|
|
|
except KeyError:
|
|
|
|
pass # no rebase, no problem
|
|
|
|
except AssertionError:
|
|
|
|
msg = _('tweakdefaults: _computeobsoletenotrebased or ' +
|
|
|
|
'_checkobsrebase are not what we expect them to be')
|
|
|
|
ui.warning(msg)
|
|
|
|
|
2015-11-14 05:10:52 +03:00
|
|
|
try:
|
|
|
|
remotenames = extensions.find('remotenames')
|
|
|
|
wrapfunction(remotenames, '_getrebasedest', _getrebasedest)
|
|
|
|
except KeyError:
|
2016-01-08 05:30:24 +03:00
|
|
|
pass # no remotenames, no worries
|
2015-11-14 05:10:52 +03:00
|
|
|
except AttributeError:
|
2016-01-08 05:30:24 +03:00
|
|
|
pass # old version of remotenames doh
|
2014-09-25 22:34:07 +04:00
|
|
|
|
|
|
|
entry = wrapcommand(commands.table, 'log', log)
|
|
|
|
for opt in logopts:
|
|
|
|
opt = (opt[0], opt[1], opt[2], opt[3])
|
|
|
|
entry[1].append(opt)
|
|
|
|
|
2015-07-02 21:11:56 +03:00
|
|
|
entry = wrapcommand(commands.table, 'branch', branchcmd)
|
|
|
|
options = entry[1]
|
|
|
|
options.append(('', 'new', None, _('allow branch creation')))
|
2015-09-24 23:09:47 +03:00
|
|
|
wrapcommand(commands.table, 'branches', branchescmd)
|
2015-07-02 21:11:56 +03:00
|
|
|
|
2015-10-07 02:39:18 +03:00
|
|
|
wrapcommand(commands.table, 'merge', mergecmd)
|
|
|
|
|
2015-09-18 20:20:49 +03:00
|
|
|
entry = wrapcommand(commands.table, 'status', statuscmd)
|
|
|
|
options = entry[1]
|
|
|
|
options.append(
|
|
|
|
('', 'root-relative', None, _('show status relative to root')))
|
|
|
|
|
2015-10-07 02:10:24 +03:00
|
|
|
wrapcommand(commands.table, 'rollback', rollbackcmd)
|
|
|
|
|
2015-09-24 21:29:41 +03:00
|
|
|
wrapcommand(commands.table, 'tag', tagcmd)
|
|
|
|
wrapcommand(commands.table, 'tags', tagscmd)
|
2015-10-22 00:26:15 +03:00
|
|
|
wrapcommand(commands.table, 'graft', graftcmd)
|
2015-10-23 01:50:59 +03:00
|
|
|
try:
|
2016-01-08 05:30:24 +03:00
|
|
|
fbamendmodule = extensions.find('fbamend')
|
2016-04-25 18:12:10 +03:00
|
|
|
opawareamend = markermetadatawritingcommand(ui, amendcmd, 'amend')
|
|
|
|
wrapcommand(fbamendmodule.cmdtable, 'amend', opawareamend)
|
2015-10-23 01:50:59 +03:00
|
|
|
except KeyError:
|
2016-01-08 05:30:24 +03:00
|
|
|
pass
|
2015-09-24 21:29:41 +03:00
|
|
|
|
2016-04-25 18:12:10 +03:00
|
|
|
# wrapped createmarkers knows how to write operation-aware
|
|
|
|
# metadata (e.g. 'amend', 'rebase' and so forth)
|
|
|
|
wrapfunction(obsolete, 'createmarkers', _createmarkers)
|
|
|
|
|
2016-08-11 20:43:06 +03:00
|
|
|
# wrap bookmarks after remotenames
|
|
|
|
def afterloaded(loaded):
|
|
|
|
if loaded:
|
|
|
|
# remotenames is loaded, wrap its wrapper directly
|
|
|
|
remotenames = extensions.find('remotenames')
|
|
|
|
wrapfunction(remotenames, 'exbookmarks', unfilteredcmd)
|
|
|
|
else:
|
|
|
|
# otherwise wrap the bookmarks command
|
|
|
|
wrapcommand(commands.table, 'bookmarks', unfilteredcmd)
|
|
|
|
extensions.afterloaded('remotenames', afterloaded)
|
2016-04-25 18:12:10 +03:00
|
|
|
|
2015-10-22 18:04:15 +03:00
|
|
|
# Tweak Behavior
|
2015-10-20 00:05:38 +03:00
|
|
|
tweakbehaviors(ui)
|
2017-04-11 03:38:22 +03:00
|
|
|
_fixpager(ui)
|
|
|
|
|
|
|
|
def reposetup(ui, repo):
|
|
|
|
_fixpager(ui)
|
2015-10-20 00:05:38 +03:00
|
|
|
|
2015-07-02 21:06:59 +03:00
|
|
|
def tweakorder():
|
|
|
|
"""
|
|
|
|
Tweakdefaults generally should load first; other extensions may modify
|
|
|
|
behavior such that tweakdefaults will be happy, so we should not prevent
|
|
|
|
that from happening too early in the process. Note that by loading first,
|
2016-04-04 22:48:01 +03:00
|
|
|
we ensure that tweakdefaults's function wrappers run *last*.
|
2015-07-02 21:06:59 +03:00
|
|
|
|
|
|
|
As of this writing, the extensions that we should load before are
|
|
|
|
remotenames and directaccess (NB: directaccess messes with order as well).
|
|
|
|
"""
|
2015-11-14 05:12:21 +03:00
|
|
|
order = extensions._order
|
2015-09-18 20:15:59 +03:00
|
|
|
order.remove('tweakdefaults')
|
|
|
|
order.insert(0, 'tweakdefaults')
|
2015-11-14 05:12:21 +03:00
|
|
|
extensions._order = order
|
|
|
|
|
2015-11-14 05:10:52 +03:00
|
|
|
# This is an ugly hack
|
|
|
|
# The remotenames extension removes the --rebase flag from pull so that the
|
|
|
|
# upstream rebase won't rebase to the wrong place. However, we want to allow
|
|
|
|
# the user to specify an explicit destination, but still abort if the user
|
|
|
|
# specifies dest without update or rebase. Conveniently, _getrebasedest is
|
|
|
|
# called before the --rebase flag is stripped from the opts. We will save it
|
|
|
|
# when _getrebasedest is called, then look it up in the pull command to do the
|
|
|
|
# right thing.
|
|
|
|
rebaseflag = False
|
|
|
|
rebasedest = None
|
|
|
|
|
|
|
|
def _getrebasedest(orig, repo, opts):
|
|
|
|
"""Use the manually specified destination over the tracking destination"""
|
|
|
|
global rebaseflag, rebasedest
|
|
|
|
rebaseflag = opts.get('rebase')
|
|
|
|
origdest = orig(repo, opts)
|
|
|
|
dest = opts.get('dest')
|
|
|
|
if not dest:
|
|
|
|
dest = origdest
|
|
|
|
rebasedest = dest
|
|
|
|
return dest
|
|
|
|
|
|
|
|
def pull(orig, ui, repo, *args, **opts):
|
|
|
|
"""pull --rebase/--update are problematic without an explicit destination"""
|
|
|
|
try:
|
|
|
|
rebasemodule = extensions.find('rebase')
|
|
|
|
except KeyError:
|
|
|
|
rebasemodule = None
|
|
|
|
|
|
|
|
rebase = opts.get('rebase')
|
|
|
|
update = opts.get('update')
|
|
|
|
isrebase = rebase or rebaseflag
|
2016-02-05 21:02:41 +03:00
|
|
|
# Only use from the global rebasedest if _getrebasedest was called. If the
|
|
|
|
# user isn't using remotenames, then rebasedest isn't set.
|
|
|
|
if rebaseflag:
|
2015-11-14 05:10:52 +03:00
|
|
|
dest = rebasedest
|
|
|
|
else:
|
|
|
|
dest = opts.get('dest')
|
|
|
|
|
2015-12-16 01:52:27 +03:00
|
|
|
if (isrebase or update) and not dest:
|
2015-11-26 05:23:07 +03:00
|
|
|
dest = ui.config('tweakdefaults', 'defaultdest')
|
|
|
|
|
2015-11-14 05:10:52 +03:00
|
|
|
if isrebase and update:
|
|
|
|
mess = _('specify either rebase or update, not both')
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(mess)
|
2015-11-14 05:10:52 +03:00
|
|
|
|
|
|
|
if dest and not (isrebase or update):
|
|
|
|
mess = _('only specify a destination if rebasing or updating')
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(mess)
|
2015-11-14 05:10:52 +03:00
|
|
|
|
|
|
|
if (isrebase or update) and not dest:
|
|
|
|
rebasemsg = _('you must use a bookmark with tracking '
|
|
|
|
'or manually specify a destination for the rebase')
|
|
|
|
if isrebase and bmactive(repo):
|
|
|
|
mess = ui.config('tweakdefaults', 'bmnodestmsg', rebasemsg)
|
|
|
|
hint = ui.config('tweakdefaults', 'bmnodesthint', _(
|
|
|
|
'set up tracking with `hg book -t <destination>` '
|
|
|
|
'or manually supply --dest / -d'))
|
|
|
|
elif isrebase:
|
|
|
|
mess = ui.config('tweakdefaults', 'nodestmsg', rebasemsg)
|
|
|
|
hint = ui.config('tweakdefaults', 'nodesthint', _(
|
|
|
|
'set up tracking with `hg book <name> -t <destination>` '
|
|
|
|
'or manually supply --dest / -d'))
|
|
|
|
else: # update
|
|
|
|
mess = _('you must specify a destination for the update')
|
|
|
|
hint = _('use `hg pull --update --dest <destination>`')
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(mess, hint=hint)
|
2015-11-14 05:10:52 +03:00
|
|
|
|
|
|
|
if 'rebase' in opts:
|
|
|
|
del opts['rebase']
|
|
|
|
if 'update' in opts:
|
|
|
|
del opts['update']
|
|
|
|
if 'dest' in opts:
|
|
|
|
del opts['dest']
|
|
|
|
|
|
|
|
ret = orig(ui, repo, *args, **opts)
|
|
|
|
|
|
|
|
# NB: we use rebase and not isrebase on the next line because
|
|
|
|
# remotenames may have already handled the rebase.
|
|
|
|
if dest and rebase:
|
|
|
|
ret = ret or rebasemodule.rebase(ui, repo, dest=dest)
|
|
|
|
if dest and update:
|
|
|
|
ret = ret or commands.update(ui, repo, node=dest, check=True)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
2015-10-20 00:05:38 +03:00
|
|
|
def tweakbehaviors(ui):
|
|
|
|
"""Tweak Behaviors
|
|
|
|
|
|
|
|
Right now this only tweaks the rebase behavior such that the default
|
|
|
|
exit status code for a noop rebase becomes 0 instead of 1.
|
|
|
|
|
|
|
|
In future we may add or modify other behaviours here.
|
|
|
|
"""
|
|
|
|
|
|
|
|
# noop rebase returns 0
|
|
|
|
def _nothingtorebase(orig, *args, **kwargs):
|
|
|
|
return 0
|
|
|
|
|
2015-10-22 18:04:15 +03:00
|
|
|
if ui.configbool("tweakdefaults", "nooprebase", True):
|
2015-10-20 00:05:38 +03:00
|
|
|
try:
|
|
|
|
rebase = extensions.find("rebase")
|
|
|
|
extensions.wrapfunction(
|
|
|
|
rebase, "_nothingtorebase", _nothingtorebase
|
|
|
|
)
|
2015-10-23 01:40:42 +03:00
|
|
|
except (KeyError, AttributeError):
|
2015-10-20 00:05:38 +03:00
|
|
|
pass
|
|
|
|
|
2015-10-20 09:55:23 +03:00
|
|
|
def commitcmd(orig, ui, repo, *pats, **opts):
|
2015-10-28 17:41:52 +03:00
|
|
|
if (opts.get("amend")
|
|
|
|
and not opts.get("date")
|
|
|
|
and not ui.configbool('tweakdefaults', 'amendkeepdate')):
|
2015-10-23 01:50:59 +03:00
|
|
|
opts["date"] = currentdate()
|
|
|
|
|
2015-10-20 09:55:23 +03:00
|
|
|
rev = opts.get('reuse_message')
|
2015-10-28 17:41:52 +03:00
|
|
|
if rev:
|
|
|
|
invalidargs = ['message', 'logfile']
|
|
|
|
currentinvalidargs = [ia for ia in invalidargs if opts.get(ia)]
|
|
|
|
if currentinvalidargs:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(_('--reuse-message and --%s are '
|
2015-10-28 17:41:52 +03:00
|
|
|
'mutually exclusive') % (currentinvalidargs[0]))
|
|
|
|
|
|
|
|
if rev:
|
2016-01-08 05:30:24 +03:00
|
|
|
opts['message'] = repo[rev].description()
|
2015-10-20 09:55:23 +03:00
|
|
|
|
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
|
2014-08-19 22:21:45 +04:00
|
|
|
def update(orig, ui, repo, node=None, rev=None, **kwargs):
|
2014-07-23 20:47:35 +04:00
|
|
|
# 'hg update' should do nothing
|
2015-03-02 21:54:07 +03:00
|
|
|
if not node and not rev and not kwargs['date']:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(
|
2015-08-15 01:18:15 +03:00
|
|
|
'You must specify a destination to update to,' +
|
|
|
|
' for example "hg update master".',
|
|
|
|
hint='If you\'re trying to move a bookmark forward, try ' +
|
|
|
|
'"hg rebase -d <destination>".')
|
|
|
|
|
2014-07-23 20:47:35 +04:00
|
|
|
|
2014-12-14 05:13:41 +03:00
|
|
|
# By default, never update when there are local changes unless updating to
|
|
|
|
# the current rev. This is useful for, eg, arc feature when the only
|
|
|
|
# thing changing is the bookmark.
|
2014-12-04 02:45:53 +03:00
|
|
|
if not kwargs['clean'] and not kwargs['nocheck']:
|
2014-12-14 05:13:41 +03:00
|
|
|
target = node or rev
|
|
|
|
if target and scmutil.revsingle(repo, target, target).rev() != \
|
|
|
|
repo.revs('.').first():
|
|
|
|
kwargs['check'] = True
|
2014-12-04 02:45:53 +03:00
|
|
|
|
|
|
|
if 'nocheck' in kwargs:
|
|
|
|
del kwargs['nocheck']
|
|
|
|
|
2014-09-03 19:46:45 +04:00
|
|
|
return orig(ui, repo, node=node, rev=rev, **kwargs)
|
2014-07-23 20:47:35 +04:00
|
|
|
|
2016-05-16 18:04:16 +03:00
|
|
|
def wrapblame():
|
|
|
|
entry = wrapcommand(commands.table, 'annotate', blame)
|
|
|
|
options = entry[1]
|
|
|
|
options.append(('p', 'phabdiff', None, _('list phabricator diff id')))
|
|
|
|
|
|
|
|
# revision number is no longer default
|
|
|
|
nind = next((i for i, o in enumerate(options) if o[0] == 'n'), -1)
|
|
|
|
if nind != -1:
|
|
|
|
options[nind] = ('n', 'number', None, _('list the revision number'))
|
|
|
|
# changeset is default now
|
|
|
|
cind = next((i for i, o in enumerate(options) if o[0] == 'c'), -1)
|
|
|
|
if cind != -1:
|
|
|
|
options[cind] = ('c', 'changeset', None,
|
|
|
|
_('list the changeset (default)'))
|
|
|
|
|
2016-04-01 17:41:29 +03:00
|
|
|
def blame(orig, ui, repo, *pats, **opts):
|
2016-05-16 18:04:16 +03:00
|
|
|
"""show changeset information by line for each file
|
|
|
|
|
|
|
|
List changes in files, showing the changeset responsible for
|
|
|
|
each line.
|
|
|
|
|
|
|
|
This command is useful for discovering when a change was made and
|
|
|
|
by whom.
|
|
|
|
|
|
|
|
If you include -n, changeset gets replaced by revision id, unless
|
|
|
|
you also include -c, in which case both are shown. -p on the other
|
|
|
|
hand always adds Phabricator Diff Id, not replacing anything with it.
|
|
|
|
|
|
|
|
Without the -a/--text option, annotate will avoid processing files
|
|
|
|
it detects as binary. With -a, annotate will annotate the file
|
|
|
|
anyway, although the results will probably be neither useful
|
|
|
|
nor desirable.
|
|
|
|
|
|
|
|
Returns 0 on success.
|
|
|
|
"""
|
2016-04-01 17:41:29 +03:00
|
|
|
def phabdiff(context, mapping, args):
|
|
|
|
"""Fetch the Phab Diff Id from the node in mapping"""
|
|
|
|
res = ' ' * 8
|
|
|
|
try:
|
2016-11-29 14:18:00 +03:00
|
|
|
d = repo[mapping['rev']].description()
|
2016-04-01 17:41:29 +03:00
|
|
|
pat = 'https://.*/(D\d+)'
|
|
|
|
m = re.search(pat, d)
|
|
|
|
res = m.group(1) if m else ''
|
|
|
|
except Exception:
|
|
|
|
pass
|
|
|
|
return res
|
|
|
|
|
|
|
|
if ui.plain():
|
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
|
2016-11-29 14:18:00 +03:00
|
|
|
# changeset is the new default
|
|
|
|
if all(not opts.get(f) for f in ['changeset', 'number', 'phabdiff', 'user',
|
|
|
|
'date', 'file']):
|
|
|
|
opts['changeset'] = True
|
|
|
|
|
2016-04-01 17:41:29 +03:00
|
|
|
# We want to register template `blame_phabdiffid` function
|
|
|
|
# just for this call so that we don't pollute the function
|
|
|
|
# namespaces for other commandss. The reason is mainly
|
2016-11-29 14:18:00 +03:00
|
|
|
# because `blame_phabdiffid` relies on 'rev' value being
|
2016-04-01 17:41:29 +03:00
|
|
|
# present in the `mapping` argument passed to it (which
|
|
|
|
# would not necessarily be the case for other non-log-like
|
|
|
|
# commands.
|
|
|
|
# tl/dr: this is a dirty hack and we want to have is as
|
|
|
|
# restricted as possible
|
|
|
|
templater.funcs['blame_phabdiffid'] = phabdiff
|
2016-11-29 14:18:00 +03:00
|
|
|
|
|
|
|
try:
|
|
|
|
# without --phabdiff or with -T, use the default formatter
|
|
|
|
if not opts.get('phabdiff') or opts.get('template'):
|
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
|
|
|
|
# to show the --phabdiff column, we want to modify "opmap" in
|
|
|
|
# commands.annotate - not doable directly so let's use templates to
|
|
|
|
# workaround.
|
|
|
|
ptmpl = ['']
|
|
|
|
|
|
|
|
def append(t, sep=' '):
|
|
|
|
if ptmpl[0]:
|
|
|
|
ptmpl[0] += sep
|
|
|
|
ptmpl[0] += t
|
|
|
|
|
|
|
|
if opts.get('user'):
|
|
|
|
append("{pad(user|emailuser, 13, ' ', True)}")
|
|
|
|
if opts.get('number'):
|
|
|
|
width = len(str(len(repo)))
|
|
|
|
append("{pad(rev, %d)}" % width)
|
2016-05-16 18:04:16 +03:00
|
|
|
if opts.get('changeset'):
|
2016-11-29 14:18:00 +03:00
|
|
|
append("{short(node)}")
|
|
|
|
if opts.get('phabdiff'):
|
|
|
|
opts['number'] = True # makes mapping['rev'] available in phabdiff
|
|
|
|
append("{pad(blame_phabdiffid(), 8)}")
|
|
|
|
if opts.get('date'):
|
2017-01-10 19:48:02 +03:00
|
|
|
if ui.quiet:
|
|
|
|
append("{pad(date|shortdate, 10)}")
|
|
|
|
else:
|
|
|
|
append("{pad(date|rfc822date, 12)}")
|
2016-11-29 14:18:00 +03:00
|
|
|
if opts.get('file'):
|
|
|
|
append("{file}")
|
|
|
|
if opts.get('line_number'):
|
|
|
|
append("{pad(line_number, 5, ' ', True)}", sep=':')
|
|
|
|
opts['template'] = ptmpl[0] + ': {line}'
|
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
finally:
|
|
|
|
del templater.funcs['blame_phabdiffid']
|
2016-04-01 17:41:29 +03:00
|
|
|
|
2014-09-25 02:11:10 +04:00
|
|
|
@command('histgrep', commands.table['grep'][1], commands.table['grep'][2])
|
|
|
|
def histgrep(ui, repo, pattern, *pats, **opts):
|
|
|
|
"""search for a pattern in specified files and revisions
|
|
|
|
|
|
|
|
Search revisions of files for a regular expression.
|
|
|
|
|
|
|
|
The command used to be hg grep.
|
|
|
|
|
|
|
|
This command behaves differently than Unix grep. It only accepts
|
|
|
|
Python/Perl regexps. It searches repository history, not the working
|
|
|
|
directory. It always prints the revision number in which a match appears.
|
|
|
|
|
|
|
|
By default, grep only prints output for the first revision of a file in
|
|
|
|
which it finds a match. To get it to print every revision that contains a
|
|
|
|
change in match status ("-" for a match that becomes a non-match, or "+"
|
|
|
|
for a non-match that becomes a match), use the --all flag.
|
|
|
|
|
|
|
|
Returns 0 if a match is found, 1 otherwise."""
|
2016-02-11 14:39:59 +03:00
|
|
|
if not pats and not ui.configbool("tweakdefaults", "allowfullrepohistgrep"):
|
2016-01-08 05:30:24 +03:00
|
|
|
m = _("can't run histgrep on the whole repo, please provide filenames")
|
|
|
|
h = _('this is disabled to avoid very slow greps over the whole repo')
|
|
|
|
raise error.Abort(m, hint=h)
|
2015-12-18 16:59:43 +03:00
|
|
|
|
2015-12-17 18:36:58 +03:00
|
|
|
return commands.grep(ui, repo, pattern, *pats, **opts)
|
2014-09-25 02:11:10 +04:00
|
|
|
|
|
|
|
del commands.table['grep']
|
2014-09-26 00:50:36 +04:00
|
|
|
@command('grep',
|
|
|
|
[('A', 'after-context', '', 'print NUM lines of trailing context', 'NUM'),
|
|
|
|
('B', 'before-context', '', 'print NUM lines of leading context', 'NUM'),
|
|
|
|
('C', 'context', '', 'print NUM lines of output context', 'NUM'),
|
|
|
|
('i', 'ignore-case', None, 'ignore case when matching'),
|
|
|
|
('l', 'files-with-matches', None, 'print only filenames that match'),
|
|
|
|
('n', 'line-number', None, 'print matching line numbers'),
|
|
|
|
('V', 'invert-match', None, 'select non-matching lines'),
|
|
|
|
('w', 'word-regexp', None, 'match whole words only'),
|
|
|
|
('E', 'extended-regexp', None, 'use POSIX extended regexps'),
|
|
|
|
('F', 'fixed-strings', None, 'interpret pattern as fixed string'),
|
|
|
|
('P', 'perl-regexp', None, 'use Perl-compatible regexps'),
|
|
|
|
], '[OPTION]... PATTERN [FILE]...',
|
|
|
|
inferrepo=True)
|
|
|
|
def grep(ui, repo, pattern, *pats, **opts):
|
|
|
|
"""search for a pattern in tracked files in the working directory
|
|
|
|
|
|
|
|
The default regexp style is POSIX basic regexps. If no FILE parameters are
|
|
|
|
passed in, the current directory and its subdirectories will be searched.
|
|
|
|
|
|
|
|
For the old 'hg grep', see 'histgrep'."""
|
2014-09-25 02:11:10 +04:00
|
|
|
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
grepcommandstr = ui.config('grep', 'command', default='grep')
|
|
|
|
# Use shlex.split() to split up grepcommandstr into multiple arguments.
|
|
|
|
# this allows users to specify a command plus arguments (e.g., "grep -i").
|
|
|
|
# We don't use a real shell to execute this, which ensures we won't do
|
|
|
|
# bad stuff if their command includes redirects, semicolons, or other
|
|
|
|
# special characters etc.
|
|
|
|
cmd = ['xargs', '-0'] + shlex.split(grepcommandstr) + [
|
|
|
|
'--no-messages',
|
|
|
|
'--binary-files=without-match',
|
|
|
|
'--with-filename',
|
|
|
|
'--regexp=' + pattern,
|
|
|
|
]
|
|
|
|
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('after_context'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-A')
|
|
|
|
cmd.append(opts.get('after_context'))
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('before_context'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-B')
|
|
|
|
cmd.append(opts.get('before_context'))
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('context'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-C')
|
|
|
|
cmd.append(opts.get('context'))
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('ignore_case'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-i')
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('files_with_matches'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-l')
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('line_number'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-n')
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('invert_match'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-v')
|
2014-09-25 02:11:10 +04:00
|
|
|
if opts.get('word_regexp'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-w')
|
2014-09-26 00:50:36 +04:00
|
|
|
if opts.get('extended_regexp'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-E')
|
2014-09-26 00:50:36 +04:00
|
|
|
if opts.get('fixed_strings'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-F')
|
2014-09-26 00:50:36 +04:00
|
|
|
if opts.get('perl_regexp'):
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('-P')
|
2014-09-26 00:50:36 +04:00
|
|
|
|
|
|
|
# color support, using the color extension
|
|
|
|
colormode = getattr(ui, '_colormode', '')
|
|
|
|
if colormode == 'ansi':
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
cmd.append('--color=always')
|
2014-09-26 00:50:36 +04:00
|
|
|
|
2014-10-01 03:37:32 +04:00
|
|
|
wctx = repo[None]
|
[tweakdefaults] fix handling of grep file pattern arguments
Summary:
Previously grep only searched in the current directory, even if you gave it a
pattern like "../". This fixes the code to correctly honor the arguments, and
to accept mercurial file patterns just like most other mercurial commands.
This does change the file parsing behavior somewhat: previously "hg grep" would
treat all arguments as glob patterns. Now you explicitly have to say
"glob:<pattern>" to get glob matching. However, I suspect this won't impact
most users, since they would normally let their shell perform glob expansion
before the arguments are given to mercurial.
Test Plan:
Included new unit tests for grep, and updated the existing tests that were
affected by the change in glob behavior.
Reviewers: #sourcecontrol, durham, carenthomas, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: quark, mwilliams, matthieu, meyering, yfeldblum, rmcelroy, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376605
Signature: t1:3376605:1464841648:98bfb47866dec802ca34f55c821796f36532211f
2016-06-22 06:44:06 +03:00
|
|
|
if not pats:
|
|
|
|
# Search everything in the current directory
|
|
|
|
m = scmutil.match(wctx, ['.'])
|
|
|
|
else:
|
|
|
|
# Search using the specified patterns
|
|
|
|
m = scmutil.match(wctx, pats)
|
[tweakdefaults] stop running xargs+grep through a shell
Summary:
Directly execute the xargs command, rather than using a shell. This is
slightly more efficient, but also ensures we won't have security problems or
other issues based on the user's grep.command config setting. Even if it
contains shell redirects, semicolons, or other special characters, we will no
longer pass them to a shell to interpret them.
We do use shlex.split() go process the grep.command setting, to allow the user
to specify a command plus arguments.
Test Plan: Included new unit tests.
Reviewers: #sourcecontrol, durham, ttung, rmcelroy
Reviewed By: rmcelroy
Subscribers: akushner, rmcelroy, sid0, net-systems-diffs@, yogeshwer, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3376617
Signature: t1:3376617:1464841542:f58fc0a05d62b649edc70bc261009875385186c9
2016-06-22 06:44:08 +03:00
|
|
|
|
|
|
|
# Add '--' to make sure grep recognizes all remaining arguments
|
|
|
|
# (passed in by xargs) as filenames.
|
|
|
|
cmd.append('--')
|
|
|
|
p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
|
|
|
|
stdin=subprocess.PIPE)
|
2014-10-01 03:37:32 +04:00
|
|
|
|
|
|
|
write = p.stdin.write
|
|
|
|
ds = repo.dirstate
|
|
|
|
getkind = stat.S_IFMT
|
|
|
|
lnkkind = stat.S_IFLNK
|
|
|
|
for f in wctx.matches(m):
|
|
|
|
# skip symlinks and removed files
|
|
|
|
t = ds._map[f]
|
|
|
|
if t[0] == 'r' or getkind(t[1]) == lnkkind:
|
|
|
|
continue
|
|
|
|
write(m.rel(f) + '\0')
|
|
|
|
|
|
|
|
p.stdin.close()
|
|
|
|
return p.wait()
|
2014-09-25 02:11:10 +04:00
|
|
|
|
2016-04-25 18:12:10 +03:00
|
|
|
def markermetadatawritingcommand(ui, origcmd, operationame):
|
|
|
|
"""Wrap origcmd in a context where globaldata config contains
|
|
|
|
the name of current operation so that any function up the call
|
|
|
|
stack can query for this value:
|
|
|
|
`repo.ui.config(globaldata, createmarkersoperation)`
|
|
|
|
|
|
|
|
In particular, we want `obsolete.createmarkers` to know whether
|
|
|
|
top-level scenario is amend, rebase or something else so that
|
|
|
|
it can write these values into marker metadata.
|
|
|
|
"""
|
|
|
|
origargs = inspect.getargspec(origcmd)
|
|
|
|
try:
|
|
|
|
repo_index = origargs.args.index('repo')
|
|
|
|
except ValueError:
|
|
|
|
ui.warn(_("cannot wrap a command that does not have repo argument"))
|
|
|
|
return origcmd
|
|
|
|
|
|
|
|
def cmd(*args, **kwargs):
|
|
|
|
repo = args[repo_index]
|
2017-03-18 05:42:50 +03:00
|
|
|
overrides = {(globaldata, createmarkersoperation): operationame}
|
|
|
|
with repo.ui.configoverride(overrides, 'tweakdefaults'):
|
2016-04-25 18:12:10 +03:00
|
|
|
return origcmd(*args, **kwargs)
|
|
|
|
return cmd
|
|
|
|
|
2014-07-23 20:47:35 +04:00
|
|
|
def _rebase(orig, ui, repo, **opts):
|
2016-01-08 05:30:24 +03:00
|
|
|
if not opts.get('date') and not ui.configbool('tweakdefaults',
|
|
|
|
'rebasekeepdate'):
|
2015-11-12 12:36:21 +03:00
|
|
|
opts['date'] = currentdate()
|
|
|
|
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
if opts.get('continue') or opts.get('abort') or opts.get('restack'):
|
2014-08-19 01:27:37 +04:00
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
2014-07-23 20:47:35 +04:00
|
|
|
# 'hg rebase' w/o args should do nothing
|
|
|
|
if not opts.get('dest'):
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort("you must specify a destination (-d) for the rebase")
|
2014-07-23 20:47:35 +04:00
|
|
|
|
2014-09-19 04:22:14 +04:00
|
|
|
# 'hg rebase' can fast-forward bookmark
|
|
|
|
prev = repo['.']
|
|
|
|
dest = scmutil.revsingle(repo, opts.get('dest'))
|
2014-07-23 20:47:35 +04:00
|
|
|
|
2014-09-19 04:22:14 +04:00
|
|
|
# Only fast-forward the bookmark if no source nodes were explicitly
|
|
|
|
# specified.
|
|
|
|
if not (opts.get('base') or opts.get('source') or opts.get('rev')):
|
|
|
|
common = dest.ancestor(prev)
|
2014-07-23 20:47:35 +04:00
|
|
|
if prev == common:
|
2014-09-19 04:22:14 +04:00
|
|
|
result = hg.update(repo, dest.node())
|
2015-05-10 06:22:31 +03:00
|
|
|
if bmactive(repo):
|
2014-09-19 04:22:14 +04:00
|
|
|
bookmarks.update(repo, [prev.node()], dest.node())
|
2014-07-23 20:47:35 +04:00
|
|
|
return result
|
|
|
|
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
2016-06-12 01:25:13 +03:00
|
|
|
def _computeobsoletenotrebasedwrapper(orig, repo, rebaseobsrevs, dest):
|
|
|
|
"""Wrapper for _computeobsoletenotrebased from rebase extensions
|
|
|
|
|
|
|
|
Unlike upstream rebase, we don't want to skip purely pruned commits.
|
|
|
|
We also want to explain why some particular commit was skipped."""
|
|
|
|
res = orig(repo, rebaseobsrevs, dest)
|
|
|
|
for key in res.keys():
|
|
|
|
if res[key] is None:
|
|
|
|
# key => None is a sign of a pruned commit
|
|
|
|
del res[key]
|
|
|
|
return res
|
|
|
|
|
|
|
|
def _checkobsrebasewrapper(orig, repo, ui, *args):
|
2017-03-18 05:42:50 +03:00
|
|
|
overrides = {}
|
2016-06-12 01:25:13 +03:00
|
|
|
try:
|
|
|
|
extensions.find('inhibit')
|
2017-03-18 05:42:50 +03:00
|
|
|
# if inhibit is enabled, allow divergence
|
|
|
|
overrides[('experimental', 'allowdivergence')] = True
|
2016-06-12 01:25:13 +03:00
|
|
|
except KeyError:
|
|
|
|
pass
|
2017-03-18 05:42:50 +03:00
|
|
|
with repo.ui.configoverride(overrides, 'tweakdefaults'):
|
2016-06-12 01:25:13 +03:00
|
|
|
orig(repo, ui, *args)
|
|
|
|
|
2015-10-23 01:50:59 +03:00
|
|
|
def currentdate():
|
|
|
|
return "%d %d" % util.makedate(time.time())
|
|
|
|
|
2015-10-22 00:26:15 +03:00
|
|
|
def graftcmd(orig, ui, repo, *revs, **opts):
|
2016-01-08 05:30:24 +03:00
|
|
|
if not opts.get("date") and not ui.configbool('tweakdefaults',
|
|
|
|
'graftkeepdate'):
|
2015-10-23 01:50:59 +03:00
|
|
|
opts["date"] = currentdate()
|
2015-10-22 00:26:15 +03:00
|
|
|
return orig(ui, repo, *revs, **opts)
|
|
|
|
|
2015-10-23 01:50:59 +03:00
|
|
|
def amendcmd(orig, ui, repo, *pats, **opts):
|
2016-01-08 05:30:24 +03:00
|
|
|
if not opts.get("date") and not ui.configbool('tweakdefaults',
|
|
|
|
'amendkeepdate'):
|
2015-10-23 01:50:59 +03:00
|
|
|
opts["date"] = currentdate()
|
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
|
2014-07-23 20:47:35 +04:00
|
|
|
def log(orig, ui, repo, *pats, **opts):
|
|
|
|
# 'hg log' defaults to -f
|
|
|
|
# All special uses of log (--date, --branch, etc) will also now do follow.
|
|
|
|
if not opts.get('rev') and not opts.get('all'):
|
|
|
|
opts['follow'] = True
|
|
|
|
|
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
|
2015-07-02 21:11:56 +03:00
|
|
|
def branchcmd(orig, ui, repo, label=None, **opts):
|
2015-09-24 23:09:47 +03:00
|
|
|
message = ui.config('tweakdefaults', 'branchmessage',
|
|
|
|
_('new named branches are disabled in this repository'))
|
|
|
|
enabled = ui.configbool('tweakdefaults', 'allowbranch', True)
|
|
|
|
if (enabled and opts.get('new')) or label is None:
|
2015-07-02 21:11:56 +03:00
|
|
|
if 'new' in opts:
|
|
|
|
del opts['new']
|
|
|
|
return orig(ui, repo, label, **opts)
|
2015-09-24 23:09:47 +03:00
|
|
|
elif enabled:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(
|
2015-07-02 21:11:56 +03:00
|
|
|
_('do not use branches; use bookmarks instead'),
|
|
|
|
hint=_('use --new if you are certain you want a branch'))
|
2015-09-24 23:09:47 +03:00
|
|
|
else:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(message)
|
2015-09-24 23:09:47 +03:00
|
|
|
|
|
|
|
def branchescmd(orig, ui, repo, active, closed, **opts):
|
|
|
|
message = ui.config('tweakdefaults', 'branchesmessage')
|
|
|
|
if message:
|
|
|
|
ui.warn(message + '\n')
|
|
|
|
return orig(ui, repo, active, closed, **opts)
|
2015-07-02 21:11:56 +03:00
|
|
|
|
2015-10-07 02:39:18 +03:00
|
|
|
def mergecmd(orig, ui, repo, node=None, **opts):
|
|
|
|
"""
|
|
|
|
Allowing to disable merges
|
|
|
|
"""
|
|
|
|
if ui.configbool('tweakdefaults','allowmerge', True):
|
|
|
|
return orig(ui, repo, node, **opts)
|
|
|
|
else:
|
2015-10-08 21:32:39 +03:00
|
|
|
message = ui.config('tweakdefaults', 'mergemessage',
|
|
|
|
_('merging is not supported for this repository'))
|
|
|
|
hint = ui.config('tweakdefaults', 'mergehint', _('use rebase instead'))
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(message, hint=hint)
|
2015-10-07 02:39:18 +03:00
|
|
|
|
2015-09-18 20:20:49 +03:00
|
|
|
def statuscmd(orig, ui, repo, *pats, **opts):
|
|
|
|
"""
|
|
|
|
Make status relative by default for interactive usage
|
|
|
|
"""
|
|
|
|
if opts.get('root_relative'):
|
|
|
|
del opts['root_relative']
|
tweakdefaults: abort when combining --root-relative with patterns
Summary:
When people combine --root-relative with a file pattern, they would probably
expect the output to be relative to the root -- but it's not! In this case, it
would fall back to the default file pattern behavior, which is cwd-relative.
Instead of confusing the user with apprarently errorneous output, let's abort
explicitly and provide a helptful hint.
Test Plan: added a new test, existing tests still pass
Reviewers: #mercurial, simpkins, ttung, quark
Reviewed By: quark
Subscribers: quark, net-systems-diffs@, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3319366
Signature: t1:3319366:1463610688:3f129c97f68f43ac85d2b31b55fac5c859e85c04
2016-05-19 19:35:59 +03:00
|
|
|
if pats:
|
|
|
|
# Ugh. So, if people pass a pattern and --root-relative,
|
|
|
|
# they will get pattern behavior and not any root-relative paths,
|
|
|
|
# because that's how hg status works. It's non-trivial to fixup
|
|
|
|
# either all the patterns or all the output, so we just raise
|
|
|
|
# an exception instead.
|
|
|
|
message = _('--root-relative not supported with patterns')
|
|
|
|
hint = _('run from the repo root instead')
|
|
|
|
raise error.Abort(message, hint=hint)
|
2017-01-03 16:59:55 +03:00
|
|
|
elif encoding.environ.get('HGPLAIN'): # don't break automation
|
2015-09-18 20:20:49 +03:00
|
|
|
pass
|
2015-09-25 05:05:26 +03:00
|
|
|
# Here's an ugly hack! If users are passing "re:" to make status relative,
|
|
|
|
# hgwatchman will never refresh the full state and status will become and
|
|
|
|
# remain slow after a restart or 24 hours. Here, we check for this and
|
|
|
|
# replace 're:' with '' which has the same semantic effect but works for
|
|
|
|
# hgwatchman (because match.always() == True), if and only if 're:' is the
|
|
|
|
# only pattern passed.
|
|
|
|
#
|
|
|
|
# Also set pats to [''] if pats is empty because that makes status relative.
|
|
|
|
elif not pats or (len(pats) == 1 and pats[0] == 're:'):
|
|
|
|
pats = ['']
|
2015-09-18 20:20:49 +03:00
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
|
2015-10-07 02:10:24 +03:00
|
|
|
def rollbackcmd(orig, ui, repo, **opts):
|
|
|
|
"""
|
|
|
|
Allowing to disable the rollback command
|
|
|
|
"""
|
|
|
|
if ui.configbool('tweakdefaults', 'allowrollback', True):
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
else:
|
|
|
|
message = ui.config('tweakdefaults', 'rollbackmessage',
|
|
|
|
_('the use of rollback is disabled'))
|
|
|
|
hint = ui.config('tweakdefaults', 'rollbackhint', None)
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(message, hint=hint)
|
2015-10-07 02:10:24 +03:00
|
|
|
|
2015-09-24 21:29:41 +03:00
|
|
|
def tagcmd(orig, ui, repo, name1, *names, **opts):
|
|
|
|
"""
|
2015-10-20 00:05:38 +03:00
|
|
|
Allowing to disable tags
|
2015-09-24 21:29:41 +03:00
|
|
|
"""
|
|
|
|
message = ui.config('tweakdefaults', 'tagmessage',
|
2015-09-29 00:39:56 +03:00
|
|
|
_('new tags are disabled in this repository'))
|
|
|
|
if ui.configbool('tweakdefaults', 'allowtags', True):
|
2015-09-24 21:29:41 +03:00
|
|
|
return orig(ui, repo, name1, *names, **opts)
|
|
|
|
else:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(message)
|
2015-09-24 21:29:41 +03:00
|
|
|
|
|
|
|
def tagscmd(orig, ui, repo, **opts):
|
|
|
|
message = ui.config('tweakdefaults', 'tagsmessage', '')
|
|
|
|
if message:
|
|
|
|
ui.warn(message + '\n')
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
2016-08-11 20:43:06 +03:00
|
|
|
def unfilteredcmd(orig, *args, **opts):
|
|
|
|
# use unfiltered repo for performance
|
|
|
|
#
|
|
|
|
# find the "repo" arg and change it to the unfiltered version.
|
|
|
|
# "repo" could in different location, for example:
|
|
|
|
# args = [ui, repo, ...] for commands.bookmark
|
|
|
|
# args = [orig, ui, repo, ...] for remotenames.exbookmarks
|
|
|
|
for i in [1, 2]:
|
|
|
|
if len(args) > i and util.safehasattr(args[i], 'unfiltered'):
|
|
|
|
args = list(args)
|
|
|
|
args[i] = args[i].unfiltered()
|
|
|
|
args = tuple(args)
|
|
|
|
return orig(*args, **opts)
|
2015-09-24 21:29:41 +03:00
|
|
|
|
2015-05-10 06:22:31 +03:00
|
|
|
### bookmarks api compatibility layer ###
|
|
|
|
def bmactive(repo):
|
|
|
|
try:
|
|
|
|
return repo._activebookmark
|
|
|
|
except AttributeError:
|
|
|
|
return repo._bookmarkcurrent
|
2016-04-25 18:12:10 +03:00
|
|
|
|
|
|
|
def _createmarkers(orig, repo, relations, flag=0, date=None, metadata=None):
|
|
|
|
operation = repo.ui.config(globaldata, createmarkersoperation, None)
|
|
|
|
if operation is None:
|
|
|
|
return orig(repo, relations, flag, date, metadata)
|
|
|
|
|
|
|
|
if metadata is None:
|
|
|
|
metadata = {}
|
|
|
|
metadata['operation'] = operation
|
|
|
|
return orig(repo, relations, flag, date, metadata)
|
2017-04-11 03:38:22 +03:00
|
|
|
|
|
|
|
def _fixpager(ui):
|
|
|
|
# users may mistakenly set PAGER=less, which will affect "pager.pager".
|
|
|
|
# raw "less" does not support colors and is not friendly, add "-FRQX"
|
|
|
|
# automatically.
|
|
|
|
if ui.config('pager', 'pager', '').strip() == 'less':
|
|
|
|
ui.setconfig('pager', 'pager', 'less -FRQX')
|