hook: centralize passing HG_PENDING to external hook process
This patch centralizes passing HG_PENDING to external hook process
into '_exthook()'. To make in-memory changes visible to external hook
process, this patch does:
- write (or schedule to write) in-memory dirstate changes, and
- set HG_PENDING environment variable, if:
- a transaction is running, and
- there are in-memory changes to be visible
This patch tests some commands with some hooks, because transaction
activity of a same hook differs from each other ("---": "not tested").
======== ========= ========= ============
command preupdate precommit pretxncommit
======== ========= ========= ============
unshelve o --- ---
backout x --- ---
import --- o o
qrefresh --- x o
======== ========= ========= ============
Each hooks are examined separately to prevent in-memory changes from
being visible to external process accidentally by side effect of hooks
previously invoked.
--- a/mercurial/changegroup.py Sat Oct 17 01:15:34 2015 +0900
+++ b/mercurial/changegroup.py Sat Oct 17 01:15:34 2015 +0900
@@ -407,15 +407,13 @@
repo.invalidatevolatilesets()
if changesets > 0:
- p = lambda: tr.writepending() and repo.root or ""
if 'node' not in tr.hookargs:
tr.hookargs['node'] = hex(cl.node(clstart))
hookargs = dict(tr.hookargs)
else:
hookargs = dict(tr.hookargs)
hookargs['node'] = hex(cl.node(clstart))
- repo.hook('pretxnchangegroup', throw=True, pending=p,
- **hookargs)
+ repo.hook('pretxnchangegroup', throw=True, **hookargs)
added = [cl.node(r) for r in xrange(clstart, clend)]
publishing = repo.publishing()
--- a/mercurial/hook.py Sat Oct 17 01:15:34 2015 +0900
+++ b/mercurial/hook.py Sat Oct 17 01:15:34 2015 +0900
@@ -118,6 +118,13 @@
starttime = time.time()
env = {}
+
+ # make in-memory changes visible to external process
+ tr = repo.currenttransaction()
+ repo.dirstate.write(tr)
+ if tr and tr.writepending():
+ env['HG_PENDING'] = repo.root
+
for k, v in args.iteritems():
if callable(v):
v = v()
--- a/mercurial/localrepo.py Sat Oct 17 01:15:34 2015 +0900
+++ b/mercurial/localrepo.py Sat Oct 17 01:15:34 2015 +0900
@@ -994,8 +994,7 @@
reporef = weakref.ref(self)
def validate(tr):
"""will run pre-closing hooks"""
- pending = lambda: tr.writepending() and self.root or ""
- reporef().hook('pretxnclose', throw=True, pending=pending,
+ reporef().hook('pretxnclose', throw=True,
txnname=desc, **tr.hookargs)
def releasefn(tr, success):
repo = reporef()
@@ -1682,10 +1681,9 @@
n = self.changelog.add(mn, files, ctx.description(),
trp, p1.node(), p2.node(),
user, ctx.date(), ctx.extra().copy())
- p = lambda: tr.writepending() and self.root or ""
xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
- parent2=xp2, pending=p)
+ parent2=xp2)
# set the new commit is proper phase
targetphase = subrepo.newcommitphase(self.ui, ctx)
if targetphase:
@@ -1865,8 +1863,6 @@
hookargs = {}
if tr is not None:
hookargs.update(tr.hookargs)
- pending = lambda: tr.writepending() and self.root or ""
- hookargs['pending'] = pending
hookargs['namespace'] = namespace
hookargs['key'] = key
hookargs['old'] = old
--- a/tests/test-backout.t Sat Oct 17 01:15:34 2015 +0900
+++ b/tests/test-backout.t Sat Oct 17 01:15:34 2015 +0900
@@ -259,6 +259,60 @@
line 2
line 3
+Test visibility of in-memory dirstate changes outside transaction to
+external hook process
+
+ $ cat > $TESTTMP/checkvisibility.sh <<EOF
+ > echo "==== \$1:"
+ > hg parents --template "{rev}:{node|short}\n"
+ > echo "===="
+ > EOF
+
+"hg backout --merge REV1" at REV2 below implies steps below:
+
+(1) update to REV1 (REV2 => REV1)
+(2) revert by REV1^1
+(3) commit backnig out revision (REV3)
+(4) update to REV2 (REV3 => REV2)
+(5) merge with REV3 (REV2 => REV2, REV3)
+
+== test visibility to external preupdate hook
+
+ $ hg update -q -C 2
+ $ hg --config extensions.strip= strip 3
+ saved backup bundle to * (glob)
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
+ > EOF
+
+("-m" is needed to avoid writing dirstte changes out at other than
+invocation of the hook to be examined)
+
+ $ hg backout --merge -d '3 0' 1 --tool=true -m 'fixed comment'
+ ==== preupdate:
+ 2:6ea3f2a197a2
+ ====
+ reverting a
+ created new head
+ changeset 3:d92a3f57f067 backs out changeset 1:5a50a024c182
+ ==== preupdate:
+ 3:d92a3f57f067
+ ====
+ merging with changeset 3:d92a3f57f067
+ ==== preupdate:
+ 2:6ea3f2a197a2
+ ====
+ merging a
+ 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > preupdate.visibility =
+ > EOF
+
$ cd ..
backout should not back out subsequent changesets
--- a/tests/test-import.t Sat Oct 17 01:15:34 2015 +0900
+++ b/tests/test-import.t Sat Oct 17 01:15:34 2015 +0900
@@ -533,6 +533,110 @@
$ hg --cwd b revert --no-backup a
$ rm -f b/foo
+== test visibility to precommit external hook
+
+ $ cat >> b/.hg/hgrc <<EOF
+ > [hooks]
+ > precommit.visibility = sh $TESTTMP/checkvisibility.sh
+ > EOF
+
+ $ (cd b && sh "$TESTTMP/checkvisibility.sh")
+ ====
+ VISIBLE 0:80971e65b431
+ ACTUAL 0:80971e65b431
+ ====
+
+ $ hg --cwd b import ../patch1 ../patch2 ../patch3
+ applying ../patch1
+ ====
+ VISIBLE 0:80971e65b431
+ M a
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+ applying ../patch2
+ ====
+ VISIBLE 1:1d4bd90af0e4
+ M a
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+ applying ../patch3
+ ====
+ VISIBLE 2:6d019af21222
+ A foo
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+
+ $ hg --cwd b rollback -q
+ $ (cd b && sh "$TESTTMP/checkvisibility.sh")
+ ====
+ VISIBLE 0:80971e65b431
+ M a
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+ $ hg --cwd b revert --no-backup a
+ $ rm -f b/foo
+
+ $ cat >> b/.hg/hgrc <<EOF
+ > [hooks]
+ > precommit.visibility =
+ > EOF
+
+== test visibility to pretxncommit external hook
+
+ $ cat >> b/.hg/hgrc <<EOF
+ > [hooks]
+ > pretxncommit.visibility = sh $TESTTMP/checkvisibility.sh
+ > EOF
+
+ $ (cd b && sh "$TESTTMP/checkvisibility.sh")
+ ====
+ VISIBLE 0:80971e65b431
+ ACTUAL 0:80971e65b431
+ ====
+
+ $ hg --cwd b import ../patch1 ../patch2 ../patch3
+ applying ../patch1
+ ====
+ VISIBLE 0:80971e65b431
+ M a
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+ applying ../patch2
+ ====
+ VISIBLE 1:1d4bd90af0e4
+ M a
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+ applying ../patch3
+ ====
+ VISIBLE 2:6d019af21222
+ A foo
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+
+ $ hg --cwd b rollback -q
+ $ (cd b && sh "$TESTTMP/checkvisibility.sh")
+ ====
+ VISIBLE 0:80971e65b431
+ M a
+ ACTUAL 0:80971e65b431
+ M a
+ ====
+ $ hg --cwd b revert --no-backup a
+ $ rm -f b/foo
+
+ $ cat >> b/.hg/hgrc <<EOF
+ > [hooks]
+ > pretxncommit.visibility =
+ > EOF
+
$ rm -r b
--- a/tests/test-mq-qrefresh-replace-log-message.t Sat Oct 17 01:15:34 2015 +0900
+++ b/tests/test-mq-qrefresh-replace-log-message.t Sat Oct 17 01:15:34 2015 +0900
@@ -242,3 +242,85 @@
====
0:25e397dabed2
====
+
+== test visibility to precommit external hook
+
+ $ hg update -C -q
+ $ rm -f file2
+ $ hg qpush -q second-patch --config hooks.pretxncommit.unexpectedabort=
+ now at: second-patch
+ $ echo bbbb >> file2
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > precommit.checkvisibility = sh "$TESTTMP/checkvisibility.sh"
+ > EOF
+
+ $ sh "$TESTTMP/checkvisibility.sh"
+ ====
+ 1:e30108269082
+ M file2
+ ====
+
+ $ hg qrefresh
+ ====
+ 0:25e397dabed2
+ A file2
+ ====
+ transaction abort!
+ rollback completed
+ refresh interrupted while patch was popped! (revert --all, qpush to recover)
+ abort: pretxncommit.unexpectedabort hook exited with status 1
+ [255]
+
+ $ sh "$TESTTMP/checkvisibility.sh"
+ ====
+ 0:25e397dabed2
+ ====
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > precommit.checkvisibility =
+ > EOF
+
+== test visibility to pretxncommit external hook
+
+ $ hg update -C -q
+ $ rm -f file2
+ $ hg qpush -q second-patch --config hooks.pretxncommit.unexpectedabort=
+ now at: second-patch
+ $ echo bbbb >> file2
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > pretxncommit.checkvisibility = sh "$TESTTMP/checkvisibility.sh"
+ > # make checkvisibility run before unexpectedabort
+ > priority.pretxncommit.checkvisibility = 10
+ > EOF
+
+ $ sh "$TESTTMP/checkvisibility.sh"
+ ====
+ 1:e30108269082
+ M file2
+ ====
+
+ $ hg qrefresh
+ ====
+ 0:25e397dabed2
+ A file2
+ ====
+ transaction abort!
+ rollback completed
+ refresh interrupted while patch was popped! (revert --all, qpush to recover)
+ abort: pretxncommit.unexpectedabort hook exited with status 1
+ [255]
+
+ $ sh "$TESTTMP/checkvisibility.sh"
+ ====
+ 0:25e397dabed2
+ ====
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > pretxncommit.checkvisibility =
+ > EOF
--- a/tests/test-shelve.t Sat Oct 17 01:15:34 2015 +0900
+++ b/tests/test-shelve.t Sat Oct 17 01:15:34 2015 +0900
@@ -1011,6 +1011,84 @@
7e30d8ac6f23cfc84330fd7e698730374615d21a
$ cd ..
+Test visibility of in-memory changes inside transaction to external hook
+------------------------------------------------------------------------
+
+ $ cd repo
+
+ $ echo xxxx >> x
+ $ hg commit -m "#5: changes to invoke rebase"
+
+ $ cat > $TESTTMP/checkvisibility.sh <<EOF
+ > echo "==== \$1:"
+ > hg parents --template "VISIBLE {rev}:{node|short}\n"
+ > # test that pending changes are hidden
+ > unset HG_PENDING
+ > hg parents --template "ACTUAL {rev}:{node|short}\n"
+ > echo "===="
+ > EOF
+
+ $ cat >> .hg/hgrc <<EOF
+ > [defaults]
+ > # to fix hash id of temporary revisions
+ > unshelve = --date '0 0'
+ > EOF
+
+"hg unshelve" at REV5 implies steps below:
+
+(1) commit changes in the working directory (REV6)
+(2) unbundle shelved revision (REV7)
+(3) rebase: merge REV7 into REV6 (REV6 => REV6, REV7)
+(4) rebase: commit merged revision (REV8)
+(5) rebase: update to REV6 (REV8 => REV6)
+(6) update to REV5 (REV6 => REV5)
+(7) abort transaction
+
+== test visibility to external preupdate hook
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > preupdate.visibility = sh $TESTTMP/checkvisibility.sh preupdate
+ > EOF
+
+ $ echo nnnn >> n
+
+ $ sh $TESTTMP/checkvisibility.sh before-unshelving
+ ==== before-unshelving:
+ VISIBLE 5:703117a2acfb
+ ACTUAL 5:703117a2acfb
+ ====
+
+ $ hg unshelve --keep default
+ temporarily committing pending changes (restore with 'hg unshelve --abort')
+ rebasing shelved changes
+ rebasing 7:fcbb97608399 "changes to 'create conflict'" (tip)
+ ==== preupdate:
+ VISIBLE 6:66b86db80ee4
+ ACTUAL 5:703117a2acfb
+ ====
+ ==== preupdate:
+ VISIBLE 8:cb2a4e59c2d5
+ ACTUAL 5:703117a2acfb
+ ====
+ ==== preupdate:
+ VISIBLE 6:66b86db80ee4
+ ACTUAL 5:703117a2acfb
+ ====
+
+ $ cat >> .hg/hgrc <<EOF
+ > [hooks]
+ > preupdate.visibility =
+ > EOF
+
+ $ sh $TESTTMP/checkvisibility.sh after-unshelving
+ ==== after-unshelving:
+ VISIBLE 5:703117a2acfb
+ ACTUAL 5:703117a2acfb
+ ====
+
+ $ cd ..
+
test Abort unshelve always gets user out of the unshelved state
---------------------------------------------------------------
$ hg init salvage