builddependencies: don't add dependency on revision outside input set
This was already handled in the single-successor case, but had been
missed in the multiple-successors case.
Note that there seems to be a copy of builddependencies() in the
topics extension. I don't use topics more than I have to, so I'll let
someone else fix that code.
"""enable a minimal verison of topic for serverNon publishing repository will see topic as "branch:topic" in the branch field.In addition to adding the extensions, the feature must be manually enabled in the config: [experimental] server-mini-topic = yes"""importhashlibimportcontextlibfrommercurialimport(branchmap,context,encoding,extensions,node,registrar,util,)try:frommercurialimportwireprotowireproto.branchmapexceptImportError:# <= hg-4.5frommercurialimportwireprotov1serveraswireprotoifutil.safehasattr(registrar,'configitem'):configtable={}configitem=registrar.configitem(configtable)configitem('experimental','server-mini-topic',default=False,)defhasminitopic(repo):"""true if minitopic is enabled on the repository (The value is cached on the repository) """enabled=getattr(repo,'_hasminitopic',None)ifenabledisNone:enabled=(repo.ui.configbool('experimental','server-mini-topic')andnotrepo.publishing())repo._hasminitopic=enabledreturnenabled### make topic visible though "ctx.branch()"deftopicbranch(orig,self):branch=orig(self)ifhasminitopic(self._repo)andself.phase():topic=self._changeset.extra.get('topic')iftopicisnotNone:topic=encoding.tolocal(topic)branch='%s:%s'%(branch,topic)returnbranch### avoid caching topic data in rev-branch-cacheclassrevbranchcacheoverlay(object):"""revbranch mixin that don't use the cache for non public changeset"""def_init__(self,*args,**kwargs):super(revbranchcacheoverlay,self).__init__(*args,**kwargs)if'branchinfo'invars(self):delself.branchinfodefbranchinfo(self,rev):"""return branch name and close flag for rev, using and updating persistent cache."""phase=self._repo._phasecache.phase(self._repo,rev)ifphase:ctx=self._repo[rev]returnctx.branch(),ctx.closesbranch()returnsuper(revbranchcacheoverlay,self).branchinfo(rev)defreposetup(ui,repo):"""install a repo class with a special revbranchcache"""ifhasminitopic(repo):repo=repo.unfiltered()classminitopicrepo(repo.__class__):"""repository subclass that install the modified cache"""defrevbranchcache(self):ifself._revbranchcacheisNone:cache=super(minitopicrepo,self).revbranchcache()classtopicawarerbc(revbranchcacheoverlay,cache.__class__):passcache.__class__=topicawarerbcif'branchinfo'invars(cache):delcache.branchinfoself._revbranchcache=cachereturnself._revbranchcacherepo.__class__=minitopicrepo### topic aware branch head cachedef_phaseshash(repo,maxrev):"""uniq ID for a phase matching a set of rev"""revs=set()cl=repo.changelogfr=cl.filteredrevsnm=cl.nodemapforrootsinrepo._phasecache.phaseroots[1:]:forninroots:r=nm.get(n)ifrnotinfrandr<maxrev:revs.add(r)key=node.nullidrevs=sorted(revs)ifrevs:s=hashlib.sha1()forrevinrevs:s.update('%s;'%rev)key=s.digest()returnkey# needed to prevent reference used for 'super()' call using in branchmap.py to# no go into cycle. (yes, URG)_oldbranchmap=branchmap.branchcache@contextlib.contextmanagerdefoldbranchmap():previous=branchmap.branchcachetry:branchmap.branchcache=_oldbranchmapyieldfinally:branchmap.branchcache=previous_publiconly=set(['base','immutable',])defmighttopic(repo):returnhasminitopic(repo)andrepo.filternamenotin_publiconlyclass_topiccache(branchmap.branchcache):# combine me with branchmap.branchcachedef__init__(self,*args,**kwargs):# super() call may fail otherwisewitholdbranchmap():super(_topiccache,self).__init__(*args,**kwargs)self.phaseshash=Nonedefcopy(self):"""return an deep copy of the branchcache object"""new=self.__class__(self,self.tipnode,self.tiprev,self.filteredhash,self._closednodes)new.phaseshash=self.phaseshashreturnnewdefvalidfor(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."""valid=super(_topiccache,self).validfor(repo)ifnotvalid:returnFalseelifself.phaseshashisNone:# phasehash at None means this is a branchmap# coming from a public only setreturnTrueelse:try:valid=self.phaseshash==_phaseshash(repo,self.tiprev)returnvalidexceptIndexError:returnFalsedefwrite(self,repo):# we expect (hope) mutable set to be small enough to be that computing# it all the time will be fast enoughifnotmighttopic(repo):super(_topiccache,self).write(repo)defupdate(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. """super(_topiccache,self).update(repo,revgen)ifmighttopic(repo):self.phaseshash=_phaseshash(repo,self.tiprev)defwrapread(orig,repo):# Avoiding to write cache for filter where topic applies is a good step,# but we need to also avoid reading it. Existing branchmap cache might# exists before the turned the feature on.ifmighttopic(repo):returnNonereturnorig(repo)# advertise topic capabilitiesdefwireprotocaps(orig,repo,proto):caps=orig(repo,proto)ifhasminitopic(repo):caps.append('topics')returncaps# wrap the necessary bitdefwrapclass(container,oldname,new):old=getattr(container,oldname)ifnotissubclass(old,new):targetclass=new# check if someone else already wrapped the class and handle thatifnotissubclass(new,old):classtargetclass(new,old):passsetattr(container,oldname,targetclass)current=getattr(container,oldname)assertissubclass(current,new),(current,new,targetclass)defuisetup(ui):wrapclass(branchmap,'branchcache',_topiccache)extensions.wrapfunction(branchmap,'read',wrapread)extensions.wrapfunction(wireproto,'_capabilities',wireprotocaps)extensions.wrapfunction(context.changectx,'branch',topicbranch)