a ~_@sdZddlZddlmZmZddlmZmZmZddl m Z m Z dZ dZ dZed Zd Zd d Zd dZGdddeZGdddeZGdddeZGdddeZGdddeZGdddeZddZddZdd Zd+d!d"Zd#d$Zd%d&Z d'd(Z!d)d*Z"dS),zRef handling. N)PackedRefsExceptionRefFormatError)git_line valid_hexshaZERO_SHA)GitFileensure_dir_existssref: s refs/heads/s refs/tags/s ~^:?*[s^{}cCs,|tr |ttddSt|dS)z`Parse a symref value. Args: contents: Contents to parse Returns: Destination N ) startswithSYMREFlenrstrip ValueError)contentsr./usr/lib/python3/dist-packages/dulwich/refs.pyparse_symref_value1s rcCsd|vs|drdSd|vr"dSd|vr.dSt|D].\}}t|||ddks^|tvr6dSq6|ddvrvdS|d rdSd |vrdSd |vrdSd S) a+Check if a refname is correctly formatted. Implements all the same rules as git-check-ref-format[1]. [1] http://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html Args: refname: The refname to check Returns: True if refname is valid, False otherwise s/..F/s.. s.locks@{\T)r enumerateord BAD_REF_CHARSendswith)refnameicrrrcheck_ref_format=s$   r c@seZdZdZd6ddZd7ddZd8ddZd d Zd d Zd9ddZ ddZ ddZ d:ddZ ddZ d;ddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd RefsContainerzA container for refs.NcCs ||_dSNZ_logger)selfloggerrrr__init__bszRefsContainer.__init__c Cs4|jdurdS|durdS||||||||dSr"r#)r$refZold_shaZnew_sha committer timestamptimezonemessagerrr_loges zRefsContainer._logcCst|jdS)zMake a ref point at another ref. Args: name: Name of the ref to set other: Name of the ref to point at message: Optional message N)NotImplementedErrorset_symbolic_ref)r$nameotherr(r)r*r+rrrr.ns zRefsContainer.set_symbolic_refcCst|jdS)Get contents of the packed-refs file. Returns: Dictionary mapping ref names to SHA1s Note: Will return an empty dictionary when no packed-refs file is present. N)r-get_packed_refsr$rrrr2yszRefsContainer.get_packed_refscCsdSaeReturn the cached peeled value of a ref, if available. Args: name: Name of the ref to peel Returns: The peeled value of the ref. If the ref is known not point to a tag, this will be the SHA the ref refers to. If the ref may point to a tag, but no cached information is available, None is returned. Nrr$r/rrr get_peeleds zRefsContainer.get_peeledFc Cs|rt||}nt}|D]^\} } | dur>|| n|jd|| fd| |d|r"z|| Wq"ty~Yq"0q"|D]} |jd|| fd|dqdS)Nr)r+) setsubkeysitemsadd set_if_equalsjoinremoveKeyErrorremove_if_equals) r$baser0r(r)r*r+ZpruneZ to_deleter/valuer'rrr import_refss$  zRefsContainer.import_refscCst|jdS)z#All refs present in this container.N)r-allkeysr3rrrrCszRefsContainer.allkeyscCs t|Sr")iterrCr3rrr__iter__szRefsContainer.__iter__cCs|dur||S|SdS)zRefs present in this container. Args: base: An optional base to return refs under. Returns: An unsorted set of valid refs in this container, including packed refs. N)r8rC)r$r@rrrkeyss zRefsContainer.keyscCs@t}t|d}|D] }||r|||dq|S)zRefs present in this container under a base. Args: base: The base to return refs under. Returns: A set of valid refs in this container under the base; the base prefix is stripped from the ref names returned. rN)r7r rCr r:)r$r@rFZbase_lenrrrrr8s    zRefsContainer.subkeysc Csji}||}|durd}n |d}|D]:}z||d|d||<Wq*tybYq*Yq*0q*|S)z@Return the contents of this container as a dictionary. Nr)rFr stripr>)r$r@retrFkeyrrras_dicts    zRefsContainer.as_dictcCs2|dvr dS|dr&t|dds.t|dS)aEnsure a refname is valid and lives in refs or is HEAD. HEAD is not a valid refname according to git-check-ref-format, but this class needs to be able to touch HEAD. Also, check_ref_format expects refnames without the leading 'refs/', but this class requires that so it cannot touch anything outside the refs dir (or HEAD). Args: name: The name of the reference. Raises: KeyError: if a refname is not HEAD or is otherwise not valid. )HEADs refs/stashNsrefs/)r r rr5rrr_check_refnames zRefsContainer._check_refnamecCs"||}|s||d}|S)zRead a reference without following any references. Args: refname: The name of the reference Returns: The contents of the ref file, or None if it does not exist. N)read_loose_refr2get)r$rrrrrread_refs zRefsContainer.read_refcCst|jdS)zRead a loose reference and return its contents. Args: name: the refname to read Returns: The contents of the ref file, or None if it does not exist. N)r-rOr5rrrrOszRefsContainer.read_loose_refcCsft|}d}g}|tr^|ttd}||||}|sDq^|d7}|dkrt|q||fS)zFollow a reference name. Returns: a tuple of (refnames, sha), wheres refnames are the names of references in the chain rNrrM)r r r appendrQr>)r$r/rZdepthrefnamesrrrrfollows    zRefsContainer.followcCs:ddl}|dt||\}}|s.d|fS|d|fS)NrzFRefsContainer._follow is deprecated. Use RefsContainer.follow instead.r)warningswarnDeprecationWarningrT)r$r/rUrSrrrr_followszRefsContainer._followcCs||rdSdS)NTF)rQ)r$rrrr __contains__s zRefsContainer.__contains__cCs"||\}}|durt||S)zaGet the SHA1 for a reference name. This method follows all symbolic references. N)rTr>)r$r/_sharrr __getitem__$szRefsContainer.__getitem__cCst|jdS)a'Set a refname to new_ref only if it currently equals old_ref. This method follows all symbolic references if applicable for the subclass, and can be used to perform an atomic compare-and-swap operation. Args: name: The refname to set. old_ref: The old sha the refname must refer to, or None to set unconditionally. new_ref: The new sha the refname will refer to. message: Message for reflog Returns: True if the set was successful, False otherwise. N)r-r;)r$r/old_refnew_refr(r)r*r+rrrr;.szRefsContainer.set_if_equalscCst|jdS)zAdd a new reference only if it does not already exist. Args: name: Ref name ref: Ref value message: Message for reflog N)r- add_if_newr$r/r'rrrr_@szRefsContainer.add_if_newcCs||d|dS)aSet a reference name to point to the given SHA1. This method follows all symbolic references if applicable for the subclass. Note: This method unconditionally overwrites the contents of a reference. To update atomically only if the reference has not changed, use set_if_equals(). Args: name: The refname to set. ref: The new sha the refname will refer to. N)r;r`rrr __setitem__JszRefsContainer.__setitem__cCst|jdS)aRemove a refname only if it currently equals old_ref. This method does not follow symbolic references, even if applicable for the subclass. It can be used to perform an atomic compare-and-delete operation. Args: name: The refname to delete. old_ref: The old sha the refname must refer to, or None to delete unconditionally. message: Message for reflog Returns: True if the delete was successful, False otherwise. N)r-r?)r$r/r]r(r)r*r+rrrr?ZszRefsContainer.remove_if_equalscCs||ddS)asRemove a refname. This method does not follow symbolic references, even if applicable for the subclass. Note: This method unconditionally deletes the contents of a reference. To delete atomically only if the reference has not changed, use remove_if_equals(). Args: name: The refname to delete. N)r?r5rrr __delitem__ks zRefsContainer.__delitem__c CsDi}|D]2}zt||}Wnty4Yq 0|||<q |S)zuGet a dict with all symrefs in this container. Returns: Dictionary mapping source ref to target ref )rCrrQr)r$rIsrcZdstrrr get_symrefszs   zRefsContainer.get_symrefscCst|jdS)zWatch for changes to the refs in this container. Returns a context manager that yields tuples with (refname, new_sha) N)r-watchr3rrrreszRefsContainer.watch)N)NNNN)NNNN)NNNNF)N)N)NNNN)NNNN)__name__ __module__ __qualname____doc__r&r,r.r2r6rBrCrErFr8rKrNrQrOrTrXrYr\r;r_rar?rbrdrerrrrr!_sH               r!c@s4eZdZddZddZddZddZd d Zd S) _DictRefsWatchercCs ||_dSr")_refs)r$refsrrrr&sz_DictRefsWatcher.__init__cCs&ddlm}||_|jj||S)NrQueue)queuernrk _watchersr:)r$rnrrr __enter__s z_DictRefsWatcher.__enter__cCs |jSr"rorPr3rrr__next__sz_DictRefsWatcher.__next__cCs|j|dSr")ro put_nowait)r$entryrrr_notifysz_DictRefsWatcher._notifycCs|jj|dSNF)rkrpr=r$exc_typeZexc_valZexc_tbrrr__exit__sz_DictRefsWatcher.__exit__N)rfrgrhr&rqrsrvrzrrrrrjs rjcseZdZdZdfdd ZddZddZd d Zd d Zd dZ dddZ dddZ d ddZ d!ddZ ddZddZddZZS)"DictRefsContainerzRefsContainer backed by a simple dict. This container does not support symbolic or packed references and is not threadsafe. Ncs*tt|j|d||_i|_t|_dS)Nr%)superr{r&rk_peeledr7rp)r$rlr% __class__rrr&szDictRefsContainer.__init__cCs |jSr"rkrFr3rrrrCszDictRefsContainer.allkeyscCs|j|dSr"rkrPr5rrrrOsz DictRefsContainer.read_loose_refcCsiSr"rr3rrrr2sz!DictRefsContainer.get_packed_refscCs|jD]}|||fqdSr")rprv)r$r'ZnewshaZwatcherrrrrvs zDictRefsContainer._notifycCst|Sr")rjr3rrrreszDictRefsContainer.watchc CsH||d}t|}||j|<||||j|||||||ddS)Nrr(r)r*r+)rTr rkrvr,) r$r/r0r(r)r*r+oldnewrrrr.s  z"DictRefsContainer.set_symbolic_refc Cs~|dur|j|t|krdS||\}} |D]H} || |j| } ||j| <|| ||j| | |||||dq0dSNFrT)rkrPrrTrNrvr,) r$r/r]r^r(r)r*r+ realnamesrZrealnamerrrrr;s     zDictRefsContainer.set_if_equalsc Cs@||jvrdS||j|<||||j|d|||||ddSr)rkrvr,)r$r/r'r(r)r*r+rrrr_s   zDictRefsContainer.add_if_newc Csj|dur|j|t|krdSz|j|}Wnty@Yn&0||d|j||d||||ddSr)rkrPrpopr>rvr,)r$r/r]r(r)r*r+rrrrr?s   z"DictRefsContainer.remove_if_equalscCs |j|Sr")r~rPr5rrrr6szDictRefsContainer.get_peeledcCs$|D]\}}||d|qdS)z0Update multiple refs; intended only for testing.N)r9r;)r$rlr'r[rrr_updateszDictRefsContainer._updatecCs|j|dS)z5Update cached peeled refs; intended only for testing.N)r~update)r$peeledrrr_update_peeledsz DictRefsContainer._update_peeled)N)NNNN)NNNN)NNNN)NNNN)rfrgrhrir&rCrOr2rvrer.r;r_r?r6rr __classcell__rrrrr{s,    r{c@s8eZdZdZddZddZddZdd Zd d Zd S) InfoRefsContainerz5Refs container that reads refs from a info/refs file.cCsi|_i|_|D]l}|dd\}}|trb|dd}t|sVtd|||j|<qt|svtd|||j|<qdS)N  invalid ref name %r) rkr~ readlinesr splitrANNOTATED_TAG_SUFFIXr r)r$fliner[r/rrrr&s      zInfoRefsContainer.__init__cCs |jSr"rr3rrrrCszInfoRefsContainer.allkeyscCs|j|dSr"rr5rrrrOsz InfoRefsContainer.read_loose_refcCsiSr"rr3rrrr2sz!InfoRefsContainer.get_packed_refscCs.z |j|WSty(|j|YS0dSr")r~r>rkr5rrrr6s  zInfoRefsContainer.get_peeledN) rfrgrhrir&rCrOr2r6rrrrrs rc@s4eZdZddZddZddZddZd d Zd S) _InotifyRefsWatchercCsnddl}ddlm}t||_||_|jj|j|j |j B|j Bddd|j |j|j d|_||_dS)NrrmT)ZrecZauto_add)Zdefault_proc_fun) pyinotifyrornosfsdecodepathZ WatchManagerZmanagerZ add_watch IN_DELETEIN_CLOSE_WRITE IN_MOVED_TOZThreadedNotifierrvnotifier)r$rrrnrrrr&&s"   z_InotifyRefsWatcher.__init__cCs|jr dS|jdrdSttj|j|j}|jdkrN|j |dfnT|jdvrt |jd.}| d}|j ||fWdn1s0YdS)Nz.lockr)rrrb ) dirpathnamerrfsencoderrelpathZmasknamerortopenreadliner )r$Zeventr'rr[rrrrv4s   z_InotifyRefsWatcher._notifycCs |jSr"rrr3rrrrsAsz_InotifyRefsWatcher.__next__cCs|j|Sr")rstartr3rrrrqDs z_InotifyRefsWatcher.__enter__cCs|jdSrw)rstoprxrrrrzHs z_InotifyRefsWatcher.__exit__N)rfrgrhr&rvrsrqrzrrrrr$s  rcseZdZdZdfdd ZddZddZd d Zd d Zd dZ ddZ ddZ ddZ d ddZ d!ddZd"ddZd#ddZddZZS)$DiskRefsContainerz)Refs container that reads refs from disk.Ncsntt|j|dt|dddur,t|}||_|dur>|}t|dddurXt|}||_d|_d|_ dS)Nr|encode) r}rr&getattrrrr worktree_path _packed_refs _peeled_refs)r$rrr%rrrr&Ps  zDiskRefsContainer.__init__cCsd|jj|jfS)Nz%s(%r))rrfrr3rrr__repr__]szDiskRefsContainer.__repr__c Cst}||}t|D]\}}}|t|d}tjjdkrV|ttjjd}| d}|D]8}d |rv|gng|g} t |d| rd| | qdq| D]*} | |r| | t|d dq|S)N/r)r7refpathrwalkr rsepreplacerrHr<r r:r2r ) r$r@r8rroot unused_dirsfilesrfilenamerrJrrrr8`s     zDiskRefsContainer.subkeysc Cst}tj|dr"|d|d}|d}t|D]f\}}}|t|d}tjjdkr|| t tjjd}|D]$}d ||g} t | r|| qq@| ||S)NrLrGsrefsrr)r7rrexistsrr:rr rrrr<r rr2) r$rCrZrefspathrrrrrrrrrrCss    zDiskRefsContainer.allkeyscCsNtjjdkr"|dttjj}|dkr:tj|j|Stj|j|SdS)z(Return the disk path of a ref. rrrLN)rrrrrr<rr5rrrrs  zDiskRefsContainer.refpathcCs|jduri|_i|_tj|jd}zt|d}WntyJiYS0|tt| }| drd|vrt |D]"\}}}||j|<|r|||j|<q|n&| dt |D]\}}||j|<qWdn1s0Y|jS)r1N packed-refsrs # pack-refss peeledr)rrrrr<rFileNotFoundErrornextrDr r read_packed_refs_with_peeledseekread_packed_refs)r$rrZ first_liner[r/rrrrr2s*      *z!DiskRefsContainer.get_packed_refscCs@||jdus||jvr dS||jvr4|j|S||SdSr4)r2rrr5rrrr6s   zDiskRefsContainer.get_peeledc Cs||}zt|dr}|tt}|tkrT|tt|dWdWS||dttWdWSWdn1s0YWntt t fyYdS0dS)aRead a reference file and return its contents. If the reference file a symbolic reference, only read the first line of the file. Otherwise, only read the first 40 bytes. Args: name: the refname to read, relative to refpath Returns: The contents of the ref file, or None if the file does not exist. Raises: IOError: if any other error occurs rr N() rrreadr r rrDr rIsADirectoryErrorNotADirectoryError)r$r/rrheaderrrrrOs  &Hz DiskRefsContainer.read_loose_refcCs|jdurdStj|jd}t|d}zdd|_|||jvrPW|dS|j|=||jvrj|j|=t||j|j| W|n |0dS)Nrwb) rrrr<rr2abortrwrite_packed_refsclose)r$r/rrrrr_remove_packed_refs"     z$DiskRefsContainer._remove_packed_refc Cs||||||}t|d}z<|t|d||d} |j|| | ||||dWnty|Yn 0| dS)zMake a ref point at another ref. Args: name: Name of the ref to set other: Name of the ref to point at message: Optional message to describe the change rrrrN) rNrrwriter rTr, BaseExceptionrr) r$r/r0r(r)r*r+rrr[rrrr.s       z"DiskRefsContainer.set_symbolic_refc Cs||z||\}} |d} Wnttfy>|} Yn0|| } tj| } |} | r| | ddurzt | tj| } q^t tj| t | d}|durzH| | }|dur| | t}||kr|WWddSWn"ttfy|Yn0z||dWn"ttfyN|Yn0|j| ||||||dWdn1s~0YdS)aSet a refname to new_ref only if it currently equals old_ref. This method follows all symbolic references, and can be used to perform an atomic compare-and-swap operation. Args: name: The refname to set. old_ref: The old sha the refname must refer to, or None to set unconditionally. new_ref: The new sha the refname will refer to. message: Set message for reflog Returns: True if the set was successful, False otherwise. rNrFrrT)rNrTr> IndexErrorrrrdirnamer2rPrrrrOrrOSErrorIOErrorrr,)r$r/r]r^r(r)r*r+rrZrrZ probe_ref packed_refsrorig_refrrrr; sJ         &zDiskRefsContainer.set_if_equalsc Csz(||\}}|durWdS|d} WnttfyB|} Yn0|| || } ttj| t | d} tj | s|| vr| WddSz| |dWn ttfy| Yn0|j|d|||||dWdn1s0YdS)aAdd a new reference only if it does not already exist. This method follows symrefs, and only ensures that the last ref in the chain does not exist. Args: name: The refname to set. ref: The new sha the refname will refer to. message: Optional message for reflog Returns: True if the add was successful, False otherwise. NFrrrrT)rTr>rrNrrrrrrrr2rrrrr,) r$r/r'r(r)r*r+rrrrrrrrr_Ds0       &zDiskRefsContainer.add_if_newc Cs6||||}ttj|t|d}z|durp||} | durZ| |t } | |krpW| dSzt |Wnt yYn0|||j||d||||dW| n | 0|} z| dd\} } WntyYq2Yn0|| } zt| Wqty.Yq2Yq0qdS)aRemove a refname only if it currently equals old_ref. This method does not follow symbolic references. It can be used to perform an atomic compare-and-delete operation. Args: name: The refname to delete. old_ref: The old sha the refname must refer to, or None to delete unconditionally. message: Optional message Returns: True if the delete was successful, False otherwise. rNFrrrT)rNrrrrrrrOr2rPrrr=rrr,rsplitrrmdirr) r$r/r]r(r)r*r+rrrparentrZZparent_filenamerrrr?jsB           z"DiskRefsContainer.remove_if_equalscCsddl}t|jS)Nr)rrr)r$rrrrreszDiskRefsContainer.watch)NN)NNNN)NNNN)NNNN)NNNN)rfrgrhrir&rr8rCrr2r6rOrr.r;r_r?rerrrrrrMs.  !  7 & =rcCs`|dd}t|dkr(td||\}}t|sDtd|t|sXtd|||fS)z6Split a single ref line into a tuple of SHA1 and name.r zinvalid ref line %rInvalid hex sha %rr)r rr rrr )rfieldsr[r/rrr_split_ref_lines    rccs6|D],}|drq|dr&tdt|VqdS)zRead a packed refs file. Args: f: file-like object to read from Returns: Iterator over tuples with SHA1s and ref names. #^z.found peeled ref in packed-refs without peeledN)r rr)rrrrrrs  rccsd}|D]}|ddkrq|d}|dr|s:tdt|dds^td|ddt|\}}d}|||ddfVq|rt|\}}||dfV|}q|rt|\}}||dfVdS) a Read a packed refs file including peeled refs. Assumes the "# pack-refs with: peeled" line was already read. Yields tuples with ref names, SHA1s, and peeled SHA1s (or None). Args: f: file-like object to read from, seek'ed to the second line Nrrr rzunexpected peeled ref linerr)r r rrr)rZlastrr[r/rrrrs(        rcCs`|duri}n |dt|D]6}|t|||||vr$|d||dq$dS)zWrite a packed refs file. Args: f: empty file-like object to write to packed_refs: dict of refname to sha of packed refs to write peeled_refs: dict of refname to peeled value of sha Ns# pack-refs with: peeled rr)rsortedrFr)rrZ peeled_refsrrrrrs rcCs4i}|D]"}|ddd\}}|||<q |S)Nr rr)rr r)rrIrr[r/rrrread_info_refss   rc cst|D]x\}}|dkrq z ||}Wnty@Yq Yn0||}|jd|dV|j|jkr |jd|tdVq dS)zGenerate info refs.rLrrN)rr9r>Zpeel_shaidr)rlZstorer/r[orrrrwrite_info_refss     rcCs |tSr")r LOCAL_BRANCH_PREFIX)xrrris_local_branchsrcCsdd|DS)zRemove all peeled refscSs i|]\}}|ts||qSr)rr).0r'r[rrr s  z%strip_peeled_refs..)r9)rlrrrstrip_peeled_refssr)N)#rirZdulwich.errorsrrZdulwich.objectsrrrZ dulwich.filerrr rZLOCAL_TAG_PREFIXr7rrrr objectr!rjr{rrrrrrrrrrrrrrrs: "4[")a