Qc@sdZddlZddlZddlZddlZddlmZejZej Z dZ e Z dZdZdZejeZejeZdZd Zd Zd Zd efd YZdefdYZe dZdZdZdZdZdZ dZ!dZ"dZ#dZ$ddZ%dZ&ddZ(dZ)iZ*dZ+dZ,d Z-e+d!d"Z.e+d#d$Z/e+d%d&Z0e+d'd(Z1e+d)d*Z2e+d+d,Z3ddd-Z4dS(.s Obsolete markers handling An obsolete marker maps an old changeset to a list of new changesets. If the list of new changesets is empty, the old changeset is said to be "killed". Otherwise, the old changeset is being "replaced" by the new changesets. Obsolete markers can be used to record and distribute changeset graph transformations performed by history rewriting operations, and help building new tools to reconciliate conflicting rewriting actions. To facilitate conflicts resolution, markers include various annotations besides old and news changeset identifiers, such as creation date or author name. The old obsoleted changeset is called "precursor" and possible replacements are called "successors". Markers that used changeset X as a precursors are called "successor markers of X" because they hold information about the successors of X. Markers that use changeset Y as a successors are call "precursor markers of Y" because they hold information about the precursors of Y. Examples: - When changeset A is replacement by a changeset A', one marker is stored: (A, (A')) - When changesets A and B are folded into a new changeset C two markers are stored: (A, (C,)) and (B, (C,)) - When changeset A is simply "pruned" from the graph, a marker in create: (A, ()) - When changeset A is split into B and C, a single marker are used: (A, (C, C)) We use a single marker to distinct the "split" case from the "divergence" case. If two independents operation rewrite the same changeset A in to A' and A'' when have an error case: divergent rewriting. We can detect it because two markers will be created independently: (A, (B,)) and (A, (C,)) Format ------ Markers are stored in an append-only file stored in '.hg/store/obsstore'. The file starts with a version header: - 1 unsigned byte: version number, starting at zero. The header is followed by the markers. Each marker is made of: - 1 unsigned byte: number of new changesets "R", could be zero. - 1 unsigned 32-bits integer: metadata size "M" in bytes. - 1 byte: a bit field. It is reserved for flags used in obsolete markers common operations, to avoid repeated decoding of metadata entries. - 20 bytes: obsoleted changeset identifier. - N*20 bytes: new changesets identifiers. - M bytes: metadata as a sequence of nul-terminated strings. Each string contains a key and a value, separated by a color ':', without additional encoding. Keys cannot contain '' or ':' and values cannot contain ''. iN(t_iis>BIB20st20sic cs`d}td|||d!d}|d7}|tkrVtjtd|nt|}x|t|kr[|||t!}|t7}tt|\}}}}d} |rt|} |||| !}tt ||} || 7}n||||!} t| |kr=tjtd|t| fn||7}|| || fVqeWdS(s(Read and enumerate markers from raw datais>Bis+parsing obsolete marker: unknown version %rsIparsing obsolete marker: metadata is too short, %d bytes expected, got %dN(( t_unpackt _fmversiontutiltAbortRtlent_fmfsizet_fmfixedt _fnodesizet_fmnode( tdatatofft diskversiontltcurtnbsuctmdsizetflagstpretsucststmetadata((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt _readmarkerss.        cCsx\|jD]N\}}d|ks1d|kr@tdnd|kr tdq q Wdjgt|D]}d|||f^qrS(smReturn encoded metadata string to string mapping. Assume no ':' in key and no '' in both key and value.t:ts*':' and '' are forbidden in metadata key's$':' are forbidden in metadata value's%s:%s(t iteritemst ValueErrortjointsorted(tmetatkeytvaluetk((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt encodemetas  cCsLi}x?|jdD].}|r|jd\}}||| set(markers on precursors edges of x) - successors[x] -> set(markers on successors edges of x) cCs\i|_g|_i|_i|_||_|jd}|rX|jt|ndS(NR8(tcachest_allt precursorst successorstsopenerttryreadt_loadR(R+R=R ((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyR-s     cCs t|jS(N(titerR:(R+((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt__iter__scCs t|jS(N(tboolR:(R+((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt __nonzero__sicCs|dkri}nd|kr8dtj|dB(t_packRt_encodeonemarker(RWt addheaderR&((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyRS5s cCsb|\}}}}t|}tt|}|t|||g}|j|t|||S(N(RRR textendRe(R&RRRRRtformatR ((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyRf>s   ic Cs|js iSi}g}td}xl|jD]a}t|}t||tkrqg}d}|j|n|j||t|7}q-WxVtt|D]B\}}djtdt g|} t j | |d|Bsdump%i( R8t _maxpayloadRfRR^t enumeratetreversedRReRtbase85t b85encode( R,tkeysR4t currentlenR&tnextdatat currentparttidxtpartR ((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt listmarkersLs"    cCs|jds-|jjtd|dS|rQ|jjtd|dStj|}|j}zF|jd}z%|jj |||j dSWd|j XWd|j XdS(sPush markers over pushkeytdumpsunknown key: %risunexpected old valuespushkey: obsolete markersiN( t startswithtuitwarnRRnt b85decodetlockRHR8R]RUtrelease(R,RtoldRYR R|ttr((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt pushmarker`s   c Cstr|jrd|jdkrg}|jd}xCt|dtD]/}||}|j|jd|d|qLWg|D]}|s|^qrtd}|jj |qndS(sputility function to push bookmark to a remote Exist mostly to allow overridding for experimentation purposetobsoletet namespacestreverseRjs&failed to push some obsolete markers! N( ROR8tlistkeysRtTrueR^tpushkeyRRyRz(R,tremotetrsltst remotedataRR trtmsg((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytsyncpushus # cCsd}tr|jjd|jd}d|kr|}xRt|dtD]>}|jdrStj ||}|j j ||qSqSW|j qn|S(sMutility function to pull bookmark to a remote The `gettransaction` is function that return the pull transaction, creating one if necessary. We return the transaction to inform the calling code that a new transaction have been created (when applicable). Exists mostly to allow overridding for experimentation purposes!fetching remote obsolete markers Rtdump0RRwN( R)RORytdebugRRRRxRnR{R8R]tinvalidatevolatilesets(R,RtgettransactionRt remoteobsRR ((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytsyncpulls  ccs&x|jD]}t||Vq WdS(s*all obsolete markers known in a repositoryN(R8R&(R,t markerdata((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt allmarkerssccsAx:|jjjj|jdD]}t|j|Vq"WdS(s6obsolete marker marking this changeset as a successorsN((R'R8R;tgetRaR&(tctxR ((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytprecursormarkerss(ccsAx:|jjjj|jdD]}t|j|Vq"WdS(s.obsolete marker making this changeset obsoleteN((R'R8R<RRaR&(RR ((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytsuccessormarkerss(ccst|}t|}x|r|j}|Vxo|jj|dD]X}|d|@rbqHnx;|dD]/}||krm|j||j|qmqmWqHWqWdS(sYield node for every successor of . Some successors may be unknown locally. This is a linear yield unsuited to detecting split changesets.iiN((R`tpopR<RRG(R8tnodest ignoreflagst remainingtseentcurrentRcRd((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt allsuccessorss      cs|j}t|jd|}|jr|jjd}xt||krt|}td|D}g|D]}|jr}|j^q}}|jt |j|fd|D}t|jd|}qBWntd|DS(sSreturn all nodes in the "foreground" of other node The foreground of a revision is anything reachable using parent -> children or precursor -> sucessor relation. It is very similars to "descendant" but augmented with obsolescence information. Beware that possible obsolescence cycle may result if complexe situation. s%ln::icss|]}|jVqdS(N(Ra(t.0tc((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pys sc3s!|]}|kr|VqdS(N((Rtn(tnm(s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pys scss|]}|jVqdS(N(Ra(RR((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pys s( t unfilteredR`R8t changelogtnodemapRtmutableRatupdateR(R,Rt foregroundtplenRJRRtknown((Rs6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyRs    +cCs|jj}|g}t|}|dkr6i}nxC|r{|d}||krk|j|jq9||kr||kr|fg||sRcSst|dS(Ni(R(tx((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytsRN(R8R<R`R)tremoveRRR^RGtlistRhRtissubsetR(R,t initialnodetcachet succmarkerst toproceedt stackedsetRRcRdt succssetstmarksst productresulttprefixtsuffixtnewssRuRtfinalt candidatet setversiont listversiontseenset((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytsuccessorssetssd           !              ccsD|jjj}x.|D]&}||}|dk r|VqqWdS(sgyield revision numbers of known nodes passed in parameters Unknown revisions are silently ignored.N(RRRR)(R,RttorevRtrev((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt _knownrevss    csfd}|S(sADecorator to register a function as computing the cache for a setcs tkst|t<|S(N(t cachefuncstAssertionError(tfunc(tname(s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt decorators ((RR((Rs6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytcacheforscCsV|j}|jsdS||jjkrHt|||jj| set Such access may compute the set and cache it for future use((RR8R9R(R,R((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytgetrevss   cCs&d|jkr"|jjjndS(sRemove all obsolescence related cache from a repo This remove all cache in obsstore is the obsstore already exist on the repo. (We could be smarter here given the exact event that trigger the cache clearing)R8N(t _filecacheR8R9RV(R,((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytclearobscachess RcCsvt}|jjj}|jj}xK|jjD]=}||}|dk r1|||r1|j |q1q1W|S(sthe set of obsolete revisionsN( R`RRRt _phasecachetphaseR8R<R)RG(R,tobstgetrevtgetphaseRaR((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt_computeobsoletesets   tunstablecsHt|dstS|j}tfd|jDS(s7the set of non obsolete revisions with obsolete parentsRc3s!|]}|kr|VqdS(N((RR(R(s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pys s(RR`Rt descendants(R,tcl((Rs6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt_computeunstablesets  t suspendedcs>|jjt|dtfdt|dDS(s9the set of obsolete parents with non obsolete descendantsRc3s!|]}|kr|VqdS(N((RR(R(s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pys sR(Rt ancestorsRR`(R,((Rs6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt_computesuspendedsetstextinctcCst|dt|dS(s<the set of obsolete parents without non obsolete descendantsRR(R(R,((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt_computeextinctsetstbumpedcsh|jjfd|jdD}t|j|dt}d}t|j|t||S(s3the set of revs trying to obsolete public revisionsc3s|]}|VqdS(N((RR(ttonode(s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pys sspublic()Rs%ld - obsolete() - public()(RRatrevsRR8t bumpedfixR`R(R,t publicnodesR<tquery((Rs6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt_computebumpedsets   t divergentc Cst}|j}i}x|jdD]}|jj|jd}t|}x|r|jd}||krt|||ng||D]}|r|^q} t| dkr|j|j Pn|j |jj|dqXWq(W|S(sMthe set of rev that compete to be the final successors of some revision. s(not public()) - obsolete()ii((( R`R8R;RRaRRRRGRR( R,RR8tnewermapRRct toprocessRIRtnewer((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt_computedivergentsets      #$c Cs/|dkri}nd|kr8dtj|d must be an iterable of (, (, ...)) tuple. `old` and `news` are changectx. Trying to obsolete a public changeset will raise an exception. Current user and date are used except if specified otherwise in the metadata attribute. This function operates within a transaction of its own, but does not take any lock on the repo. R0s%i %itusersadd-obsolescence-markers'cannot obsolete immutable changeset: %scss|]}|jVqdS(N(Ra(RR((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pys ,ss#changeset %s cannot obsolete itselfN(R)RRDRytusernameRHRRRaRFR8RMtfilteredrevcacheRVRUR}( R,t relationsRKRRRIRtnprectnsucs((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pyt createmarkerss(         (5R7tstructRRnRati18nRtpackRetunpackRRQtFalseRORRR tcalcsizeRR RRR"R%tobjectR&R8RSRfRkRvRRRRRRRRR)RRRRRRRRRRRRR(((s6/sys/lib/python2.7/site-packages/mercurial/obsolete.pytTsV $    ! [