# HG changeset patch # User Anton Shestakov # Date 1718206051 -14400 # Node ID cd8e1a69712497048333610b5372ec277381d758 # Parent 0674b56d352669dec226993eb4c1dcc9e2b2c117 topic: compatibility for branchmap.BranchCacheV2 diff -r 0674b56d3526 -r cd8e1a697124 hgext3rd/topic/topicmap.py --- a/hgext3rd/topic/topicmap.py Mon Mar 18 14:01:40 2024 -0300 +++ b/hgext3rd/topic/topicmap.py Wed Jun 12 19:27:31 2024 +0400 @@ -121,26 +121,36 @@ return ret def _wrapbmcache(ui): - class topiccache(_topiccache, branchmap.branchcache): - pass - branchmap.branchcache = topiccache + if util.safehasattr(branchmap, 'BranchCacheV2'): + class TopicCache(_TopicCacheV2, branchmap.BranchCacheV2): + pass + branchmap.BranchCacheV2 = TopicCache - try: - # Mercurial 5.0 - class remotetopiccache(_topiccache, branchmap.remotebranchcache): + class remotetopiccache(_TopicCacheV2, branchmap.remotebranchcache): pass branchmap.remotebranchcache = remotetopiccache + else: + # hg <= 6.7 (ec640dc9cebd) + class topiccache(_topiccache, branchmap.branchcache): + pass + branchmap.branchcache = topiccache - def _wrapupdatebmcachemethod(orig, self, repo): - # pass in the bound method as the original - return _wrapupdatebmcache(orig.__get__(self), repo) - extensions.wrapfunction(branchmap.BranchMapCache, 'updatecache', _wrapupdatebmcachemethod) - except AttributeError: - # hg <= 4.9 (3461814417f3) - extensions.wrapfunction(branchmap, 'updatecache', _wrapupdatebmcache) - # branchcache in hg <= 4.9 doesn't have load method, instead there's a - # module-level function to read on-disk cache and return a branchcache - extensions.wrapfunction(branchmap, 'read', _wrapbmread) + try: + # Mercurial 5.0 + class remotetopiccache(_topiccache, branchmap.remotebranchcache): + pass + branchmap.remotebranchcache = remotetopiccache + + def _wrapupdatebmcachemethod(orig, self, repo): + # pass in the bound method as the original + return _wrapupdatebmcache(orig.__get__(self), repo) + extensions.wrapfunction(branchmap.BranchMapCache, 'updatecache', _wrapupdatebmcachemethod) + except AttributeError: + # hg <= 4.9 (3461814417f3) + extensions.wrapfunction(branchmap, 'updatecache', _wrapupdatebmcache) + # branchcache in hg <= 4.9 doesn't have load method, instead there's a + # module-level function to read on-disk cache and return a branchcache + extensions.wrapfunction(branchmap, 'read', _wrapbmread) def _wrapupdatebmcache(orig, repo): previous = getattr(repo, '_autobranchmaptopic', False) @@ -239,6 +249,87 @@ super(_topiccache, self).update(repo, revgen) self.phaseshash = _phaseshash(repo, self.tiprev) +class _TopicCacheV2(object): # combine me with branchmap.BranchCacheV2 + + def __init__(self, *args, **kwargs): + super(_TopicCacheV2, self).__init__(*args, **kwargs) + self.phaseshash = None + + def _load_heads(self, repo, lineiter): + """call BranchCacheV2._load_heads(), and then transform branch names to + be in the new "//" format + """ + assert isinstance(self, branchmap.BranchCacheV2) # help pytype + super(_TopicCacheV2, self)._load_heads(repo, lineiter) + + for branch in tuple(self._entries): + formatted = common.formatfqbn(branch=branch) + if branch != formatted: + self._entries[formatted] = self._entries.pop(branch) + + def validfor(self, repo): + """Is the cache content valid regarding a repo + + - False when cached tipnode is unknown or if we detect a strip. + - True when cache is up to date or a subset of current repo.""" + assert isinstance(self, (branchmap.BranchCacheV2, branchmap.remotebranchcache)) # help pytype + valid = super(_TopicCacheV2, self).validfor(repo) + if not valid: + return False + elif not istopicfilter(repo.filtername) or self.phaseshash is None: + # phasehash at None means this is a branchmap + # come from non topic thing + return True + else: + try: + valid = self.phaseshash == _phaseshash(repo, self.tiprev) + return valid + except IndexError: + return False + + def write(self, repo): + """write cache to disk if it's not topic-only, but first transform + cache keys from branches in "//" format into bare branch names + """ + # we expect mutable set to be small enough to be that computing it all + # the time will be fast enough + if not istopicfilter(repo.filtername): + entries = self._entries.copy() + + for formatted in tuple(entries): + branch, tns, topic = common.parsefqbn(formatted) + if branch != formatted: + entries[branch] = entries.pop(formatted) + + oldentries = self._entries + try: + self._entries = entries + super(_TopicCacheV2, self).write(repo) + finally: + self._entries = oldentries + + def update(self, repo, revgen): + """Given a branchhead cache, self, that may have extra nodes or be + missing heads, and a generator of nodes that are strictly a superset of + heads missing, this function updates self to be correct. + """ + assert isinstance(self, (branchmap.BranchCacheV2, branchmap.remotebranchcache)) # help pytype + if not istopicfilter(repo.filtername): + return super(_TopicCacheV2, self).update(repo, revgen) + + # See topic.discovery._headssummary(), where repo.unfiltered gets + # overridden to return .filtered('unfiltered-topic'). revbranchcache + # only can be created for unfiltered repo (filtername is None), so we + # do that here, and this revbranchcache will be cached inside repo. + # When we get rid of *-topic filters, then this workaround can be + # removed too. + repo.unfiltered().revbranchcache() + + super(_TopicCacheV2, self).update(repo, revgen) + if util.safehasattr(self, 'tiprev'): + # remotebranchcache doesn't have self.tiprev + self.phaseshash = _phaseshash(repo, self.tiprev) + def _wrapbmread(orig, repo): """call branchmap.read(), and then transform branch names to be in the new "//" format