diff --git a/mercurial/dirstateguard.py b/mercurial/dirstateguard.py --- a/mercurial/dirstateguard.py +++ b/mercurial/dirstateguard.py @@ -11,9 +11,10 @@ from . import ( error, + util, ) -class dirstateguard(object): +class dirstateguard(util.transactional): '''Restore dirstate at unexpected failure. At the construction, this class does: @@ -43,16 +44,6 @@ # ``release(tr, ....)``. self._abort() - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - try: - if exc_type is None: - self.close() - finally: - self.release() - def close(self): if not self._active: # already inactivated msg = (_("can't close already inactivated backup: %s") diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -1168,7 +1168,7 @@ # deprecated; talk to trmanager directly return self.trmanager.transaction() -class transactionmanager(object): +class transactionmanager(util.transactional): """An object to manage the life cycle of a transaction It creates the transaction on demand and calls the appropriate hooks when diff --git a/mercurial/transaction.py b/mercurial/transaction.py --- a/mercurial/transaction.py +++ b/mercurial/transaction.py @@ -101,7 +101,7 @@ # only pure backup file remains, it is sage to ignore any error pass -class transaction(object): +class transaction(util.transactional): def __init__(self, report, opener, vfsmap, journalname, undoname=None, after=None, createmode=None, validator=None, releasefn=None, checkambigfiles=None): @@ -376,16 +376,6 @@ if self.count > 0 and self.usages == 0: self._abort() - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - try: - if exc_type is None: - self.close() - finally: - self.release() - def running(self): return self.count > 0 diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -592,6 +592,24 @@ for k, v in src: self[k] = v +class transactional(object): + + def close(self): + raise NotImplementedError + + def release(self): + raise NotImplementedError + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + try: + if exc_type is None: + self.close() + finally: + self.release() + @contextlib.contextmanager def acceptintervention(tr=None): """A context manager that closes the transaction on InterventionRequired