o ]Lbܣ @sdZddlmZddlZddlmZddlmZmZddl m Z m Z m Z m Z mZmZmZmZmZmZmZmZmZmZmZddlmZdZiZeeZiZeeZed d d d ed d dd ed ddd ddddZ ej!Z!Gddde"Z#Gddde"Z$ddZ%dd*d+Z/ed d,d-ded.fd/d0ded1fd2d3ded4fd5d6ded7fge j0e j1e j2ed8ej3d d9d:d;Z4dS)?a?apply working directory changes to changesets (EXPERIMENTAL) The absorb extension provides a command to use annotate information to amend modified chunks into the corresponding non-public changesets. :: [absorb] # only check 50 recent non-public changesets at most max-stack-size = 50 # whether to add noise to new commits to avoid obsolescence cycle add-noise = 1 # make `amend --correlated` a shortcut to the main command amend-flag = correlated [color] absorb.description = yellow absorb.node = blue bold absorb.path = bold )absolute_importN)_)hexshort)cmdutilcommandscontextcrecorderrorlinelogmdiffobsoletepatchphasespycompat registrar rewriteutilscmutilutil) stringutilsships-with-hg-coreabsorb add-noiseTdefaults amend-flagmax-stack-size2syellows blue boldsbold)absorb.description absorb.node absorb.pathc@s$eZdZdZdZdZdZddZdS)nulluizblank ui object doing nothingFTcCs dd}|S)Nc_sdSN)argskwdsr!r!./usr/lib/python3/dist-packages/hgext/absorb.pynullfunc_z$nullui.__getitem__..nullfuncr!)namer%r!r!r$ __getitem__^sznullui.__getitem__N)__name__ __module__ __qualname____doc__ debugflagverbosequietr(r!r!r!r$rWs  rc@s(eZdZdZddZddZddZdS) emptyfilecontextz.minimal filecontext representing an empty filecCs ||_dSr )_repo)selfrepor!r!r$__init__hs zemptyfilecontext.__init__cCdS)Nr!r2r!r!r$datakr&zemptyfilecontext.datacCs|jjSr )r1nullidr7r!r!r$nodenszemptyfilecontext.nodeN)r)r*r+r,r4r8r:r!r!r!r$r0es  r0cCs4t}g}|D]}||vr||||q|S)z@list -> list. remove duplicated items without changing the order)setaddappend)lstseenresultxr!r!r$uniqrs  rBcCsj|}g}|tjkr/|rt||krn|}t|dkrn|||d}|tjks ||S)a)(ctx, int?) -> [ctx]. get a linear stack of non-public changesets. changesets are sorted in topo order, oldest first. return at most limit items, if limit is a positive number. merges are considered as non-draft as well. i.e. every commit returned has and only has 1 parent. r)phaserpubliclenparentsr=reverse)headctxlimitctxr@rGr!r!r$ getdraftstack}s   rLc Cs|durt}|s J||dvrgifSg}i}|d}t|D]1}||vr-|}n(||}||||vr>d}n|||<|}|rT|}||vrT|}nq#|durn||vre|||n |t||t||fS)aP([ctx], str, set) -> [fctx], {ctx: fctx} stack is a list of contexts, from old to new. usually they are what "getdraftstack" returns. follows renames, but not copies. seenfctxs is a set of filecontexts that will be considered "immutable". they are usually what this function returned in earlier calls, useful to avoid issues that a file was "moved" to multiple places and was then modified differently, like: "a" was copied to "b", "a" was also copied to "c" and then "a" was deleted, then both "b" and "c" were "moved" from "a" and we enforce only one of them to be able to affect "a"'s content. return an empty list and an empty dict, if the specified path does not exist in stack[-1] (the top of the stack). otherwise, return a list of de-duplicated filecontexts, and the map to convert ctx in the stack to fctx, for possible mutable fctxs. the first item of the list would be outside the stack and should be considered immutable. the remaining items are within the stack. for example, given the following changelog and corresponding filelog revisions: changelog: 3----4----5----6----7 filelog: x 0----1----1----2 (x: no such file yet) - if stack = [5, 6, 7], returns ([0, 1, 2], {5: 1, 6: 1, 7: 2}) - if stack = [3, 4, 5], returns ([e, 0, 1], {4: 0, 5: 1}), where "e" is a dummy empty filecontext. - if stack = [2], returns ([], {}) - if stack = [7], returns ([1, 2], {7: 2}) - if stack = [6, 7], returns ([1, 2], {6: 1, 7: 2}), although {6: 1} can be removed, since 1 is immutable. Nr) r;p1reversedr= copysourcer0r3rHrB) stackpath seenfctxsfctxsfctxmappctxrKfctxcopyr!r!r$ getfilestacks>%     rYc@s eZdZdZddZddZdS) overlaystorezsread-only, hybrid store based on a dict and ctx. memworkingcopy: {path: content}, overrides file contents. cCs||_||_dSr )basectxmemworkingcopy)r2r[r\r!r!r$r4s zoverlaystore.__init__cCsX||jvrdS|j|}||jvr|j|}n|}||f}|}|||fS)z-comply with mercurial.patch.filestore.getfileNNN)r[r\r8islinkisexecrP)r2rRrWcontentmoderXr!r!r$getfiles     zoverlaystore.getfileN)r)r*r+r,r4rbr!r!r!r$rZs rZc Cs|dur|j|}|dur|}|dur|}|}|}t|  |}t ||}t j |||||||d|d S)zi({path: content}, ctx, (p1node, p2node)?, {}?) -> memctx memworkingcopy overrides file contents. N) r3rGtextfiles filectxfnuserdatebranchextra)r3 changelogrGr:ri descriptionrgrfr;rdunionrZrmemctx) r\rKrGridescrgrfrdstorer!r!r$overlaycontexts* rpc@seZdZdZdddZdddZddZd d Zd d Ze d dZ ddZ ddZ ddZ ddZd ddZddZddZdS)!filefixupstatea state needed to apply fixups to a single file internally, it keeps file contents of several revisions and a linelog. the linelog uses odd revision numbers for original contents (fctxs passed to __init__), and even revision numbers for fixups, like: linelog rev 1: self.fctxs[0] (from an immutable "public" changeset) linelog rev 2: fixups made to self.fctxs[0] linelog rev 3: self.fctxs[1] (a child of fctxs[0]) linelog rev 4: fixups made to self.fctxs[1] ... a typical use is like: 1. call diffwith, to calculate self.fixups 2. (optionally), present self.fixups to the user, or change it 3. call apply, to apply changes 4. read results from "finalcontents", or call getfinalcontent NcCs||_||_|p t|_|pi|_dd|D|_ttj |j|_ | |_ |jj r4||jks4Jddg|_g|_g|_g|_t|_dS)z([fctx], ui or None) -> None fctxs should be linear, and sorted by topo order - oldest first. fctxs[0] will be considered as "immutable" and will not be changed. cSsg|]}|qSr!)r8.0fr!r!r$ ;z+filefixupstate.__init__..rN)rTrRruioptscontentsrmaplistr splitnewlines contentlines _buildlinelogr r-_checkoutlinelog chunkstats targetlinesfixups finalcontentsr; ctxaffected)r2rTrRrwrxr!r!r$r4/s     zfilefixupstate.__init__c Cs|jd}|jd}|}t|}||_|j|jj|jj }t |t |ks,J|rA|dd|dddf}| || ||||D]0} | | |} |jdt| 7<|jdd7<|j| 7_|dury||||| | qIdS)acalculate fixups needed by examining the differences between self.fctxs[-1] and targetfctx, chunk by chunk. targetfctx is the target state we move towards. we may or may not be able to get there because not all modified chunks can be amended into a non-public fctx unambiguously. call this only once, before apply(). update self.fixups, self.chunkstats, and self.targetlines. rMrrCN)ryr|r8r r{rr annotatemaxrevannotateresultrFr=_alldiffchunks_analysediffchunkrboolr _showchanges) r2 targetfctxfmaalinesbblines annotated dummyendlinechunk newfixupsr!r!r$diffwithHs(    zfilefixupstate.diffwithc Cst|jD]<\}}}}}|j||}|jjr7t|ddd}|jtdt|j | ||t |f|j |||||q|jddrP||_dS||_dS)zapply self.fixups. update self.linelog, self.finalcontents. call this only once, before getfinalcontent(), after diffwith(). rCrs%s: chunk %d:%d -> %d lines edit_linesFN)rOrrrwr-maxwriterrrTr:rFr replacelinesrxget_checkoutlinelogwitheditsrr~)r2reva1a2b1b2ridxr!r!r$applykszfilefixupstate.applycCs|j|}|j|S)z@(fctx) -> str. get modified file content for a given filecontext)rTindexr)r2rWrr!r!r$getfinalcontents  zfilefixupstate.getfinalcontentcs4|\}}}}||}|s"r"|td|dh}fdd|D}tdd|D} g} t| dkrS|||ddrS| d} | dkrR| d} | | ||||fnB||||ks_||krt||D]/} | \} }| dkr||krzd}}n || |}|d}| d} | | | | d||fqe|| S)aanalyse a different chunk and return new fixups found return [] if no lines from the chunk can be safely applied. the chunk (or lines) cannot be safely applied, if, for example: - the modified (deleted) lines belong to a public changeset (self.fctxs[0]) - the chunk is a pure insertion and the adjacent lines (at most 2 lines) belong to different non-public changesets, or do not belong to any non-public changesets. - the chunk is modifying lines from different changesets. in this case, if the number of lines deleted equals to the number of lines added, assume it's a simple 1:1 map (could be wrong). otherwise, give up. - the chunk is modifying lines from a single non-public changeset, but other revisions touch the area as well. i.e. the lines are not continuous as seen from the linelog. rrCcs$g|]}|ddkr|qSrrCr!)rsirr!r$rusz4filefixupstate._analysediffchunk..cSsh|]\}}|qSr!r!)rsrlr!r!r$ rvz3filefixupstate._analysediffchunk..T)rlistrF _iscontinuousr=rxrange_optimizefixups)r2rrrrrrinvolvednearbylinenums involvedrevsrrfixuprevrlinenumnb1nb2r!rr$rs6       z filefixupstate._analysediffchunkccs6tj||||d}|D] \}}|dkrq |Vq dS)z5like mdiff.allblocks, but only care about differences)lines1lines2!N)r allblocks)rrrrblocksrbtyper!r!r$rs zfilefixupstate._alldiffchunksc Cst}dg}}tt|jD]6}|j||j|}}|dd}|||||}tt|D]\} } } } | || | | | q2||}}q|S)z~calculate the initial linelog based on self.content{,line}s. this is similar to running a partial "annotate". r6rrC) r rrrFryr|rrOrr) r2llogrrrrrllrevchunksrrrrr!r!r$r}s   zfilefixupstate._buildlinelogcCsVg}tt|jD]}|dd}|j|dt|j|jj }| |q |S)z1() -> [str]. check out file contents from linelogrCrr6) rrrFryr rjoinmap_getlinerr=)r2ryrrr`r!r!r$r~s   zfilefixupstate._checkoutlinelogc s"|j}td|jd}ddt|jD}t|D](\}\}}|tdd|dt||dt|| d dd f7}q|td dt|7}t d d |D]\}}|j |dd|jj D] |qmq[|D]|ddfdd|D|f7}qz|jj|ddd}|sttddgt|j}d} | t|d} t|D]Hdrq| d| ddkrttd| dd} tt| | dD]\}} | dkr|||d | 7<qq||krddg|_|S)z&() -> [str]. prompt all lines for editsZHG: editing %s HG: "y" means the line to the right exists in the changeset to the top HG: rMcSs"g|] \}}t|ts||fqSr!) isinstancer0)rsrrtr!r!r$rus z.sHG: %s/%s %s %s |-rC rsHG: %s cSstSr )r;r!r!r!r$sz:filefixupstate._checkoutlinelogwithedits..rs %s : %sr6cs$g|]\}}|vrdndqS)y r!)rsr_frlinesetr!r$rur)actionsempty editor textsHG:s : smalformed line: %sNr)r getalllinesrrTrR enumeraterFrr:rksplit defaultdictrrr<rrrweditr InputErrorr r{ startswithrbytestrr) r2alllines editortext visiblefctxsrjrt editedtextry leftpadposcolonpos linecontentchr!rr$rsn              z(filefixupstate._checkoutlinelogwitheditscCs,|\}}|d@r|j|d|S|j|S)z@((rev, linenum)) -> str. convert rev+line number to line contentrCr)r|r)r2lineinforrr!r!r$rs zfilefixupstate._getlineFcCsR||krdS|j}||}||t|}|||}t|||t|kS)a(a1, a2 : int) -> bool check if these lines are continuous. i.e. no other insertions or deletions (from other revisions) among these lines. closedinterval decides whether a2 should be included or not. i.e. is it [a1, a2), or [a1, a2] ? T)r getoffsetintrrF)r2rrclosedintervalroffset1offset2linesinbetweenr!r!r$r&s   zfilefixupstate._iscontinuousc sggdgfdd}t|D]J\}}|\}}}}} dd} dd} dd} || krS|| krS|| krS|t|dd|rS|dd<| dd<q|t|d<q|S)zx[(rev, a1, a2, b1, b2)] -> [(rev, a1, a2, b1, b2)]. merge adjacent fixups to make them less fragmented. )rMrMrMrMrMcs*dddkrtddSdS)NrrM)r=tupler! pcurrentchunkr@r!r$ pushchunk>sz1filefixupstate._optimizefixups..pushchunkrrrrC)rrrr) r2rrrrrrrrrlastrevlasta2lastb2r!rr$r7s&     zfilefixupstate._optimizefixupsc sRdd}|\}}} } dg||dg| | } } |D]3\} }}}}t||D]}t| ddd| ||<q(t||D]}t| ddd| || <q>qjddd|||| | | fd d jjdd fd d }t||D]}|| ||d|||ddq{t| | D]}|| || d|||ddqdS)NcSs|dr |dd}|S)NrrM)endswith)liner!r!r$trimWs  z)filefixupstate._showchanges..trimrrCrshunks %s s@@ -%d,%d +%d,%d @@s diff.hunklabelrRlinetypecs|d}|rj|}j|d|}j|jdd|ddjd|d|||djj |d dS) Nr6)rWnode%-7.7s rrs diffchar s%s%s r) startitemrTrrrr< changectxrr8rR)rdiffcharrr linelabelr:rKrr2r!r$ writelineos   z.filefixupstate._showchanges..writelinersdeleteds diff.deleted+sinserteds diff.inserted)rrrrrr8rR)r2rrrrrrrrrraidxsbidxsrfa1fa2fb1fb2rrr!rr$rVsF     zfilefixupstate._showchangesNNr )F)r)r*r+r,r4rrrr staticmethodrr}r~rrrrrr!r!r!r$rqs   #3  D  rqc@seZdZdZd#ddZd#ddZddZed d Zd d Z d dZ ddZ ddZ ddZ ddZddZed$ddZd$ddZejddZdd Zejd!d"ZdS)% fixupstatea^state needed to run absorb internally, it keeps paths and filefixupstates. a typical use is like filefixupstates: 1. call diffwith, to calculate fixups 2. (optionally), present fixups to the user, or edit fixups 3. call apply, to apply changes to memory 4. call commit, to commit changes to hg database NcCsf|sJ|pt|_|p i|_||_|d|_g|_d|_i|_i|_ i|_ d|_ t |_ dS)z([ctx], ui or None) -> None stack: should be linear, and sorted by topo order - oldest first. all commits in stack are considered mutable. rMN)rrwrxrQr3 unfilteredpathsstatusrUfixupmap replacemap finalnoder;r)r2rQrwrxr!r!r$r4s   zfixupstate.__init__c CsV|jd|||_g|_|jd}|jjs |r |r |}n|jj}t}t|D]}}|j d|||}t |j||\} } t dd|g| DrOq+| | d kr\|s\q+|| dd| |j|<t| ||j |jd} |dur||d |jd d |d d |j d d| ||| |j|<|j||j| jq+dS)z9diff and prepare fixups. update self.fixupmap, self.pathsrMrscalculating fixups for %s css0|]}t|ts|pt|VqdSr )rr0r^rbinaryr8rrr!r!r$ s z&fixupstate.diffwith..rCNrwrxsshowing changes for spath%s rrr)rQr r rxrmodifiedrdr;sortedrwdebugrYanyr8updaterUrqrplainrrr r=r) r2 targetctxmatchreditoptinterestingpathsrSrRrrTctx2fctxfstater!r!r$rs<         zfixupstate.diffwithcCs>t|jD]\}}|jjr|jtd||qdS)z*apply fixups to individual filefixupstatessapplying fixups to %s N)r iteritemsr rwr-rrr)r2rRstater!r!r$rs  zfixupstate.applycCsddt|jDS)z>-> {path: chunkstats}. collect chunkstats from filefixupstatescSsi|]\}}||jqSr!)r)rsrRr r!r!r$ z)fixupstate.chunkstats..)rrr r7r!r!r$rs zfixupstate.chunkstatscCsl|jd%}||||jd|jvr||Wd|jS1s.wY|jS)z6commit changes. update self.finalnode, self.replacemapr.N) r3 transaction _commitstack_movebookmarksr:r _moveworkingdirectoryparent_cleanupoldcommitsr )r2trr!r!r$commits   zfixupstate.commitcs|j}|j}|jr)t|D]\}}|dr&|td||d|dfqdS|jsH|fdddD\}}|td||fdSdS) z+print things like '1 of 2 chunk(s) applied'rs%s: %d of %d chunk(s) applied rCc3s&|]tfddDVqdS)c3s|]}|VqdSr r!rssrr!r$rz7fixupstate.printchunkstats...N)sum)rsstatsr-r$rs$z-fixupstate.printchunkstats..rs%d of %d chunk(s) applied N) rwrr.rrrrr/values)r2rwrrRstatappliedtotalr!r0r$printchunkstatss"zfixupstate.printchunkstatscCsd}d}|jD]y}||}|s|s|}q|o||||}|jr1|r1d|j|<td}n:|j|||d}|j |}|}||j|<|rb|rRtd}ntd}|t || |f}n td| |}|j j r|r|j td| ||fq|o||_dS)zmake new commits. update self.finalnode, self.replacemap. it is splitted from "commit" to avoid too much indentation. Nsbecame empty and was dropped)rNs&%d file(s) changed, became empty as %ss%d file(s) changed, became %ss became %ss%s: %s )rQ_getnewfilecontentsrd_willbecomenoopskip_empty_successorr r:r _commitsingler3rF_ctx2strrwr.rr )r2 lastcommittednextp1rKr\willbecomenoopmsgnodestrr!r!r$r% s<        zfixupstate._commitstackcCs4|jjrd||fSd|t|fS)Ns%d:%s)rwr-rrrr:)r2rKr!r!r$r;5szfixupstate._ctx2strcCs\i}|jD]&}|j|}||vrq||}|}|j||}||kr+|||<q|S)z(ctx) -> {path: str} fetch file contents from filefixupstates. return the working copy overrides - files different from ctx. )r rUr8r rrR)r2rKr@rRrrWr` newcontentr!r!r$r7;s   zfixupstate._getnewfilecontentscsj}fddt|jD}g}|D]5\}}|r4|||fjjr3jtd|t |fq||dfjjrIjtd|q|j |||dS)Ncs(g|]\}}|jvr|j|fqSr!)r )rsr'hshr7r!r$ruOs   z-fixupstate._movebookmarks..smoving bookmark %s to %s sdeleting bookmark %s ) r3rr _bookmarksr=rwr.rrr applychanges)r2r)r3 needupdatechangesr'rBr!r7r$r&Ms$   zfixupstate._movebookmarkscs|js|jd|j}|j|}||_n|j|j}|jjdd}|}t dr?j j fdd}|j _ z,  |||jWdn1s[wYW|dSW|dS|w)Nsmax(::. - %ln)cSr5)Nrr!r!r!r!r$rnz8fixupstate._moveworkingdirectoryparent.._fsmonitorstatecs j_dSr )rH invalidater!bakdirstater!r$restoress z7fixupstate._moveworkingdirectoryparent..restore)r r3revsr keysfirstr:rLr safehasattrrHrI parentchangerebuildmanifestr )r2rNrKnooprMr!rJr$r'bs&     z&fixupstate._moveworkingdirectoryparentcCs|s|}t|dkrdS|d}||krdS|dr%dSt|t|s2dSt |D]+\}}||vsC||vrFdS||}||}| | krYdS| |krbdSq7dS)z({path: content}, ctx, ctx) -> bool. test if a commit will be noop if it will become an empty commit (does not change anything, after the memworkingcopy overrides), return True. otherwise return False. rCFrscloseT) rGrFrhrirr;rdissubsetrrflagsr8)r\rKrVrGrRr`rWpfctxr!r!r$r8}s,  zfixupstate._willbecomenoopcCsx|o||jjf}|}|jr|jddr||d<t|| dd|j D}t |||||d}| S)z(ctx, {path: content}, node) -> node. make a single commit the commit is a clone from ctx, with a (optionally) different p1, and different file contents replaced by memworkingcopy. rrs absorb_sourcecSsi|]\}}||gqSr!r!)rsoldnodenewnoder!r!r$r!r"z,fixupstate._commitsingle..)rirn)r3r9ri _useobsoleterw configboolrrupdate_hash_refsrkr itemsrpr*)r2r\rKrNrGrirnmctxr!r!r$r:s  zfixupstate._commitsinglecCst|jtjS)z () -> bool)r isenabledr3createmarkersoptr7r!r!r$r[szfixupstate._useobsoletecCs6ddt|jD}|rtj|j|ddddSdS)NcSs$i|]\}}||dur|gngqSr r!)rskvr!r!r$r!rz1fixupstate._cleanupoldcommits..rT) operationfixphase)rrr r cleanupnodesr3)r2 replacementsr!r!r$r(s   zfixupstate._cleanupoldcommitscCst|jdS)Nr)rr9rwr7r!r!r$r9szfixupstate.skip_empty_successorrr )r)r*r+r,r4rrpropertyrr*r6r%r;r7r&r'rr8r:r propertycacher[r(r9r!r!r!r$rs, *  +    rcCst|tjtjfvr dS|j}|jt|j d}g|_ |_ t }| |t|}||j}dd|ddD}||||ffS)zA(crecord.uihunk or patch.recordhunk) -> (path, (a1, a2, [bline]))rrCcSs"g|] }|ds|ddqS)rrCN)r)rsrr!r!r$rus"z_parsechunk..N)typer uihunkr recordhunkheaderfilenamefromlinerFbeforeafterrstringiorr r{getvalueremoved)hunkrRrbuf patchlinesrrr!r!r$ _parsechunks    rxc Csi}tdd}tt|D]\}}|r|sq |||q t|D]/\}}||vs-|s.q#|jddt|| }|D] \}} } | ||| <q?d |||<q#t ||S)z(ctx, [crecord.uihunk]) -> memctx return a memctx with some [1] patches (chunks) applied to ctx. [1]: modifications are handled. renames, mode changes, etc. are ignored. cSsgSr r!r!r!r!r$rrGz$overlaydiffcontext..T)rHr6) rrrxr=rrsortr r{r8rrp) rKrr\patchmaprRinfopatcheslinesrrrr!r!r$overlaydiffcontexts    r~cCs^|dur3|dd}|d}t|dkrttdt||}|r3t||kr3|td||s.rNrC) r byteskwargswlocklockrcheckunfinishedrr/rr2)rwr3rrxr r!r!r$ absorbcmdGs > Prr r])NNNN)5r, __future__r collectionsmercurial.i18nrmercurial.noderr mercurialrrrr r r r r rrrrrrrmercurial.utilsr testedwithcmdtablecommand configtable configitem colortablerobjectrr0rBrLrY filestorerZrprqrrxr~r dryrunopts templateoptswalkoptsCATEGORY_COMMITTINGrr!r!r!r$s  D    R |6 O &