\x89\x50\x4E\x47\x0D\x0A\x1A\x0A PNG  \x89\x50\x4E\x47\x0D\x0A\x1A\x0A  13\c@@s'dZddlmZddlZddlZddlmZddlmZm Z m Z m Z m Z ddl mZmZmZmZmZejdZd Zd Zed \ZZZeeBZeZeedZedZege eZ!d d dge!d *de!e Logilab SA Augie Fackler This software may be used and distributed according to the terms of the GNU General Public License version 2 or any later version. --- This module implements most phase logic in mercurial. Basic Concept ============= A 'changeset phase' is an indicator that tells us how a changeset is manipulated and communicated. The details of each phase is described below, here we describe the properties they have in common. Like bookmarks, phases are not stored in history and thus are not permanent and leave no audit trail. First, no changeset can be in two phases at once. Phases are ordered, so they can be considered from lowest to highest. The default, lowest phase is 'public' - this is the normal phase of existing changesets. A child changeset can not be in a lower phase than its parents. These phases share a hierarchy of traits: immutable shared public: X X draft: X secret: Local commits are draft by default. Phase Movement and Exchange =========================== Phase data is exchanged by pushkey on pull and push. Some servers have a publish option set, we call such a server a "publishing server". Pushing a draft changeset to a publishing server changes the phase to public. A small list of fact/rules define the exchange of phase: * old client never changes server states * pull never changes server states * publish and old server changesets are seen as public by client * any secret changeset seen in another repository is lowered to at least draft Here is the final table summing up the 49 possible use cases of phase exchange: server old publish non-publish N X N D P N D P old client pull N - X/X - X/D X/P - X/D X/P X - X/X - X/D X/P - X/D X/P push X X/X X/X X/P X/P X/P X/D X/D X/P new client pull N - P/X - P/D P/P - D/D P/P D - P/X - P/D P/P - D/D P/P P - P/X - P/D P/P - P/D P/P push D P/X P/X P/P P/P P/P D/D D/D P/P P P/X P/X P/P P/P P/P P/P P/P P/P Legend: A/B = final state on client / state on server * N = new/not present, * P = public, * D = draft, * X = not tracked (i.e., the old client or server has no internal way of recording the phase.) passive = only pushes A cell here can be read like this: "When a new client pushes a draft changeset (D) to a publishing server where it's not present (N), it's marked public on both sides (P/P)." Note: old client behave as a publishing server with draft only content - other people see it as public - content is pushed as draft i(tabsolute_importNi(t_(tbinthextnullidtnullrevtshort(terrortpycompattsmartsetttxnutiltutils>i20si@i itpublictdrafttsecrettarchivedtinternalicc@s|]}|t@r|VqdS(N(t HIDEABLE_FLAG(t.0tp((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pys scC@s d|jkS(s6True if the internal phase can be used on a repositorysinternal-phase(t requirements(trepo((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytsupportinternalsc C@s |j}t}gtD]}t^q}ywtj|j|jd\}}zDx=|D]5}|j\}} |t |j t | q\WWd|j XWnZt k r} | jtjkrn|rx |D]}|||}qWnt}nX||fS(sRead phase roots from disk phasedefaults is a list of fn(repo, roots) callable, which are executed if the phase roots file does not exist. When phases are being initialized on an existing repository, this could be used to set selected changesets phase to something else than public. Return (roots, dirty) where dirty is true if roots differ from what is being stored. t phaserootsN(t unfilteredtFalset allphasestsetR t trypendingtroottsvfstsplittinttaddRtclosetIOErrorterrnotENOENTtTrue( Rt phasedefaultstdirtytitrootstftpendingtlinetphasetnhtinst((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt _readrootss$ ! %  cC@sZg}xDt|D]6\}}x'|D]}|jtj||q&WqWdj|S(sencode a 'phase -> nodes' mapping into a binary stream Since phases are integer the mapping is actually a python list: [[PUBLIC_HEADS], [DRAFTS_HEADS], [SECRET_HEADS]] t(t enumeratetappendt _fphasesentrytpacktjoin(t phasemappingt binarydataR.tnodesthead((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt binaryencodes  !cC@sgtD] }g^q}tj}xstr|j|}t||krn|rjtjtdnPntj |\}}||j |q%W|S(s{decode a binary stream into a 'phase -> nodes' mapping Since phases are integer the mapping is actually a python list.sbad phase-heads stream( RR5tsizeR&treadtlenRtAbortRtunpackR4(tstreamR)t headsbyphaset entrysizetentryR.tnode((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt binarydecodes  cC@sL|dkrdS|j|}|dk r8|d}n||f|| dictionnary If data is None, nothing happens. Ni(tNonetget(tdatatrevtoldtnewtexisting((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt_trackphasechanges    t phasecachecB@seZedZddZdZdZdZdZ dZ dZ dZ d Z d Zd Zd Zdd ZdZdZdZRS(cC@sS|rOt||\|_|_d|_d|_|j||j|_ndS(Ni( R1RR(t_loadedrevslenRHt _phasesetst filterunknownRtopener(tselfRR't_load((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt__init__s    c@s|j|t|}t|krt|dkrP|\}|j|n)tjg|D]}|j|^q]|jjr|jjn|dkrt j S|t j @Sntt j |}|st j |St|dkr|\}|j|n)tjg|D]}|j|^q%|dkr_t j |}nsi|S|jfdSdS(s&return a smartset for the given phasesic@s |kS(N((tr(trevs(s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytsN(t loadphaserevsRR R?RRtuniont changelogt filteredrevsRHR tbasesetRt differencet fullreposettfilter(RURtphasestsubsetR((RYs6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt getrevsets0    )     ) cC@sY|jdddt}|j|_|j|_|j|_|j|_|j|_|S(NRV(t __class__RHRRR(RTRQRR(RUtph((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytcopys     cC@s.x'dD]}t||t||qWdS(s4replace all values in 'self' with content of phcacheRR(RTRQRRN(RR(RTRQRR(tsetattrtgetattr(RUtphcacheta((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytreplaces cC@sY|j}g}x4tD],}|jtj|jj|j|qW|jj|S(N( Rt trackedphasesR4RtmaplistR]RKRt computephases(RURt nativerootsR.((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt_getphaserevsnatives   cC@s|j}|j}gtD]}t^q|_t}xttD]}tj|j |j |}|rJt|j |}x|D]}|j |qW|j ||j|||j|ssroots((%ln::) - %ld)iN(RHRRIRRRtxrangeR?RR.RKRRYRvRORtextendRR(RURRRR:tdryrunRRtdelrootsR.RtoldstaffectedRXR*((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytadvanceboundaryss:    # .       cC@s-|j|d }|dkr&d}n|jjd}|j}|j||||r|dk r|j|}||}t|jd||} xtj |ddD]h} | r|| } t|jd| | } | | 8} n| } x!| D]} t || | |qWqWn|j dS(NiRcs(%ln::) - (%ln::)is%ln::%ld( RRHRRIRRRRYRRROR(RURRRR:toldrootsRRMRLRR.R*RYRX((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytretractboundarys&         c@s|ttfkrEt rEt|}d|}tj|nj|j|}t|}} g|D].} |j | j |kru| ^qu} | rt | krtj t dn|j}|j| tfd| Dg|D]"} | j kr| ^q} jd| } tfd|D}|jd| Dn|| kr|j|||tStS(Ns-this repository does not support the %s phases!cannot change null revision phasec3@s|]}|jVqdS(N(RK(RR(R(s6/usr/lib64/python2.7/site-packages/mercurial/phases.pys ss roots(%ln::)c3@s+|]!}|jkr|VqdS(N(RK(RR(t minnewrootR(s6/usr/lib64/python2.7/site-packages/mercurial/phases.pys scs@s|]}|jVqdS(N(RF(RR((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pys s(RRRt phasenamesRtProgrammingErrorRRRR.RKRR@RRhRvtminRR&R(RURRRR:tnametmsgt currentrootst finalrootsRRRt aboverootst updatedroots((RRs6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRs0     .    " c@st}|jjxt|jD]u\}}tfd|D}|r"x.|D]&}|jjdt||fqWW|j |t }q"q"W|rt |_ n|j dS(sremove unknown nodes from the phase boundary Nothing is lost as unknown nodes only hold data for their descendants. c3@s!|]}|kr|VqdS(N((RRF(tnodemap(s6/usr/lib64/python2.7/site-packages/mercurial/phases.pys ss0removing unknown node %s from %i-phase boundary N( RR]RR3RRtuitdebugRtsymmetric_difference_updateR&R(R}(RURtfilteredR.R:tmissingtmnode((Rs6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRSs      N(t__name__t __module__R&RWRHReRhRmRrRzR[R}R.RRRRRRRRS(((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRPs" !        2  #cC@sJ|jj}|j||||d|}|sF|jj|n|S(suAdd nodes to a phase changing other nodes phases if necessary. This function move boundary *forward* this means that all nodes are set in the target phase or kept in a *lower* phase. Simplify boundary to contains phase roots only. If dryrun is True, no actions will be performed Returns a set of revs whose phase is changed or should be changed R(t _phasecacheRhRRm(RRRR:RRkR((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRs  cC@s9|jj}|j|||||jj|dS(sSet nodes back to a phase changing other nodes phases if necessary. This function move boundary *backward* this means that all nodes are set in the target phase or kept in a *higher* phase. Simplify boundary to contains phase roots only.N(RRhRRm(RRRR:Rk((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRscC@s9|jj}|j|||||jj|dS(sregister a new revision and its phase Code adding revisions to the repository should use this function to set new changeset in their target phase (or higher). N(RRhRRm(RRRR:Rk((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRscC@stj}dt}|jj}xO|jjtD]=}|jj||j|tkr6||t | => phase} mapping. key and value are string. Accept unknown element input Rs2ignoring inconsistent public root from remote: %s s,ignoring unexpected root from remote: %i %s (RR]Rt iteritemsRR R RRtwarnRR R4tnewheads( RRdR*t draftrootsRRR.RFt publicheads((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytanalyzeremotephasests&         tremotephasessummarycB@seZdZdZRS(ssummarize phase information on the remote side :publishing: True is the remote is publishing :publicheads: list of remote public phase heads (nodes) :draftheads: list of remote draft phase heads (nodes) :draftroots: list of remote draft phase root (nodes) cC@s|j}||_|jdt|_t|||}|\|_|_|jd|j|}g|D]}|j ^qm|_ dS(NRsheads(%ln::%ln)( Rt_allremoterootsRIRRRRRRRFt draftheads(RURt remotesubsett remoterootstunfitanatdheadsR((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRWs  (RRt__doc__RW(((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRsc @s:ddlm}|j}|j}|jj|s;|S| sQ|tgkrUgStfd|D}g|D]}|^qx}|jd||}|j ||jd||}||8}|s|r!|j ||jd|} |j ||| } |j | nt j |jt|S(scompute new head of a subset minus another * `heads`: define the first subset * `roots`: define the second we subtract from the firsti(tdagopc3@s'|]}|tkr|VqdS(N(R(RR(RK(s6/usr/lib64/python2.7/site-packages/mercurial/phases.pys ss (%ld::%ld)s-parents(%ld + (%ld and merge())) and not nullsparents(%ld) and not null(R2RRR]RRIRRRYRuRvtreachablerootsRRoRFR( RRR*RRwt new_headsRt affected_zonet candidatest prunestarttpruned((RKs6/usr/lib64/python2.7/site-packages/mercurial/phases.pyRs*         cC@s||jdd}ytj|SWnRtk rwyt|SWqxtk rstd}tj||qxXnXdS(suhelper to get the target phase of new commit Handle all possible values for the phases.new-commit options. Rcs new-commits0phases.new-commit: not a valid phase name ('%s')N(tconfigRtindexR~R RRt ConfigError(RtvR((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytnewcommitphases   cC@st|jjdS(s@utility function that check if a repo have any secret changeset.i(tboolRR(R((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pyt hassecretscC@s<|dkrd}n t|}i|d6|d6t|d6S(NR2RFRR.(RHR(RFRLRM((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytpreparehookargss     (:Rt __future__RR$tstructti18nRRFRRRRRR2RRR R R tStructR5t INTERNAL_FLAGRtrangeR R RRRRRnRHR?Rttuplet mutablephasestremotehiddenphasestlocalhiddenphasesRR1R<RGROtobjectRPRRRRRRRRRRRRR(((s6/usr/lib64/python2.7/site-packages/mercurial/phases.pytesR  ((        $      %