# HG changeset patch # User Tony Tung # Date 1454630357 28800 # Thu Feb 04 15:59:17 2016 -0800 # Node ID 2ccf6a5617509d364e2618635d6a37bea31eee34 # Parent a8805edec6460792848863fb5773297bbb360d28 [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 diff --git a/bundle2hooks.py b/bundle2hooks.py new file mode 100644 --- /dev/null +++ b/bundle2hooks.py @@ -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) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -17,11 +17,13 @@ py_modules=[ 'automv', 'backups', + 'bundle2hooks', 'catnotate', 'chistedit', 'commitextras', 'dirsync', 'errorredirect', + 'ext2util', 'fbamend', 'fbconduit', 'fbhistedit',