o ]Lb/{@sTddlmZddlZddlZddlZddlmZddlmZm Z m Z ddl m Z m Z mZddlmZmZmZmZmZmZmZddlmZmZdd lmZmZej d d Z!d&d dZ"ddZ#ddZ$e ej%Z&d'ddZ'ddZ(ddZ)e)ej*Z+Gddde,Z-e-Z*Gddde,Z.ddZ/Gd d!d!e,Z0ej1e*dfd"d#Z2d(d$d%Z3dS)))absolute_importN)_)getattropensetattr)binhexshort)errorlineloglockmdiffpycompatscmutilutil)hashutil stringutil)r revmapcCs ||SN)file)repopathr=s z_parents.._filelog) _changeidparents__dict__r_reporr")r followplrrrr_parents3s r)csD}|d}|r|ds|d7}fddt|D|fS)N rcsg|]}|fqSrr)rifctxrrr!Osz_decorate..)datacountendswithrxrange)r-text linecountrr,r _decorateJs  r4cCs>|D]\\}}}}}|dkr|d|||d||<q|S)N=rr)parentchildblocksa1a2b1b2trrr_pairUs r>FcCs|rt|ts|durt||}n||}|dur0|dur%||}|S|j||d}|S||}|dkr=|}n|}||krO||_|||_|S)a2(repo, str, str) -> fctx get the filectx object from repo, rev, path, in an efficient way. if resolverev is True, "rev" is a revision specified by the revset language, otherwise "rev" is a nodeid, or a revision number that can be consumed by repo.__getitem__. if adjustctx is not None, the returned fctx will point to a changeset that introduces the change (last modified the file). if adjustctx is 'linkrev', trust the linkrev and do not adjust it. this is noticeably faster for big repos but is incorrect for some cases. N)changeidlinkrev) isinstanceint _revsinglerevfilectxlinkrevintrorevr# _changectx)rrDr resolverev adjustctxctxr-rGrrr resolvefctxcs"       rLcCs$|ddddddddS) Ns.hg/s.hg.hg/s.l/s.l.hg/s.m/s.m.hg/s.lock/s .lock.hg/)replacerrrr encodedirs rNcs:ttfddtjjD}tt| ddS)Nc3s|] }|t|fVqdSr)r)rkdiffoptsrr szhashdiffopts..) rpprintsortedr rQdefaultsrrsha1digest)rQ diffoptstrrrPr hashdiffoptssrZc@s2eZdZdZddddZddZejddZdS) annotateoptszlike mercurial.mdiff.diffopts, but is for annotate followrename: follow renames, like "hg annotate -f" followmerge: follow p2 of a merge changeset, otherwise p2 is ignored NT)sdiffoptss followrenames followmergecKs8t|}t|jD]\}}t|||||q dSr)r byteskwargs iteritemsrVrget)selfoptsrOvrrr__init__s zannotateopts.__init__cCsbd}|js |d7}|js|d7}|jdur-t|jtjsJt|j}|tkr-|d|7}|p0dS)z?represent opts in a short string, suitable for a directory namesr0sm0Nisdefault) followrename followmergerQrAr rZ_defaultdiffopthash)r_result diffopthashrrrshortstrs   zannotateopts.shortstr) __name__ __module__ __qualname____doc__rVrbr propertycacherjrrrrr[sr[c@seZdZdZddZeddZeddZdd ZeZ d d Z ed d Z d/ddZ d0ddZ ddZd1ddZddZddZddZd2dd Zd!d"Zed2d#d$Zd2d%d&Zd'd(Zejd)d*Zejd+d,Zd2d-d.ZdS)3_annotatecontextz{do not use this class directly as it does not use lock to protect writes. use "with annotatecontext(...)" instead. cCs<||_|j|_||_||_||_||_d|_d|_i|_dSr) ruirr` linelogpath revmappath_linelog_revmap _node2path)r_rrrrrsr`rrrrbs z_annotatecontext.__init__c Cs|jdurPtj|jrKt|jd.}z tj| |_Wntj y-t|_Yn wWd|jSWd|jS1sCwY|jSt|_|jS)Nsrb) rtosrexistsrrr linelogmodr fromdataread LineLogErrorr_r rrrr s$    z_annotatecontext.linelogcCs|jdur t|j|_|jSr)ru revmapmodrrsr_rrrrs z_annotatecontext.revmapcCsn|jdur |jd|_|jdur5t|jd}||jWdn1s+wYd|_dSdS)Nswb)ruflushrtrrrwriteencoder}rrrcloses    z_annotatecontext.closecCs&||jt|j|jgdS)z0delete linelog and revmap, useful for rebuildingN)rrvclear _unlinkpathsrsrrrrrrrebuilds z_annotatecontext.rebuildcCs&|jdur t|jS|j|jjS)z6return last node in revmap, or None if revmap is emptyN)rur~ getlastnodersrev2hshmaxrevrrrrlastnodes  z_annotatecontext.lastnodeTcCsh|j}z&|j|dd}|jj|}|s%|r%||kr%|j|duWS||kWSty3YdSw)areturn True if the revmap / linelog is up-to-date, or the file does not exist in the master revision. False otherwise. it tries to be fast and could return false negatives, because of the use of linkrev instead of introrev. useful for both server and client to decide whether to update fastannotate cache or not. if strict is True, even if fctx exists in the revmap, but is not the last node, isuptodate will return False. it's good for performance - no expensive check was done. if strict is False, if fctx exists in the revmap, this function may return True. this is useful for the client to skip downloading the cache if the client's master is behind the server's. T)rIN) r _resolvefctxr changelognoderFrhsh2rev LookupError)r_masterstrictrr linknoderrr isuptodates  z_annotatecontext.isuptodateNFc s6t|trtjj|}|\}}|r4jjr-j dj t t |df|||Sd}|rSz j|ddd}Wn tyKYnw|jvrSd}|g}|rn|duritjtdtdd|||dd} i} |d i} i} | r| } | | vs| | vrq|| jvrj| }j|jj}|| f| | <q|| }|| | <|D]}| |d d | |<|| vr| |q| s~t }|} | r| jvr|!| | | }|r|d } nd} n| r| jvs|dur"| jjr|rj d j t#|fn | sj d j jjj$|dd} jj%d t#|d}| r| d} | | vrI| q7d}| | }|D]}|| vr_d}| |qQ|sfq7| d}| |v}| | vswJt&| }t'|D]<\}}t()| |d |d }|d kr|r|}t*| |||}| |d kr| |=| |=q| |d 8<q|| | <| | =|r|+d}t#|dkr܈j,j-r|d }|durt()d|d }.| ||n |r| j/| <| s:|0fdd| |d D}1||||S)aincrementally update the cache so it includes revisions in the main branch till 'master'. and run annotate on 'rev', which may or may not be included in the main branch. if master is None, do not update linelog. the first value returned is the annotate result, it is [(node, linenum)] by default. [(node, linenum, path)] if showpath is True. if showlines is True, a second value will be returned, it is a list of corresponding line contents. s6fastannotate: %s: using fast path (resolved fctx: %s) snodeNTrIrJscannot update linelog to wdir()sset fastannotate.mainbranch)hintrrs7fastannotate: %s: %d new changesets in the main branch sBfastannotate: %s: linelog cannot help in annotating this revision sbuilding cache)totalFrccs2g|]\}}t|trj|n||fqSr)rArBrrr)rfrlrrrr!s z-_annotatecontext.annotate..)2rArBrrrrcanannotatedirectlyrq debugflagdebugrrrTr safehasattrannotatedirectlyrrrrDr Abortrappendpoprr annotateannotateresultr. _parentfuncr^setadd_checklastmasterheadlenr makeprogressr4 enumeratelist _diffblocksr> incrementr`rf _appendrevrvcomplete_refineannotateresult)r_rDrshowpath showlinesdirectlyrevfctx masterfctx initvisitvisitpcacheneededhistr llrevrhr(r newmainbranchprogressreadyr8 ismainbranchcurrr+bs bannotatedrrrr(s                     0  z_annotatecontext.annotatecCsd}d}t|ts*|dur*ttdt|dd|}|dur*||jf|jvr*|}|durO|jr3dnd}|j ||dd}||jv}|sO|jrO|j |ddd}||fS)z(str) -> bool, fctx or node. return (True, f) if we can annotate without updating the linelog, pass f to annotatedirectly. return (False, f) if we need extra calculation. f is the fctx resolved from rev. TN)(cSsdSrr)xrrrsz6_annotatecontext.canannotatedirectly..r@)rJrI) rArBbytesrr^rrr _perfhackr)r_rDrhr hshrJrrrrs  z$_annotatecontext.canannotatedirectlycsB|j|ddd}||jvrm|g}d} |d}||}|sn|d|jvr-|d}n||dqt} | |j| | j t |jt |D]}|} t | || } || || | }qSn|j} |j| } |} | fdd| D}|r||}|r||| }||f}|S)a (rev : str) -> [(node : str, linenum : int, path : str)] the result has the same format with annotate, but include all (including deleted) lines up to rev. call this after calling annotate(rev, ...) for better performance and accuracy. Trrcrrcs&g|]\}}|kr||fqSr)rrrrrrrrr!/s&z5_annotatecontext.annotatealllines..)rrrr.rryr copyfromrrr~reversedrr _doappendrev getalllinesrr_addpathtoresult _resolvelines)r_rDrrrchainar r(r br8linesrrh linecontentsrrrannotatealllinessJ         z!_annotatecontext.annotatealllinescsfdd|D}dgt|}tt}tt|D]}|||||df|q|r d}zt|D]\\} } } | t j @rHq9|| dd}Wn t y]|YSw|duri} t|D]D\\} } } | | vr|| dd}|j j r|j dt|| | f||| }t|}|| | <| D] }| | | ||<qqitdd|DsJ|S|j d t||| ||| }|j}t|}t|t|krtd t|D]\}}||}||vr ||D]}|||<q||=q|s1|S) ah(annotateresult) -> [line]. designed for annotatealllines. this is probably the most inefficient code in the whole fastannotate directory. but we have made a decision that the linelog does not store line contents. so getting them requires random accesses to the revlog data, since they can be many, it can be very slow. csg|] }|dqS)r)r)rrrrrr!Asz2_annotatecontext._resolvelines..Nrrs6fastannotate: reading %s line #%d to resolve lines %r css|]}|duVqdSrr)rrrrrrRdsz1_annotatecontext._resolvelines..s+fastannotate: annotate %s to resolve lines sunexpected annotated lines)r collections defaultdictrrr1rr]rev2flagr~sidebranchflag StopIterationrqrrr rrev2pathr splitnewlinesr.allrrfaerrorCorruptedFileErrorr)r_rrr revsrhkey2idxsr+rrD_linenumidxsrevlineslinenumr-ridx annotatedlinerOrrrr9sl          1z_annotatecontext._resolvelinescst|tr|}n|}j|}|stdt|j|t j @dkr1tdt|j |fddj j D}||||S)alike annotate, but when we know that f is in linelog. f can be either a 20-char str (node) or a fctx. this is for perf - in the best case, the user provides a node and we don't need to read the filelog or construct any filecontext. s%s is not in revmaprs%s is not in revmap mainbranchcs g|] \}}j||fqSr)rrrrrrr!sz5_annotatecontext.annotatedirectly..)rArrrrrrrrr~rr rrr)r_r rrrrrhrrrrzs     z!_annotatecontext.annotatedirectlycCst|r||}|r8t|tr|j|}|||j|}n|}t| }t |t |kr4t ||f}|S)znadd the missing path or line contents, they can be expensive. f could be either node or fctx. ) rrArrrrrr rr.rrr)r_rhr rrrr-rrrrrs   z&_annotatecontext._refineannotateresultcCs||j|j|||dSr)rr r)r_r-r8rrrrrsz_annotatecontext._appendrevcCst|||jjSr)r allblocksr`rQ)r_rrrrrrsz_annotatecontext._diffblockscsfdd}g}i|dur*|D]\\}}} } } | dkr)|dd|| | D7}qt|}||vr7|||D]} || | <q9j||d} | |<t|D]0\\}}} } } | dkrbqU|durp|| ||| | qUfdd|| | D}|| |||qUdS) z'append a revision to linelog and revmapcsFt|tr td|}|}|dur!j|d|d}|S)z (fctx) -> intsf should not be an intNT) sidebranchr)rArBr ProgrammingErrorrrrr)r rrDrrrgetllrevs   z/_annotatecontext._doappendrev..getllrevNr5cSsg|] \}}t|ts|qSrrArB)rr rrrrr!s z1_annotatecontext._doappendrev..rcs*g|]\}}t|tr |n||fqSrrr) siderevmaprrr!s)rremoverrrr replacelinesreplacelines_vec)r rr-r8rrsiderevsr9r:r;r<opr rblinesr)rrrrs6      z_annotatecontext._doappendrevcs.durjfddfdd|DS)z6(revmap, [(node, linenum)]) -> [(node, linenum, path)]Ncs2j|}|dur|}|j|<|Sr)rvr^rr)nodeidr)rr_rr_getpaths  z3_annotatecontext._addpathtoresult.._getpathcsg|] \}}|||fqSrr)rnr)rrrr!sz5_annotatecontext._addpathtoresult..r)r_rrr)rrr_rrsz!_annotatecontext._addpathtoresultcCsB|durd}n|j|}|st|jj|krtdS)z:check if fctx is the master's head last time, raise if notNr)rrrrCannotReuseErrorr r)r_r-rrrrrs z%_annotatecontext._checklastmasterheadcs"|jj|jjfdd}|S)z-> (fctx) -> [fctx]cs t|d}s|dd}|S)N)r'r)r))r r(rfrerrr$s  z-_annotatecontext._parentfunc..parents)r`rerf)r_r$rrrrsz_annotatecontext._parentfunccCs|jddS)N fastannotatesperfhack)rq configboolrrrrrsz_annotatecontext._perfhackcKst|j||p|jfi|Sr)rLrr)r_rDrkwdsrrrrsz_annotatecontext._resolvefctxT)NFF)FFr)rkrlrmrnrbpropertyr rr__del__rrrrrrrrrrr staticmethodrrrrrorrrrrrrrps>      #C 8A   1  rpc Cs.|D]}zt|WqtyYqwdS)zsilent, best-effort unlinkN)runlinkOSError)pathsrrrrr s rc@sHeZdZdZefddZeddZeddZdd Z ed d Z d S) pathhelperz9helper for getting paths for lockfile, linelog and revmapcCs"tjd|jt||_||_dS)Nr)rwrjoinrjrN_vfspathr&)r_rrr`rrrrbs  zpathhelper.__init__cCstj|jj|jSr)rwrdirnamer&vfsr r rrrrr szpathhelper.dirnamecC|jj|jdS)Ns.lr&r r r rrrrrr!zpathhelper.linelogpathcCst|jj|jdS)Ns.lock)lockmodr r&r r rrrrr %szpathhelper.lockcCr)Ns.mrrrrrrs(rzpathhelper.revmappathN) rkrlrmrn defaultoptsrbrr rrr rsrrrrr s   r ccst|||}t|j|j}|j}d}zMz'|t|||||}|r*||VWdn1s7wYWnt yU|durL||j d|wW|dura| dSdS|durl| ww)a context needed to perform (fast) annotate on a file an annotatecontext of a single file consists of two structures: the linelog and the revmap. this function takes care of locking. only 1 process is allowed to write that file's linelog and revmap at a time. when something goes wrong, this function will assume the linelog and the revmap are in a bad state, and remove them from disk. use this function in the following way: with annotatecontext(...) as actx: actx. .... Ns+fastannotate: %s: cache broken and deleted ) r rmakedirsr rsrrr rpr Exceptionrqrr)rrr`rhelperrsrractxrrrannotatecontext-s4      rcCs:|j}|j}|jdddrd}t||d}t||||S)zdlike annotatecontext but get the context from a fctx. convenient when used in fctx.annotate rs forcefollowT)rQre)r&_pathrqrr[r)r-r'rQrrraoptsrrrfctxannotatecontextRs  rr)FN)TNF)4 __future__rr contextlibrwmercurial.i18nrmercurial.pycompatrrrmercurial.noderrr mercurialr r ryr rr rrrmercurial.utilsrrrrr~ lrucachefuncrr)r4r> revsinglerCrLrNrZrrgobjectr[rprr contextmanagerrrrrrrs@  $    - "F $