Patchwork [5,of,6] hook: centralize HG_PENDING passing to external hook process

login
register
mail settings
Submitter Katsunori FUJIWARA
Date Oct. 14, 2015, 5:35 p.m.
Message ID <806dc96ae4a3526b9c20.1444844120@feefifofum>
Download mbox | patch
Permalink /patch/11066/
State Accepted
Headers show

Comments

Katsunori FUJIWARA - Oct. 14, 2015, 5:35 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1444843899 -32400
#      Thu Oct 15 02:31:39 2015 +0900
# Node ID 806dc96ae4a3526b9c20a9e89428bff08631a2cf
# Parent  6036b2db93e866c4af9587675c61db8946543c3a
hook: centralize HG_PENDING passing to external hook process

To centralize HG_PENDING passing to external hook process, this patch
passes 'repo' to 'ui.system()'.

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.

Patch

diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -837,14 +837,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()
diff --git a/mercurial/hook.py b/mercurial/hook.py
--- a/mercurial/hook.py
+++ b/mercurial/hook.py
@@ -132,7 +132,7 @@ 
         cwd = repo.root
     else:
         cwd = os.getcwd()
-    r = ui.system(cmd, environ=env, cwd=cwd)
+    r = ui.system(cmd, environ=env, cwd=cwd, repo=repo)
 
     duration = time.time() - starttime
     ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -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()
@@ -1672,10 +1671,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:
@@ -1855,8 +1853,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
diff --git a/tests/test-backout.t b/tests/test-backout.t
--- a/tests/test-backout.t
+++ b/tests/test-backout.t
@@ -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
diff --git a/tests/test-import.t b/tests/test-import.t
--- a/tests/test-import.t
+++ b/tests/test-import.t
@@ -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
 
 
diff --git a/tests/test-mq-qrefresh-replace-log-message.t b/tests/test-mq-qrefresh-replace-log-message.t
--- a/tests/test-mq-qrefresh-replace-log-message.t
+++ b/tests/test-mq-qrefresh-replace-log-message.t
@@ -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
diff --git a/tests/test-shelve.t b/tests/test-shelve.t
--- a/tests/test-shelve.t
+++ b/tests/test-shelve.t
@@ -1010,3 +1010,81 @@ 
   changegroup -- "{'version': '02'}"
       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 ..