2ccf6a561750 — Tony Tung 8 years ago
[bundle2hooks] allow hook arguments to be stored on the operation object

Summary:
Some bundle2 handlers (such as pushvars) run prior to the acquisition of the lock.  In order to have those handlers be able to set hook variables, we have to save the hook variables onto the bundle object, rather than the transaction object.

Once the transaction is retrieved, we drain all the hook arguments into the transaction.  Further attempts to call `addhookargs will cause an abort.

An alternative to aborting is to save the transaction, and pass further arguments to the transaction.  I believe this is an inferior choice because it is masking a bug.

Test Plan: run ./verify_reviewedby_info.t in opsfiles with D2880506 patched in.  passed.

Reviewers: #sourcecontrol, durham

Reviewed By: durham

Subscribers: durham, mitrandir

Differential Revision: https://phabricator.fb.com/D2898401

Signature: t1:2898401:1454615031:94933cf513eaa06c5b60686ec5d65a563ddc31c4
2 files changed, 48 insertions(+), 0 deletions(-)

A => bundle2hooks.py
M setup.py
A => bundle2hooks.py +46 -0
@@ 0,0 1,46 @@ 
+# bundle2hooks.py - fix bundle2's support for hooks prior to lock acquisition.
+#
+# Copyright 2012 Facebook
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+'''Hooks arguments are typically stored on the transaction object.  However, we
+may want to add hooks arguments without starting a transaction.  This allows us
+to queue hook arguments on the bundle2 operation object.
+
+'''
+
+from mercurial import bundle2
+
+from extutil import replaceclass
+
+def reposetup(ui, repo):
+    @replaceclass(bundle2, 'bundleoperation')
+    class bundleoperationhooked(bundle2.bundleoperation):
+        def __init__(self, repo, transactiongetter, *args, **kwargs):
+            def gettransaction():
+                transaction = transactiongetter()
+
+                if self.hookargs is not None:
+                    # the ones added to the transaction supercede those added to
+                    # the operation.
+                    self.hookargs.update(transaction.hookargs)
+                    transaction.hookargs = self.hookargs
+
+                    # mark the hookargs as flushed.  further attempts to add to
+                    # hookargs will result in an abort.
+                    self.hookargs = None
+
+                return transaction
+
+            super(bundleoperationhooked, self).__init__(repo, gettransaction,
+                                                        *args, **kwargs)
+
+            self.hookargs = {}
+
+        def addhookargs(self, hookargs):
+            if self.hookargs is None:
+                raise error.Abort(_('attempted to add hooks to operation after '
+                                    'transaction started'))
+            self.hookargs.update(hookargs)

          
M setup.py +2 -0
@@ 17,11 17,13 @@ setup(
     py_modules=[
         'automv',
         'backups',
+        'bundle2hooks',
         'catnotate',
         'chistedit',
         'commitextras',
         'dirsync',
         'errorredirect',
+        'ext2util',
         'fbamend',
         'fbconduit',
         'fbhistedit',