o ]LbB@s4dZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z mZddlmZddlmZddlmZddlmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z/m0Z0dd l1m2Z2m3Z3m4Z4d d l5m6Z6d Z7eZ8e8j9Z9e8j:Z:e8j;Z;e8je8j?d ddde8j?d ddde8j?d ddde8j?d ddde8j?d ddde8j?d ddde8j?d dd de8j?d ddde8j?dddde8j?dddde8j?dddddddd d!d"dd#d$d$d% Z@d&d'd&ed(fgZAe8Bed)d*d+ZCdd,d-ZDd.d/ZEd0d1ZFd2d3ZGd4d5ZHeDd6ged7d8d9d:d;ZIdZLe Kd?e jMZNd@dAZOdBdCZPdDdEZQGdFdGdGeRZSGdHdIdIeRZTejUGdJdKdKeVZWejUGdLdMdMeRZXejUGdNdOdOeRZYdPdQZZdRdSZ[dTdUZ\dVdWZ]dXdYZ^dZd[d\d]Z_d^d_Z`d`daZadbdcZbdddeZcdfdgZddhdiZe       ddjdkZfdldmZgdndoZhdpdqZieDddrdsgedtedufd&dvd8edwfd&dxgedyfd&dzged{fd|d}d&ed~fd&ddedfd&ddedfgede:jjdddZke0lgdZmddZnhdZoddZpdddddddddZqddZrddZsddZtddZuddZvddZwddZxddZyddZzddZ{ddZ|eDdd&ddedfgede:jjd8dddZ}eDdd&ddedfgede:jjdddZ~eDdd&ddedfd&ddedfd&ddedfd&ddedfd&ddedfd&ddedfd&ddedƒfd&ddedăfd&ddedƃfd&ddedȃfd|d}d&edɃfdrdsd&edʃedufg ed˃e:jjd8ddd̈́Ze8j  z_loadhgrc..Tsinvalid JSON in %s srepository.callsign)r&r+sphabricator.urir&r1)source)r unifromlocalreadrrapply json_loads ValueErrorwarnrjoinIOErrorr sortdict applyconfig) origuiwdirvfshgvfs requirementsargsoptsresult arcconfig rawparamscfgrBrBrC _loadhgrcs.    r]cs>|tddddddfdd}|S) NcSs|j|jks |j|jkrdStj|j}tj|j}|D]:}||vr'dS||d}|drM|drMt |}t ||d}||krLdSq||d|krXdSqdS)NFr{}T) urimethodr urlreqparseqsbody startswithendswithrrK)r1r2r1paramsr2paramskeyvaluer1jsonr2jsonrBrBrC hgmatchers$  zvcrcommand..hgmatchercSstdd|j|_|S)Ns cli-[a-z0-9]+scli-hahayouwish)resubrd)requestrBrBrCsanitiserequestsz#vcrcommand..sanitiserequestcSsd|dvr |dd=|S)Nz set-cookieheadersrB)responserBrBrCsanitiseresponses  z$vcrcommand..sanitiseresponsecsFfdd}tj|dd}j|_j|_td|S)Nc s|d}|rmt|}ddl}|Qddl}ddlm}|jdt d|j ft d|j fgd}| d|j |dgd|i|WdWdS1sYwYWdn1shwY|i|S) Ntest_vcrrjsonrhttpsconnection) serializerbefore_record_requestbefore_record_responsecustom_patchesro)match_on)poprfsdecodehgdemandimport deactivatedvcr vcr.stubsstubsVCRurlmodVCRHTTPConnectionVCRHTTPSConnectionregister_matcher use_cassette)rWkwargsrcassettervcrmodr)fnrorsrvrBrCinners:      z+vcrcommand..decorate..inner)depth helpcategory optionalrepo)r checksignature__name____doc__command)rrcmd fullflagsrronamerrsrvspec)rrCdecorates zvcrcommand..decorate) _VCR_FLAGS)rflagsrrrrrBrrC vcrcommands -rcOsB|ddr|j}zd|_|j|i|W||_dS||_wdS)zwrite debug output for Phabricator if ``phabricator.debug`` is set Specifically, this avoids dumping Conduit and HTTP auth chatter that is printed with the --debug argument. r&r-TN) configbool debugflagwrite)rSmsgrXflagrBrBrC_debugKs rcs,tfddd|tjS)alike urlencode, but works with nested parameters. For example, if params is {'a': ['b', 'c'], 'd': {'e': 'f'}}, it will be flattened to {'a[0]': 'b', 'a[1]': 'c', 'd[e]': 'f'} and then passed to urlencode. Note: the encoding is consistent with PHP's http_build_query. cst|tr ddd|}dd}t|tddit|}|dur'||<dS||D]\}}|r;d||f|q+||q+dS)Nstruesfalse)TFcSsddt|DS)NcSsg|] \}}d||fqS)%drB).0kvrBrBrC fzFurlencodenested..process....) enumerate)lrBrBrCrDfsz2urlencodenested..process..cSs|Sr;)itemsr@rBrBrCrDgs%s[%s])r=boollistdictgettype)prefixobjlisterrrr flatparamsprocessrBrCrcs   z urlencodenested..processr8)r rPr#rb urlencode)paramsrBrrCurlencodenestedZs  rcCs|dd}|sttddt||t|j}d}|r0|\}}| d|| d}|s.s error_codesConduit Error (%s): %ss error_infosresult),rr#rrNauthinforrbytereprcopyrrxrrr!popen2 shellquotercloserIropenerr rbrrstrurl configint configwithfloatrange contextlibclosingopenurlerrurlerrortimesleeprJrKr rHrrr r)rSrrhostrrrrawdatarcurlcmdsinsoutrd urlopenerrrmax_tryr try_countrsperrretry_intervalparsedrrBrBrC callconduitsp              rsdebugcallconduitsMETHODT)rcCsht|j}tddt|}tddt|||}tj |dddd}| dt |d S) zcall Conduit API Call parameters are read from stdin as a JSON blob. Result will be written to stdout as a JSON blob. cSr:r;r<r@rBrBrCrDrEz"debugcallconduit..cSst|tr t|S|Sr;)r=bytesr rHr@rBrBrCrDTr),z: ) sort_keysindent separatorss%s N) r rHfinrIrrJrKrrxdumpsrr?)rSreporr[rrYsrBrBrCdebugcallconduits rcCs||jdd}|r |S|jdd}|sdSt|jddd|gii}t|dd kr,dS|dd d }|jdd||S) z.given callsign, return repository PHID or Noner&r.r+Nsdiffusion.repository.search constraintss callsignsdatarphid)rSrrlen setconfig)rrepophidcallsignqueryrBrBrC getrepophids  rs\AD([1-9][0-9]*)\Zs>^Differential Revision:\s*(?P(?:.*)D(?P[1-9][0-9]*))$c s|}|jjj}i}t}|D]R}||}tt|j |g}|D](} || rK| | D]} t | } | rGdt |t| df||<nq.q#nq#t|} | rcdt |t| df||<q|rdd|D} t|jdd| i} dd |D]~\}\}fd d| D}fd d |D}|s|sd }tj|||jddddd|jtdqd}}|rt|ddd}|}t|jdt|t ddt!|Dft"|dkr|d}|r||sd}||f||<q|S)afind previous nodes that has been sent to Phabricator return {node: (oldnode, Differential diff, Differential Revision ID)} for node in nodelist with known previous sent versions, or associated Differential Revision IDs. ``oldnode`` and ``Differential diff`` could be ``None``. Examines commit messages like "Differential Revision:" to get the association information. If such commit message line is not found, examines all precursors and their tags. Tags with format like "D1234" are considered a match and the node with that tag, and the number after "D" (ex. 1234) will be returned. The ``old node``, if not None, is guaranteed to be the last diff of corresponding Differential Revision, and exist in the repo. rr$idcSsg|]\}}}|qSrBrB)rforceprecsdrevrBrBrCr4z%getoldnodedrevmap..differential.querydiffss revisionIDscsfddt|DS)Ncsg|]}|vr|qSrBrBrnprecsetrBrCr<rz7getoldnodedrevmap..getnodes..)getlocalcommits)dr rBr rCgetnodes9sz#getoldnodedrevmap..getnodesc g|] }t|dkr|qS)s revisionIDintrrrrBrCr?scs h|] }|D]}|q qSrBrB)rrr )rr rBrC D z$getoldnodedrevmap..D%dNTmessagerdatelocals=D%d: local tag removed - does not match Differential history cSs t|dS)Nidr)rrBrBrCrD`s z#getoldnodedrevmap..)rks%s mapped to old nodes %s cSg|]}t|qSrBrr rBrBrCrh)# unfiltered changelogindexhas_noder rPrrallpredecessorsobsstorenodetags_differentialrevisiontagrersetrr_differentialrevisiondescresearch descriptionvaluesrrSrrtagnullidrMrmaxrrr"pprintsortedr)rnodelistunfir$rY toconfirmnodectx precnodesr r.mdrevsalldiffsnewnoderdiffs phprecsettagnameoldnodelastdiffoldnodesrB)rrr rCgetoldnodedrevmaps         rCcCsi}|D]9}d||<||}t|}|r!t|d||<q||D]}t|}|rt|s>|s>t|rJt||t |||nt ||||| |qdS)z"add modified files to the phabdiff)rrN) rJrqrrr|rrrrrrr) rrLr7modifiedrrrrfilemode originalmoderBrBrC addmodifieds,        rcCsi}i}i}||krt||}|D]}||} d} t|d} t| } |r0|||} n |} | r<| d} || k}|r|| } t| }| | _| |vrmt| | t j |gd}||| <| | t j | _ n5| |vrt j|| _ || j|t j| _ n| |vrt| t jd}||| <n|| }|j|t j| _ | |kr| || | n | t| t j| _ | st| s| r| st| rt| | |rt| | | nt| ||||| q|D] \}}||q|D] \}}||qdS)z>add file adds to the phabdiff, both new files and copies/movesN)rr)rrrr)rr)r pathcopiesrJrqrrrrenamedrrRr^remover`rrbrrrar_r|rr[rrrrrrr)rrLr7addedr copiedchanges movedchangesrrrrrr originalfnamerr origpchange_path copiedchange movedchangerBrBrCaddaddeds                  rcCs|}t|}td|d|d}||\}}}}} } } t|||||t||||t |||||rA||_ t |j dt t|} | sh||kr]td||f} ntd|} t| | S)zcreate a Differential Diffs%s)rrsdifferential.creatediffscannot create diff for %s::%sscannot create diff for %s)rrrrJhexrstatusrrrrrrSrrrrrr r)rLr7rrrrrr_d_u_i_cdiffrrBrBrC creatediffs.   rc Cs|d|d}|d}|d}|dt|d||||dd}t| j d |i}|D](}t |t |t|d||g|d ||<q;|d t|d}t| j d |d S) zwrite metadata to diff so patches could be applied losslessly ``ctxs`` is the list of commits that created the diff, in ascending order. The list is generally a single commit, but may be several when using ``phabsend --fold``. sdiffidrrhg:metas%d %d)userdatebranchnodeparent)sdiff_idrrsdifferential.setdiffproperty)author authorEmailtimecommitparentsr local:commitsN)rrrxrrrrrJrrrSr"personemailr)ctxsrdiffidrLtipctxrcommitsr7rBrBrCwritediffproperties;s:       r c Cs|d}|d} |} |r.tjddd} | } | |} | |}t| || t|| | k}nd}g}|rNt| |}|d|dd|rM|d |dn|sRJ|}t|||rd|d |gd|rj||7}t }t |D]B\}}| }t | j d d |i}d D].}|d|}|sq|dkr|||<q|dkrd}dtd|||g||<qqr|D] \}}|||dqd|i}|dur||d<t | j d|}|st|dkrtd|}ntd| |f}t|||fS)acreate or update a Differential Revision If revid is None, create a new Differential Revision, otherwise update revid. If parentrevphid is not None, set it as a dependency. If there is a single commit for the new Differential Revision, ``ctxs`` will be a list of that single context. Otherwise, it is a list that covers the range of changes for the differential, where ``ctxs[0]`` is the first change to include and ``ctxs[-1]`` is the last. If oldnode is not None, check if the patch content (without commit message and metadata) has changed before creating another diff. For a Revision with a single commit, ``oldbasenode`` and ``oldnode`` have the same value. For a Revision covering multiple commits, ``oldbasenode`` corresponds to ``ctxs[0]`` the previous time this Revision was posted, and ``oldnode`` corresponds to ``ctxs[-1]``. If actions is not None, they will be appended to the transaction. rrTrrsupdaterstypesvaluecomments parents.setsdifferential.parsecommitmessagescorpus)titlesummarytestPlanfieldsrr N transactionsobjectIdentifierdifferential.revision.editr$scannot create revision for %ss!cannot create revision for %s::%s)rrrMr!rQrrr r rPrr,rrSrrstriprNfilterrrrr r)rrevid parentrevphid oldbasenoder@olddiffactionscommentr7rLrrMr4oldctx oldbasectx neednewdiff transactionsrfieldsi_ctxdescinforrrrevisionrrBrBrCcreatedifferentialrevisionhsr       $  r(cCsvdd|D}dd|ii}t|d|}|d}dd|D}t||}|r4ttd d t|d d|DS) zconvert user names to PHIDscSsg|]}|qSrBlower)rrrBrBrCrr zuserphids..rs usernamess user.searchrcSsh|] }|ddqS)rsusernamer)rentryrBrBrCrrzuserphids..sunknown username: %s cSsg|]}|dqS)rrBr+rBrBrCrr )rr)r rrrNr2)rSnamesrrYrresolved unresolvedrBrBrC userphidss   r1cCsb|tdtdtdd|d|}|d|d}t||d}|td |||fd S) zprint the ``action`` that occurred when posting ``ctx`` for review This is a utility function for the sending phase of ``phabsend``, which makes it easier to show a status for all local commits with `--fold``. createdskippedupdated)r2r3r4sphabricator.action.%srr7r2s %s - %s - %s N)labelrrformat_changeset_summaryr)rSr7newrevidaction actiondescdrevdescsummaryrBrBrC_print_phabsend_actionsr<cshtjdtdd|Dztfdd|D|WdStjjy3jd|YdSw)zupdate the local commit list for the ``diff`` associated with ``drevid`` This is a utility function for the amend phase of ``phabsend``, which converts failures to warning messages. snew commits: %s cSrrBrr rBrBrCr r z*_amend_diff_properties..cg|]}|qSrBrB)rr<r4rBrCrr s"Failed to update metadata for D%d N) rrSr"r1r r rr warnnoi18n)r4drevidnewnodesrrBr>rC_amend_diff_propertiessrBrrevsrevisions to sendsREVamendsupdate commit messagesreviewersspecify reviewersblockersspecify blocking reviewersmr s1add a comment to Revisions with new/updated Diffss#ask for confirmation before sendingfolds%combine the revisions into one reviews REV [OPTIONS])rc1 s$t|}t||dg}t|}||s"tt d|dr,t fdd|D}t dd|DrEtt dfd d } d |}t|d kr\||d  d|}t|d krm||d|d}|rt|d krtt d|dstt ddd|D} tdd| Dd krtt dtfdd|D} |dd} | t|dO} | rt|| } | stt dg} |dg}|dg}g}|r|tj||r|tddtj||r| d|d g}i}d!}|D]}|r%|d"||d#fn |d$|| |d%\}}}|||}}}|rQ| |d#d%\}}}||ks^|drt|rd|n|g|||||| |d&\}}|r|D] }|||<qyn|||<t|d'd(}|d'd)}|rd*}nd+}|st|} | rt| d,|krd-|}!t!j"|!|d!d!d!d.d/nt#jd0|d1d)}|}d2}|||}|r|D]}"| |"d%d3rd*}nd+}t$||"||qn t$||||q|dr%}#t&|d4d5|i}$'()dd6d*d7||D}%|#d8}&i}'g}(|d1t+|D]\})}*|#|*}+|s^||)fd9d|$Dd1},t,|,|+|}-|+|-ks|+-|'vs|+.|'vr|+/t0j1kr|2t d:t34|+qO|'|+-|+-fd1|'|+.|+.fd1g}.t56|-|'}-t7j8|+|.|-|+9|+:|+;d;}/|/<}0|0g|'|+<|r|(|0qOt=|#|0g||+d-}!|!!vrt!j"|!j>d!d!d!d.d/qO|r|(|+qO|rK|(rK||+}|r4t*|(t?|krCt@|d<t=|#|(|nt@|d=n|rSt@|d>|%D]h}+|'|+-|+-fd1|'|+.|+.fd1g}.t7j8|+|.t56|+|'|+9|+:|+;d;}/|/<}0|0|+kr|0g|'|+<t@|d?tA|+tA|0fqUt@|d@tA|+qUt3jB|'dd.dA|&|'vr|#C|'|&d1Wd!n 1swYWd!n1swYWd!d!SWd!d!S1s wYd!Sd!S)Baupload changesets to Phabricator If there are multiple revisions specified, they will be send as a stack with a linear dependencies relationship using the order specified by the revset. For the first time uploading changesets, local tags will be created to maintain the association. After the first time, phabsend will check obsstore and tags information so it can figure out whether to update an existing Differential Revision, or create a new one. If --amend is set, update commit messages so they have the ``Differential Revision`` URL, remove related tags. This is similar to what arcanist will do, and is more desired in author-push workflows. Otherwise, use local tags to record the ``Differential Revision`` association. The --confirm option lets you confirm changesets before sending them. You can also add following to your configuration file to make it default behaviour:: [phabsend] confirm = true By default, a separate review will be created for each commit that is selected, and will have the same parent/child relationship in Phabricator. If ``--fold`` is set, multiple commits are rolled up into a single review as if diffed from the parent of the first revision to the last. The commit messages are concatenated in the summary field on Phabricator. phabsend will check obsstore and the above association to decide whether to update an existing Differential Revision, or create a new one. rDs(phabsend requires at least one changesetrEcr=rBrB)rrErrBrCrUr zphabsend..css|] }|r|VqdSr;)obsoletercrBrBrC Wszphabsend..s,obsolete commits cannot be posted for reviewcs8fdd|D}tjtd|t|ftdd)Ncg|]}|qSrBr6rrrJrBrCr_rz:phabsend.._fail_nonlinear_revs..s)cannot phabsend multiple %s revisions: %ss&the revisions must form a linear chain)hint)r rrr nodesummaries)rDrevtypebadnodesrJrBrC_fail_nonlinear_revs^sz&phabsend.._fail_nonlinear_revss heads(%ld)r$sheads roots(%ld)srootrIscannot fold a single revisionscannot fold with --no-amendcSsg|] }t|qSrB)r*r+r,)rr7rBrBrCrs cSsh|] }|r|dqS)r)r)rr9rBrBrCrszphabsend..s0cannot fold revisions with different DREV valuescrOrBrPrQrJrBrCrrr2r3sphabsend cancelledrFrGcSsd|S)Ns blocking(%s)rB)phidrBrBrCrDrzphabsend..s reviewers.addr Nssending rev %d::%d rssending rev %d NNNr sobjectrrr4r2rrTrrrr3rdifferential.queryidscSsg|]}|qSrBrBrLrBrBrCrss4(%ld::) - (%ld) - unstable() - obsolete() - public().cr)rrr)r@rBrCrrs'warning: not updating public commit %s )parentstextrrextras#updating local commit list for D%d s0local commit list for D%d is already up-to-date sno newnodes to update srestabilizing %s as %s snot restabilizing unchanged %s )fixphase)Drrrrrrevrangesortr rrrcheckunfinishedanyrDrrCrr_confirmbeforesendrr1rSmaprrrEr6r(rr*r+r,rrr. querydrevr<r!rwlocklock transactionr)rget_amended_descrJp2phaserpublicrMrformatchangeidrupdate_hash_refsr metadataonlyctxrrr_commitrBr/rrr cleanupnodes setparents)1rSrrDrXrrWheadsrootsfold drevmatchersoldmapconfirm confirmedr reviewersblockersphidsdrevidsdiffmap lastrevphidr7r@rrr oldbasediff oldbaserevidr'rr7 newrevphidr8r9r?rMr4r:restackwnodemappingrAr#rEoldrnewdescr]newr<rB)r@rrCphabsends 4                           &           Tr))rsUser)rsDate)rsBranch)rsNode ID)rsParent c Cst|j\}}|j}|D]4}||}||d\}} } | r(|d| d} n|tdd} |td| t||dfq | td|rLdSd S) NrYrr7sNEWs%s - %s r2s1Send the above changes to %s (Y/n)?$$ &Yes $$ &NoFT) rrSrr6r5rrrr6 promptchoice) rrDryrrrSrEr7r@rr@r:rBrBrCres(  re>closedaccepted abandoned needsreview needsrevisionchangesplannedcCs|dddS)z7get normalized status name from a Differential Revision statusNamer-r8)rtr*rrBrBrC_getstatusnamesr)r(N)groupr$)NN)rXN) ancestorsrXNN)rUNN)and_rUN)rTNN)addrTN)rTNN)subrTN)rNNNN)rsymbolNNN)(:&+-rrendc #st|}dd}t|}||krRdtfddt||d}|r4d||fV|t|7}n|||ddkrJ|||dd|fV|d7}||ksd d|fVdS) Ns():+-& rr8cs|vSr;rB)chspecialrBrCrDrz_tokenize..rr$r-r) memoryviewrrN itertools takewhiler iterbytestr)r^viewposlengthsymbolrBrrC _tokenizes&  rcCs4ttt|\}}|t|krtd||S)Ns invalid token)r _elementsparserrr ParseError)r^treerrBrBrC_parses  rcCs>|dr|ddrt|ddS|rt|SdS)z int or None, ex. 'D45' -> 45; '12' -> 12; 'x' -> NoneDr$N)reisdigitr)rrBrBrC _parsedrevs rcCst}t}|d}|dkrt|d}|r||||fS|dkr>t|d\}}||||||||fS|ddD]}t|\}}||||qD||fS)z9return ({single-drev-id}, {ancestor-drev-id}) to prefetchrrr$rN)r)radd_prefetchdrevsupdate)rr: ancestordrevsoprRatrBrBrCrs&         rcsfddfddit|}t|\}}dd}t|}|D]}|ttd|||dq%|rAdt|ittt|t|Bfd d fd d |DS) areturn a list of "Differential Revision" dicts spec is a string using a simple query language, see docstring in phabread for details. A "Differential Revision dict" looks like: { "activeDiffPHID": "PHID-DIFF-xoqnjkobbm6k4dk6hi72", "authorPHID": "PHID-USER-tv3ohwc4v4jeu34otlye", "auxiliary": { "phabricator:depends-on": [ "PHID-DREV-gbapp366kutjebt7agcd" ] "phabricator:projects": [], }, "branch": "default", "ccs": [], "commits": [], "dateCreated": "1499181406", "dateModified": "1499182103", "diffs": [ "3", "4", ], "hashes": [], "id": "2", "lineCount": "2", "phid": "PHID-DREV-672qvysjcczopag46qty", "properties": {}, "repositoryPHID": "PHID-REPO-hub2hx62ieuqeheznasv", "reviewers": [], "sourcePath": null "status": "0", "statusName": "Needs Review", "summary": "", "testPlan": "", "title": "example", "uri": "https://phab.example.com/D2", } cs|dp |dp dgd}|vr|Std|}|D]}||d<|t|d<q|vr=ttd||S) zparams -> single drev or Noner[phidsNrrZrrs#cannot get Differential Revision %r)rrrr rr)rrkr:r) prefetchedrSrBrCfetchDs   zquerydrev..fetchc st}g}dd|D}|rH|}|}|d|vrq ||d|t|d|di}|dg}|D] }|d|giq;|s|t|S)z6given a top, get a stack from the bottom, [id] -> [id]cSsg|]}d|giqS)r[rB)rr#rBrBrCrXrz/querydrev..getstack..rs auxiliarysphabricator:depends-onr) r)rrrrrreverserbaseset) topdrevidsvisitedrYqueuerr auxiliarydependsrX)rrBrCgetstackTs"    zquerydrev..getstackr&r'r$r[csd}|dkr6td}|rt|gSdtvr+fddD}t|Sttdd|dvrRtdksBJtt |dd S|d kr\dS|d krhdSt d ) Nrrr$cs$g|]}t|dkr|qS)r$)rrQ)rrrBrCrs z+querydrev..walk..sunknown symbol: %s>rrrrSrrrsillegal tree: %r) rrr_knownstatusnamesr rrrroperatorProgrammingError)rrrr:)rrvalididswalk)rrCrys&       zquerydrev..walkcr=rBrBrQ)rrBrCrr zquerydrev..) rrrr)rrr0rr2)rSrrr:r batchsizetofetchrRrB)rrrrSrrrCrgs.    rgcCsP|d}|d}|d}|rd|}d|d}dtd||||gS) zget description (commit message) from "Differential Revision" This is similar to differential.getcommitmessage API. But we only care about limited fields: title, summary, test plan, and URL. rrrs Test Plan: %sDifferential Revision: %surirN)rrNr)rtitler;testplanr`rBrBrCgetdescfromdrevs   rcCsL|st|Sd|d}t|}|sd||gSt||S)a1similar to ``getdescfromdrev``, but supports a folded series of commits This is used when determining if an individual commit needs to have its message amended after posting it for review. The determination is made for each individual commit, even when they were folded into one review. rrr)rr*r+r,rNrq)rr7foldedr`r9rBrBrCrks  rkcCsT|dpi}|dp i}t|dkrdd|DStt|ddp(dhS) zkget the set of local commits from a diff object See ``getdiffmeta()`` for an example diff object. propertiesrr$cSsh|]}t|qSrB)rrLrBrBrCrr z"getlocalcommits..rr8N)rrrsr getdiffmeta)rpropsr rBrBrCrs  rcCs>|dpi}|d}|so|drmt|dd}i}d|vr3d|vr3d|d|df|d<d |vrAd t|d |d <d |vrK|d |d <|d |d}|rZ||d<t|dddkrl|dd|d<ni}d |vrd|vrd|d|d <d |vr|d r|d |d <d|vr|dr|d|d<|S)aget commit metadata (date, node, user, p1) from a diff object The metadata could be "hg:meta", sent by phabsend, like: "properties": { "hg:meta": { "branch": "default", "date": "1499571514 25200", "node": "98c08acae292b2faf60a279b4189beb6cff1414d", "user": "Foo Bar ", "parent": "6d0abad76b30e4724a37ab8721d630394070fe16" } } Or converted from "local:commits", sent by "arc", like: "properties": { "local:commits": { "98c08acae292b2faf60a279b4189beb6cff1414d": { "author": "Foo Bar", "authorEmail": "foo@example.com" "branch": "default", "commit": "98c08acae292b2faf60a279b4189beb6cff1414d", "local": "1000", "message": "...", "parents": ["6d0abad76b30e4724a37ab8721d630394070fe16"], "rev": "98c08acae292b2faf60a279b4189beb6cff1414d", "summary": "...", "tag": "", "time": 1499546314, } } } Note: metadata extracted from "local:commits" will lose time zone information. rrrrrrs%s <%s>rrs%d 0rrrrDrrrBr$rs dateCreateds%s 0ssourceControlBaseRevision)rr2r-rr)rrmetarrr6rBrBrCrs:&      rcsJt|dkrfdd}dt||}t||}|r|Sttd)zconvert user supplied DREVSPECs into "Differential Revision" dicts See ``hg help phabread`` for how to specify each DREVSPEC. rcsrd|}d|S)Ns:(%s)s(%s)rB)rstackrBrC _formatspecsz_getdrevs.._formatspecrsempty DREVSPEC set)rrNrmaplistrgr rr)rSrspecsrrr:rBrrC _getdrevss   rcCstdd|D}t|dd|i}g}|D]U}|td|dtdd|d D}t|d d |i}t|} d } t|d |} tD]} | | vrY| dt| | | f7} qGd| | |f} | |d| fq||dS)a/generate plain-text patch readable by 'hg import' write takes a list of (DREV, bytes), where DREV is the differential number (as bytes, without the "D" prefix) and the bytes are the text of a patch to be imported. drevs is what "querydrev" returns, results of "differential.query". cSs"h|] }tdd|dDqS)cs|]}t|VqdSr;rrrrBrBrCrN1z&readpatch...diffs)r0)rrrBrBrCr1"zreadpatch..r r[s reading D%s rcsrr;rrrBrBrCrN:rzreadpatch..rsdifferential.getrawdiffsdiffIDs# HG changeset patch rs# %s %s s%s%s %sN) r2rnoterr0rr _metanamemaprsr)rSr:rdiffidsr=patchesrrrdr%rrrcontentrBrBrC readpatch(s"   rsphabreadstacksread dependenciessDREVSPEC... [OPTIONS]rcs8t|}t|d|}fdd}t||dS)aprint patches from Phabricator suitable for importing DREVSPEC could be a Differential Revision identity, like ``D123``, or just the number ``123``. It could also have common operators like ``+``, ``-``, ``&``, ``(``, ``)`` for complex queries. Prefix ``:`` could be used to select a stack. If multiple DREVSPEC values are given, the result is the union of each individually evaluated value. No attempt is currently made to reorder the values to run from parent to child. ``abandoned``, ``accepted``, ``closed``, ``needsreview``, ``needsrevision`` could be used to filter patches by status. For performance reason, they only represent a subset of non-status selections and cannot be used alone. For example, ``:D6+8-(2+D4)`` selects a stack up to D6, plus D8 and exclude D2 and D4. ``:D9 & needsreview`` selects "Needs Review" revisions in a stack up to D9. If --stack is given, follow dependencies information and read all patches. It is equivalent to the ``:`` operator. rcs|D] \}}|qdSr;)r)rrrrSrBrC_writems  zphabread.._writeN)rrrrr)rSrrrXr:rrBrrCphabreadNs  rsimport dependencies as wellcstdd<dd<dd<dd<d d rdd <d dr)dd<fd d }td |}tj||dS)zimport patches from Phabricator for the specified Differential Revisions The patches are read and applied starting at the parent of the working directory. See ``hg help phabread`` for how to specify DREVSPEC. Tsbypassr$sstripr8sprefixFr6r4r5cs8d}kdV|D]K\}}td|tt |-}t ||gd\}}}|sHt td||d|g}Wdn1s^wYqWdn1snwYWdn1s}wYWddSWddS1swYdS)Nr4sapplying patch from D%s sD%s: no diffs found )r]rhrirjrrrextractrbytesior tryimportoner rr)rr]rcontents patchdatarr6rejrXrrSrBrCrs0      Pzphabimport.._writerN)rrrrrrrS)rSrrrXrr:rBrrC phabimportts   rs phabupdateacceptsaccept revisionsrejectsreject revisionsrequest-reviewsrequest review on revisionsabandonsabandon revisionsreclaimsreclaim revisionsclosesclose revisionsreopensreopen revisions plan-changessplan changes for revisionsresigns#resign as a reviewer from revisions commandeerscommandeer revisionsscomment on the last revisionslocal revision to updates"[DREVSPEC...| -r REV...] [OPTIONS]cstgd}fdd|D}t|dkr$ttdd|g}|D] }||ddq(d }|r|sCt td |rLt td t |t ||g} g}g} t | D]\} } | d uro| || q_|d | q_| rt tdt|| t|d|} t| D]*\}}|dt| krdr|ddd|r|d|d}t|d|qd S)zrupdate Differential Revision in batch DREVSPEC selects revisions. See :hg:`help phabread` for its usage. ) rrrrrrrrrrcs"g|] }|ddr|qS)r_)rrtr rGrBrCrrzphabupdate..r$s%s cannot be used togethers, Tr rDs--rev requires a repositorys&cannot specify both DREVSPEC and --revNrs-selected revisions without a Differential: %srr r)rrr)rrrr rrrNrr InputErrorrFrra iteritemsrrTrrr)rSrrrXr!rrfrDdrevmapunknownrRrr:r#rrrBrGrC phabupdatesL     rs phabreviewctx)requirescCs||d}t|}|rt|dd|ddS|| }|D]'}t |rQ|j dd}|dsC|d7}||7}t||dSq*d S) ze:phabreview: Object describing the review for this changeset. Has attributes `url` and `id`. rrsD%sr)r1rr&r1rN)resourcer*r+r,r hybriddictrrr'r6r(rrSrrf)r rr7r9rrrrBrBrCtemplate_review s,     r s phabstatus>uirrepoc Cs||d}||d}||d}|}z t||g|}Wn ty*YdSwt|dd|gi}|D]}t|d|krNt|d|d d Sq6dS) z8:phabstatus: String. Status of Phabricator differential.rrr NrZr[rrr)r1sstatus)r rErFKeyErrorrrrr ) r rr7rrSrEr@r:rrBrBrCtemplate_status! s&    rswork) csettopiccs|d}t||}gti}}}t|D]\}} | dur0|| || t|q||qtddt |i} i| D]} |t | dD]}| |<qNqDfdd} |t |8}t ||} dd d | |_t||}tj|| |t jd |id dS) z Phabricator differiential statuszsort(_underway(), topo)NrZr[rcs>|}d|dt|}d|d|fdS)Ns%(statusName)ssphabricator.status.%ss %s %s r)rEr5rr)r7rr drevsbyrevrSrBrC phabstatusL s  z&phabstatusshowview..phabstatuss experimentals graphshortenTsnodelen)r)rDrFr)rrr setdefaultrrrrrrr dagwalkerr_exthookr%longestshortestr displaygraph asciiedges)rSr displayerrDr unknownrevsr revsbydrevidrEr@r:rrrevdagnodelenrBrrCphabstatusshowview9 s8        r )NF)NNNNNNN)r __future__rrrrrrxrrrprmercurial.noderrmercurial.i18nrmercurial.pycompatrmercurial.thirdpartyr mercurialrr r r r r rrrrrrrrrrrrrrrrrrrrr mercurial.utilsr!r"r#rhr% testedwithehcmdtabler configtabletemplatekeyword finaluisetupuisetup configitem colortabler wrapfunctionr]rrrrrrrcompiler(Mr*rCrFrQobjectrRrcrrrgrqrrrrrrrrrrrrr r(r1r<rBCATEGORY_IMPORT_EXPORTrrPrrerrrrrrrrgrrkrrrrrrrr rshowviewr rBrBrBrCs 5   l    &Q>     (% S/ x o    E&  7 <