test-compat: merge mercurial-4.3 into mercurial-4.2
importcontextlibimporthashlibfrommercurial.i18nimport_frommercurial.nodeimportnullidfrommercurialimport(branchmap,changegroup,cmdutil,extensions,repoview,)basefilter=set(['base','immutable'])deftopicfilter(name):"""return a "topic" version of a filter level"""ifnameinbasefilter:returnnameelifnameisNone:returnNoneelifname.endswith('-topic'):returnnameelse:returnname+'-topic'defistopicfilter(filtername):iffilternameisNone:returnFalsereturnfiltername.endswith('-topic')defgettopicrepo(repo):filtername=topicfilter(repo.filtername)iffiltername==repo.filtername:returnreporeturnrepo.filtered(filtername)def_setuptopicfilter(ui):"""extend the filter related mapping with topic related one"""funcmap=repoview.filtertablepartialmap=branchmap.subsettable# filter level not affected by topic that we should not overrideforplainnameinlist(funcmap):newfilter=topicfilter(plainname)ifnewfilter==plainname:continuedefrevsfunc(repo,name=plainname):returnrepoview.filterrevs(repo,name)base=topicfilter(partialmap[plainname])ifnewfilternotinfuncmap:funcmap[newfilter]=revsfuncpartialmap[newfilter]=basefuncmap['unfiltered-topic']=lambdarepo:frozenset()partialmap['unfiltered-topic']='visible-topic'def_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=nullidrevs=sorted(revs)ifrevs:s=hashlib.sha1()forrevinrevs:s.update('%s;'%rev)key=s.digest()returnkeydefmodsetup(ui):"""call at uisetup time to install various wrappings"""_setuptopicfilter(ui)_wrapbmcache(ui)extensions.wrapfunction(changegroup.cg1unpacker,'apply',cgapply)extensions.wrapfunction(cmdutil,'commitstatus',commitstatus)defcgapply(orig,self,repo,*args,**kwargs):"""make sure a topicmap is used when applying a changegroup"""other=repo.filtered(topicfilter(repo.filtername))returnorig(self,other,*args,**kwargs)defcommitstatus(orig,repo,node,branch,bheads=None,opts=None):# wrap commit status use the topic branch headsctx=repo[node]ifctx.topic()andctx.branch()==branch:subbranch="%s:%s"%(branch,ctx.topic())bheads=repo.branchheads("%s:%s"%(subbranch,ctx.topic()))ret=orig(repo,node,branch,bheads=bheads,opts=opts)# logic copy-pasted from cmdutil.commitstatus()ifoptsisNone:opts={}ctx=repo[node]ifctx.topic():returnretparents=ctx.parents()if(notopts.get('amend')andbheadsandnodenotinbheadsandnot[xforxinparentsifx.node()inbheadsandx.branch()==branch]):repo.ui.status(_("(consider using topic for lightweight branches."" See 'hg help topic')\n"))returnretdef_wrapbmcache(ui):classtopiccache(_topiccache,branchmap.branchcache):passbranchmap.branchcache=topiccacheextensions.wrapfunction(branchmap,'updatecache',_wrapupdatebmcache)def_wrapupdatebmcache(orig,repo):previous=getattr(repo,'_autobranchmaptopic',False)try:repo._autobranchmaptopic=Falsereturnorig(repo)finally:repo._autobranchmaptopic=previous# 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=previousclass_topiccache(object):# 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.phaseshashreturnnewdefbranchtip(self,branch,topic=''):'''Return the tipmost open head on branch head, otherwise return the tipmost closed head on branch. Raise KeyError for unknown branch.'''iftopic:branch='%s:%s'%(branch,topic)returnsuper(_topiccache,self).branchtip(branch)defbranchheads(self,branch,closed=False,topic=''):iftopic:branch='%s:%s'%(branch,topic)returnsuper(_topiccache,self).branchheads(branch,closed=closed)defvalidfor(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:returnFalseelifnotistopicfilter(repo.filtername)orself.phaseshashisNone:# phasehash at None means this is a branchmap# come from non topic thingreturnTrueelse:try:valid=self.phaseshash==_phaseshash(repo,self.tiprev)returnvalidexceptIndexError:returnFalsedefwrite(self,repo):# we expect mutable set to be small enough to be that computing it all# the time will be fast enoughifnotistopicfilter(repo.filtername):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. """ifnotistopicfilter(repo.filtername):returnsuper(_topiccache,self).update(repo,revgen)unfi=repo.unfiltered()oldgetbranchinfo=unfi.revbranchcache().branchinfodefbranchinfo(r):info=oldgetbranchinfo(r)topic=''ctx=unfi[r]ifctx.mutable():topic=ctx.topic()branch=info[0]iftopic:branch='%s:%s'%(branch,topic)return(branch,info[1])try:unfi.revbranchcache().branchinfo=branchinfosuper(_topiccache,self).update(repo,revgen)self.phaseshash=_phaseshash(repo,self.tiprev)finally:unfi.revbranchcache().branchinfo=oldgetbranchinfo