Mercurial > public > mercurial-scm > evolve
changeset 7015:6ffc4d7635fa
topic: patch localrepo._makedirstate() to avoid touching global dirstate
This should avoid incompatibility with other extension altering the dirstate.
There are 2 cases here when we patch dirstate class on the fly: in
repo._makedirstate() and in peer.local(). The first one is the "normal" way of
making a dirstate for a repo and covers almost all cases, and the second one is
special. In some cases during clone our dirstate is not correctly handled, so
we need this band-aid solution just for clones on Mercurial 6.9 and older. See
also 0f2268783c11 in core.
author | Anton Shestakov <av6@dwimlabs.net> |
---|---|
date | Sat, 16 Nov 2024 18:15:11 +0400 |
parents | 42c10cc2ef03 |
children | cc80c5c793a7 |
files | hgext3rd/topic/__init__.py |
diffstat | 1 files changed, 80 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext3rd/topic/__init__.py Fri Jan 31 10:51:43 2025 +0100 +++ b/hgext3rd/topic/__init__.py Sat Nov 16 18:15:11 2024 +0400 @@ -644,6 +644,63 @@ repo.ui.setconfig(b'rebase', b'experimental.inmemory', b'False', source=b'topic-extension') + class _topicdirstate: + @dirstate.repocache(b'topic') + def _topic(self): + try: + return self._opener.read(b'topic').strip() or b'' + except IOError as inst: + if inst.errno != errno.ENOENT: + raise + return b'' + + def topic(self): + return encoding.tolocal(self._topic) + + def settopic(self, topic, tr): + self.__class__._topic.set(self, encoding.fromlocal(topic)) + del topic # safeguard to not use it after adjusting encoding + vfs = self._opener + if self._topic != b'': + with vfs(b'topic', b'w', atomictemp=True, checkambig=True) as f: + f.write(self._topic + b'\n') + else: + vfs.tryunlink(b'topic') + ce = self._filecache[b'_topic'] + if ce: + ce.refresh() + + @dirstate.repocache(b'topic-namespace') + def _tns(self): + try: + return self._opener.read(b'topic-namespace').strip() or b'none' + except IOError as inst: + if inst.errno != errno.ENOENT: + raise + return b'none' + + def tns(self): + return encoding.tolocal(self._tns) + + def settns(self, tns, tr): + self.__class__._tns.set(self, encoding.fromlocal(tns)) + del tns # safeguard to not use it after adjusting encoding + vfs = self._opener + if self._tns != b'none': + with vfs(b'topic-namespace', b'w', atomictemp=True, checkambig=True) as f: + f.write(self._tns + b'\n') + else: + vfs.tryunlink(b'topic-namespace') + ce = self._filecache[b'_tns'] + if ce: + ce.refresh() + + def fqbn(self, length=common.FQBN_NORMAL): + branch = encoding.tolocal(self._branch) + tns = encoding.tolocal(self._tns) + topic = encoding.tolocal(self._topic) + return common.formatfqbn(branch, tns, topic, length=length) + class topicrepo(repo.__class__): # attribute for other code to distinct between repo with topic and repo without @@ -721,6 +778,15 @@ raise return wlock + def _makedirstate(self): + dirstate = super(topicrepo, self)._makedirstate() + + class topicdirstate(dirstate.__class__, _topicdirstate): + pass + + dirstate.__class__ = topicdirstate + return dirstate + @property def currenttns(self): return self.dirstate.tns() @@ -819,6 +885,20 @@ if tns == b'none' or tns in namespaces: h.extend(nodes) return h + + def local(self): + repo = super(topicpeer, self).local() + # work around wild assignement of dirstate during + # copy-clone prior to hg <= 6.9 + # hg <= 6.9 (0f2268783c11) + dirstate = vars(repo.unfiltered()).get('dirstate') + if dirstate is not None and not isinstance(dirstate, _topicdirstate): + class topicdirstate(dirstate.__class__, _topicdirstate): + pass + + dirstate.__class__ = topicdirstate + return repo + peer.__class__ = topicpeer return peer @@ -924,65 +1004,6 @@ b'topics', b'topic', namemap=_namemap, nodemap=_nodemap, listnames=lambda repo: repo.topics)) - class topicdirstate(dirstate.dirstate): - @dirstate.repocache(b'topic') - def _topic(self): - try: - return self._opener.read(b'topic').strip() or b'' - except IOError as inst: - if inst.errno != errno.ENOENT: - raise - return b'' - - def topic(self): - return encoding.tolocal(self._topic) - - def settopic(self, topic, tr): - self.__class__._topic.set(self, encoding.fromlocal(topic)) - del topic # safeguard to not use it after adjusting encoding - vfs = self._opener - if self._topic != b'': - with vfs(b'topic', b'w', atomictemp=True, checkambig=True) as f: - f.write(self._topic + b'\n') - else: - vfs.tryunlink(b'topic') - ce = self._filecache[b'_topic'] - if ce: - ce.refresh() - - @dirstate.repocache(b'topic-namespace') - def _tns(self): - try: - return self._opener.read(b'topic-namespace').strip() or b'none' - except IOError as inst: - if inst.errno != errno.ENOENT: - raise - return b'none' - - def tns(self): - return encoding.tolocal(self._tns) - - def settns(self, tns, tr): - self.__class__._tns.set(self, encoding.fromlocal(tns)) - del tns # safeguard to not use it after adjusting encoding - vfs = self._opener - if self._tns != b'none': - with vfs(b'topic-namespace', b'w', atomictemp=True, checkambig=True) as f: - f.write(self._tns + b'\n') - else: - vfs.tryunlink(b'topic-namespace') - ce = self._filecache[b'_tns'] - if ce: - ce.refresh() - - def fqbn(self, length=common.FQBN_NORMAL): - branch = encoding.tolocal(self._branch) - tns = encoding.tolocal(self._tns) - topic = encoding.tolocal(self._topic) - return common.formatfqbn(branch, tns, topic, length=length) - - dirstate.dirstate = topicdirstate - templatekeyword = registrar.templatekeyword() @templatekeyword(b'topic', requires={b'ctx'})