metaedit: add support for storing a note in obsmarker
from__future__importabsolute_importimportcollectionsimportweakreffrommercurial.i18nimport_frommercurialimport(bundle2,discovery,error,exchange,extensions,util,wireproto,)def_headssummary(orig,*args):# In mercurial < 4.2, we receive repo, remote and outgoing as argumentspushop=Noneiflen(args)==3:pushoparg=Falserepo,remote,outgoing=args# In mercurial > 4.3, we receive the pushop as argumentseliflen(args)==1:pushoparg=Truepushop=args[0]repo=pushop.repo.unfiltered()remote=pushop.remoteelse:msg='topic-ext _headssummary() takes 1 or 3 arguments (%d given)'raiseTypeError(msg%len(args))publishing=('phases'notinremote.listkeys('namespaces')orbool(remote.listkeys('phases').get('publishing',False)))if((publishingornotremote.capable('topics'))andnotgetattr(pushop,'publish',False)):returnorig(*args)publishedset=()remotebranchmap=Noneorigremotebranchmap=remote.branchmap# < hg-4.4 do not have a --publish flag anywayifpushopargandutil.safehasattr(pushop,'remotephases'):publishednode=[c.node()forcinpushop.outdatedphases]publishedset=repo.revs('ancestors(%ln + %ln)',publishednode,pushop.remotephases.publicheads)rev=repo.unfiltered().changelog.nodemap.getdefremotebranchmap():# drop topic information from changeset about to be publishedresult=collections.defaultdict(list)forbranch,headsinorigremotebranchmap().iteritems():if':'notinbranch:result[branch].extend(heads)else:namedbranch=branch.split(':',1)[0]forhinheads:r=rev(h)ifrisnotNoneandrinpublishedset:result[namedbranch].append(h)else:result[branch].append(h)forheadsinresult.itervalues():heads.sort()returnresultclassrepocls(repo.__class__):# awful hack to see branch as "branch:topic"def__getitem__(self,key):ctx=super(repocls,self).__getitem__(key)oldbranch=ctx.branchrev=ctx.rev()defbranch():branch=oldbranch()ifrevinpublishedset:returnbranchtopic=ctx.topic()iftopic:branch="%s:%s"%(branch,topic)returnbranchctx.branch=branchreturnctxdefrevbranchcache(self):rbc=super(repocls,self).revbranchcache()changelog=self.changelogdefbranchinfo(rev):branch,close=changelog.branchinfo(rev)ifrevinpublishedset:returnbranch,closetopic=repo[rev].topic()iftopic:branch="%s:%s"%(branch,topic)returnbranch,closerbc.branchinfo=branchinforeturnrbcoldrepocls=repo.__class__try:repo.__class__=repoclsifremotebranchmapisnotNone:remote.branchmap=remotebranchmapunxx=repo.filtered('unfiltered-topic')repo.unfiltered=lambda:unxxifpushoparg:pushop.repo=reposummary=orig(pushop)else:summary=orig(repo,remote,outgoing)forkey,valueinsummary.iteritems():if':'inkey:# This is a topicifvalue[0]isNoneandvalue[1]:summary[key]=([value[1][0]],)+value[1:]returnsummaryfinally:if'unfiltered'invars(repo):delrepo.unfilteredrepo.__class__=oldrepoclsifremotebranchmapisnotNone:remote.branchmap=origremotebranchmapdefwireprotobranchmap(orig,repo,proto):oldrepo=repo.__class__try:classrepocls(repo.__class__):defbranchmap(self):usetopic=notself.publishing()returnsuper(repocls,self).branchmap(topic=usetopic)repo.__class__=repoclsreturnorig(repo,proto)finally:repo.__class__=oldrepo# Discovery have deficiency around phases, branch can get new heads with pure# phases change. This happened with a changeset was allowed to be pushed# because it had a topic, but it later become public and create a new branch# head.## Handle this by doing an extra check for new head creation server sidedef_nbheads(repo):data={}forbinrepo.branchmap().iterbranches():if':'inb[0]:continuedata[b[0]]=len(b[1])returndatadefhandlecheckheads(orig,op,inpart):"""This is used to check for new heads when publishing changeset"""orig(op,inpart)ifop.repo.publishing():returntr=op.gettransaction()iftr.hookargs['source']notin('push','serve'):# not a pushreturntr._prepushheads=_nbheads(op.repo)reporef=weakref.ref(op.repo)oldvalidator=tr.validatordefvalidator(tr):repo=reporef()ifrepoisnotNone:repo.invalidatecaches()finalheads=_nbheads(repo)forbranch,oldnbintr._prepushheads.iteritems():newnb=finalheads.pop(branch,0)ifoldnb<newnb:msg=_('push create a new head on branch "%s"'%branch)raiseerror.Abort(msg)forbranch,newnbinfinalheads.iteritems():if1<newnb:msg=_('push create more than 1 head on new branch "%s"'%branch)raiseerror.Abort(msg)returnoldvalidator(tr)tr.validator=validatorhandlecheckheads.params=frozenset()def_pushb2phases(orig,pushop,bundler):checktypes=('check:heads','check:updated-heads')hascheck=any(p.typeinchecktypesforpinbundler._parts)ifnothascheckandpushop.outdatedphases:exchange._pushb2ctxcheckheads(pushop,bundler)returnorig(pushop,bundler)defwireprotocaps(orig,repo,proto):caps=orig(repo,proto)ifrepo.peer().capable('topics'):caps.append('topics')returncapsdefmodsetup(ui):"""run at uisetup time to install all destinations wrapping"""extensions.wrapfunction(discovery,'_headssummary',_headssummary)extensions.wrapfunction(wireproto,'branchmap',wireprotobranchmap)extensions.wrapfunction(wireproto,'_capabilities',wireprotocaps)# we need a proper wrap b2 part stuffextensions.wrapfunction(bundle2,'handlecheckheads',handlecheckheads)bundle2.handlecheckheads.params=frozenset()bundle2.parthandlermapping['check:heads']=bundle2.handlecheckheadsifutil.safehasattr(bundle2,'handlecheckupdatedheads'):# we still need a proper wrap b2 part stuffextensions.wrapfunction(bundle2,'handlecheckupdatedheads',handlecheckheads)bundle2.handlecheckupdatedheads.params=frozenset()bundle2.parthandlermapping['check:updated-heads']=bundle2.handlecheckupdatedheadsextensions.wrapfunction(exchange,'_pushb2phases',_pushb2phases)exchange.b2partsgenmapping['phase']=exchange._pushb2phases