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.
|
|
|
|
|
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
|
|
|
|
|
2014-10-29 09:06:11 +03:00
|
|
|
"""
|
2014-07-23 20:47:35 +04:00
|
|
|
|
2014-09-19 04:22:14 +04:00
|
|
|
from mercurial import util, cmdutil, commands, hg, scmutil
|
2014-07-23 20:47:35 +04:00
|
|
|
from mercurial import bookmarks
|
2015-07-02 21:06:59 +03:00
|
|
|
from mercurial.extensions import wrapcommand, _order
|
2015-09-18 20:15:59 +03:00
|
|
|
import mercurial.extensions
|
2014-07-23 20:47:35 +04:00
|
|
|
from mercurial.i18n import _
|
|
|
|
from hgext import rebase
|
2014-10-01 03:37:32 +04:00
|
|
|
import errno, os, stat, subprocess
|
2014-07-23 20:47:35 +04:00
|
|
|
|
|
|
|
cmdtable = {}
|
|
|
|
command = cmdutil.command(cmdtable)
|
|
|
|
testedwith = 'internal'
|
|
|
|
|
2014-12-04 02:45:53 +03:00
|
|
|
logopts = [
|
|
|
|
('', 'all', None, _('shows all commits in the repo')),
|
|
|
|
]
|
|
|
|
|
2015-07-02 21:06:59 +03:00
|
|
|
def uisetup(ui):
|
|
|
|
tweakorder()
|
|
|
|
|
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')))
|
|
|
|
|
2014-09-25 22:34:07 +04:00
|
|
|
wrapcommand(rebase.cmdtable, 'rebase', _rebase)
|
|
|
|
|
|
|
|
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-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-09-24 21:29:41 +03:00
|
|
|
wrapcommand(commands.table, 'tag', tagcmd)
|
|
|
|
wrapcommand(commands.table, 'tags', tagscmd)
|
|
|
|
|
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,
|
|
|
|
we ensure that tweakdefault's function wrappers run *last*.
|
|
|
|
|
|
|
|
As of this writing, the extensions that we should load before are
|
|
|
|
remotenames and directaccess (NB: directaccess messes with order as well).
|
|
|
|
"""
|
2015-09-18 20:15:59 +03:00
|
|
|
order = mercurial.extensions._order
|
|
|
|
order.remove('tweakdefaults')
|
|
|
|
order.insert(0, 'tweakdefaults')
|
|
|
|
mercurial.extensions._order = order
|
2015-07-02 21:06:59 +03:00
|
|
|
|
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']:
|
2014-09-08 23:43:38 +04:00
|
|
|
raise util.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
|
|
|
|
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."""
|
|
|
|
return commands.grep(ui, repo, pattern, **opts)
|
|
|
|
|
|
|
|
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
|
|
|
|
2014-11-01 05:13:32 +03:00
|
|
|
grepcommand = ui.config('grep', 'command', default='grep')
|
2014-09-25 02:11:10 +04:00
|
|
|
optstr = ''
|
|
|
|
if opts.get('after_context'):
|
|
|
|
optstr += '-A' + opts.get('after_context') + ' '
|
|
|
|
if opts.get('before_context'):
|
|
|
|
optstr += '-B' + opts.get('before_context') + ' '
|
|
|
|
if opts.get('context'):
|
|
|
|
optstr += '-C' + opts.get('context') + ' '
|
|
|
|
if opts.get('ignore_case'):
|
|
|
|
optstr += '-i '
|
|
|
|
if opts.get('files_with_matches'):
|
|
|
|
optstr += '-l '
|
|
|
|
if opts.get('line_number'):
|
|
|
|
optstr += '-n '
|
|
|
|
if opts.get('invert_match'):
|
|
|
|
optstr += '-v '
|
|
|
|
if opts.get('word_regexp'):
|
|
|
|
optstr += '-w '
|
2014-09-26 00:50:36 +04:00
|
|
|
if opts.get('extended_regexp'):
|
|
|
|
optstr += '-E '
|
|
|
|
if opts.get('fixed_strings'):
|
|
|
|
optstr += '-F '
|
|
|
|
if opts.get('perl_regexp'):
|
|
|
|
optstr += '-P '
|
|
|
|
|
|
|
|
# color support, using the color extension
|
|
|
|
colormode = getattr(ui, '_colormode', '')
|
|
|
|
if colormode == 'ansi':
|
|
|
|
optstr += '--color=always '
|
|
|
|
|
2014-10-01 03:37:32 +04:00
|
|
|
wctx = repo[None]
|
|
|
|
m = scmutil.match(wctx, ['.'], {'include': pats})
|
|
|
|
p = subprocess.Popen(
|
2014-11-01 05:13:32 +03:00
|
|
|
'xargs -0 %s --no-messages --binary-files=without-match '
|
2014-10-01 03:37:32 +04:00
|
|
|
'--with-filename --regexp=%s %s --' %
|
2014-11-01 05:13:32 +03:00
|
|
|
(grepcommand, util.shellquote(pattern), optstr),
|
2014-10-01 03:37:32 +04:00
|
|
|
shell=True, bufsize=-1, close_fds=util.closefds,
|
|
|
|
stdin=subprocess.PIPE)
|
|
|
|
|
|
|
|
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
|
|
|
|
2014-07-23 20:47:35 +04:00
|
|
|
def _rebase(orig, ui, repo, **opts):
|
2014-08-19 01:27:37 +04:00
|
|
|
if opts.get('continue') or opts.get('abort'):
|
|
|
|
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'):
|
|
|
|
raise util.Abort("you must specify a destination (-d) for the rebase")
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
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):
|
|
|
|
if label is None or opts.get('new'):
|
|
|
|
if 'new' in opts:
|
|
|
|
del opts['new']
|
|
|
|
return orig(ui, repo, label, **opts)
|
|
|
|
raise util.Abort(
|
|
|
|
_('do not use branches; use bookmarks instead'),
|
|
|
|
hint=_('use --new if you are certain you want a branch'))
|
|
|
|
|
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']
|
|
|
|
elif os.environ.get('HGPLAIN'): # don't break automation
|
|
|
|
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-09-24 21:29:41 +03:00
|
|
|
def tagcmd(orig, ui, repo, name1, *names, **opts):
|
|
|
|
"""
|
2015-09-29 00:39:56 +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:
|
|
|
|
raise util.Abort(message)
|
|
|
|
|
|
|
|
def tagscmd(orig, ui, repo, **opts):
|
|
|
|
message = ui.config('tweakdefaults', 'tagsmessage', '')
|
|
|
|
if message:
|
|
|
|
ui.warn(message + '\n')
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
|
|
|
|
2015-05-10 06:22:31 +03:00
|
|
|
### bookmarks api compatibility layer ###
|
|
|
|
def bmactive(repo):
|
|
|
|
try:
|
|
|
|
return repo._activebookmark
|
|
|
|
except AttributeError:
|
|
|
|
return repo._bookmarkcurrent
|