Mercurial > public > mercurial-scm > hg
diff mercurial/localrepo.py @ 39606:c5e6c1ba1c79
hg: don't reuse repo instance after unshare()
Unsharing a repository is a pretty invasive procedure and fundamentally
changes the behavior of the repository.
Currently, hg.unshare() calls into localrepository.__init__ to
re-initialize the repository instance. This is a bit hacky. And
future commits that refactor how localrepository instances are
constructed will make this difficult to support.
This commit changes unshare() so it constructs a new repo instance
once the unshare I/O has completed. It then poisons the old repo
instance so any further use will result in error.
Surprisingly, nothing in core appears to access a repo instance
after it has been unshared!
.. api::
``hg.unshare()`` now poisons the repo instance so it can't be used.
It also returns a new repo instance suitable for interacting with
the unshared repository.
Differential Revision: https://phab.mercurial-scm.org/D4557
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Wed, 12 Sep 2018 19:00:46 -0700 |
parents | 76b58f240821 |
children | 24870f1be088 |
line wrap: on
line diff
--- a/mercurial/localrepo.py Tue Sep 11 20:06:39 2018 -0700 +++ b/mercurial/localrepo.py Wed Sep 12 19:00:46 2018 -0700 @@ -2503,3 +2503,28 @@ b'layout') scmutil.writerequires(hgvfs, requirements) + +def poisonrepository(repo): + """Poison a repository instance so it can no longer be used.""" + # Perform any cleanup on the instance. + repo.close() + + # Our strategy is to replace the type of the object with one that + # has all attribute lookups result in error. + # + # But we have to allow the close() method because some constructors + # of repos call close() on repo references. + class poisonedrepository(object): + def __getattribute__(self, item): + if item == r'close': + return object.__getattribute__(self, item) + + raise error.ProgrammingError('repo instances should not be used ' + 'after unshare') + + def close(self): + pass + + # We may have a repoview, which intercepts __setattr__. So be sure + # we operate at the lowest level possible. + object.__setattr__(repo, r'__class__', poisonedrepository)