util._matcher: speed up regexp matching.
In 4babaa52badf, Benoit made a change that substantially slows matching
when a big .hgignore file is in play, because it calls into the regexp
matching engine potentially hundreds of times per file to be matched.
I've partly rolled back his change, so that we only call into the matcher
once per file, but preserved the ability to report a meaningful error
message if there's a syntax error in the regexp.
#!/bin/sh
cp "$TESTDIR"/printenv.py .
# commit hooks can see env vars
hg init a
cd a
echo "[hooks]" > .hg/hgrc
echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
echo a > a
hg add a
hg commit -m a -d "1000000 0"
hg clone . ../b
cd ../b
# changegroup hooks can see env vars
echo '[hooks]' > .hg/hgrc
echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
# pretxncommit and commit hooks can see both parents of merge
cd ../a
echo b >> a
hg commit -m a1 -d "1 0"
hg update -C 0
echo b > b
hg add b
hg commit -m b -d '1 0'
hg merge 1
hg commit -m merge -d '2 0'
cd ../b
hg pull ../a
# tag hooks can see env vars
cd ../a
echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
hg tag -d '3 0' a
hg tag -l la
# pretag hook can forbid tagging
echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
hg tag -d '4 0' fa
hg tag -l fla
# pretxncommit hook can see changeset, can roll back txn, changeset
# no more there after
echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
echo z > z
hg add z
hg -q tip
hg commit -m 'fail' -d '4 0'
hg -q tip
# precommit hook can prevent commit
echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
hg commit -m 'fail' -d '4 0'
hg -q tip
# preupdate hook can prevent update
echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
hg update 1
# update hook
echo 'update = python ../printenv.py update' >> .hg/hgrc
hg update
# prechangegroup hook can prevent incoming changes
cd ../b
hg -q tip
echo '[hooks]' > .hg/hgrc
echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
hg pull ../a
# pretxnchangegroup hook can see incoming changes, can roll back txn,
# incoming changes no longer there after
echo '[hooks]' > .hg/hgrc
echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
hg pull ../a
hg -q tip
# outgoing hooks can see env vars
rm .hg/hgrc
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
hg pull ../a
hg rollback
# preoutgoing hook can prevent outgoing changes
echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
hg pull ../a
cat > hooktests.py <<EOF
from mercurial import util
uncallable = 0
def printargs(args):
args.pop('ui', None)
args.pop('repo', None)
a = list(args.items())
a.sort()
print 'hook args:'
for k, v in a:
print ' ', k, v
def passhook(**args):
printargs(args)
def failhook(**args):
printargs(args)
return True
class LocalException(Exception):
pass
def raisehook(**args):
raise LocalException('exception from hook')
def aborthook(**args):
raise util.Abort('raise abort from hook')
def brokenhook(**args):
return 1 + {}
class container:
unreachable = 1
EOF
echo '# test python hooks'
PYTHONPATH="`pwd`:$PYTHONPATH"
export PYTHONPATH
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
hg pull ../a 2>&1 | grep 'raised an exception'
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
hg pull ../a 2>&1 | grep 'raised an exception'
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
hg pull ../a
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
hg pull ../a
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
hg pull ../a
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
hg pull ../a
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
hg pull ../a
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
hg pull ../a
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
hg pull ../a
echo '[hooks]' > ../a/.hg/hgrc
echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
hg pull ../a
echo '# make sure --traceback works'
echo '[hooks]' > .hg/hgrc
echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
echo a >> a
hg --traceback commit -A -m a 2>&1 | grep '^Traceback'
cd ..
hg init c
cd c
cat > hookext.py <<EOF
def autohook(**args):
print "Automatically installed hook"
def reposetup(ui, repo):
repo.ui.setconfig("hooks", "commit.auto", autohook)
EOF
echo '[extensions]' >> .hg/hgrc
echo 'hookext = hookext.py' >> .hg/hgrc
touch foo
hg add foo
hg ci -m 'add foo'
echo >> foo
hg ci --debug -m 'change foo' | sed -e 's/ at .*>/>/'
hg showconfig hooks | sed -e 's/ at .*>/>/'
exit 0