a ~_XY@s\dZddlmZmZddlmZddlmZddlZddl m Z m Z dZ dZ d Zd Zd Zd ZeefZe dddZd ZdZdZdZGdddedgdZddZddZddZd2ddZddZd3ddZd d!Zd"d#Z d4d$d%Z!d&Z"d'd(Z#d)d*Z$d5d+d,Z%d-d.Z&Gd/d0d0e'Z(eZ)eZ*e#Z+zdd1l,mZmZm#Z#Wne-yVYn0dS)6z&Utilities for diffing files and trees.) defaultdict namedtuple)BytesIO)chainN) S_ISGITLINK TreeEntryaddZmodifydeleterenamecopyZ unchangedd<c@s(eZdZdZeddZeddZdS) TreeChangez.Named tuple a single change between two trees.cCs |tt|SN) CHANGE_ADD _NULL_ENTRY)clsnewr3/usr/lib/python3/dist-packages/dulwich/diff_tree.pyr;szTreeChange.addcCs |t|tSr) CHANGE_DELETEr)roldrrrr ?szTreeChange.deleteN)__name__ __module__ __qualname____doc__ classmethodrr rrrrr8s  r)typerrcCs2g}|s |S|jddD]}|||q|S)NT)Z name_order)Z iteritemsappendZin_path)pathZtreeresultentryrrr _tree_entriesDs r#c Cst||}t||}d}}t|}t|}g} ||kr||kr||} ||} | j| jkrt| | tf|d7}q0| j| jkr| t| f|d7}q0| | | f|d7}|d7}q0t||D]} | || tfqt||D]} | t|| fq| S)aMerge the entries of two trees. Args: path: A path to prepend to all tree entry names. tree1: The first Tree object to iterate, or None. tree2: The second Tree object to iterate, or None. Returns: A list of pairs of TreeEntry objects for each pair of entries in the trees. If an entry exists in one tree but not the other, the other entry will have all attributes set to None. If neither entry's path is None, they are guaranteed to match. r)r#lenr rrrange) r tree1tree2Zentries1Zentries2Zi1Zi2Zlen1Zlen2r!entry1entry2irrr_merge_entriesMs.       r,cCs|j}|durdSt|SNF)modestatS_ISDIR)r"r.rrr_is_treeusr1Fccs|r tjp d}|rtjpd}td||td||fg}|r|\}}t|} t|} |rl| rl| rl||krlq6| rz||jp|d} | r||jpd} |jp|j} |tt | | | ||fVq6dS)aRecursively walk all the entries of two trees. Iteration is depth-first pre-order, as in e.g. os.walk. Args: store: An ObjectStore for looking up objects. tree1_id: The SHA of the first Tree object to iterate, or None. tree2_id: The SHA of the second Tree object to iterate, or None. param prune_identical: If True, identical subtrees will not be walked. Returns: Iterator over Pairs of TreeEntry objects for each pair of entries in the trees and their subtrees recursively. If an entry exists in one tree but not the other, the other entry will have all attributes set to None. If neither entry's path is None, they are guaranteed to match. N) r/S_IFDIRrpopr1shar extendreversedr,)storetree1_idtree2_idprune_identicalZmode1Zmode2Ztodor)r*Zis_tree1Zis_tree2r'r(r rrr walk_trees|s  r<cCs"|jdus|st|jrtS|Sr)r.r/r0r)r" include_treesrrr _skip_treesr>c cs|dur:|dur:|dur:|j||||dD] }|Vq*dSt|||| d}|D]\} } | | krf|sfqPt| |} t| |} | tkr| tkrt| jt| jkr|st| Vt} t } q| | krt } qt } n| tkrt } n| tkrPt } nqPt| | | VqPdS)auFind the differences between the contents of two trees. Args: store: An ObjectStore for looking up objects. tree1_id: The SHA of the source tree. tree2_id: The SHA of the target tree. want_unchanged: If True, include TreeChanges for unmodified entries as well. include_trees: Whether to include trees rename_detector: RenameDetector object for detecting renames. change_type_same: Whether to report change types in the same entry or as delete+add. Returns: Iterator over TreeChange instances for each change between the source and target tree. Nwant_unchangedr=)r;) changes_with_renamesr<r>rr/S_IFMTr.rr rCHANGE_UNCHANGED CHANGE_MODIFYr) r8r9r:r@rename_detectorr=Zchange_type_samechangeentriesr)r* change_typerrr tree_changessB      rIcCs |D]}|||krdSqdS)NFTr)seqkeyvalueerrr_all_eqs rNcCst|dd|||dS)Nr$r)rN)rJrKrrr _all_samesrOc#sfdd|D}t|tfdd}t|D]:\}}|D],}|jtkrZ|jj} n|jj} ||| |<qBq6dd} dd} t| D]d\} } t| ksJd d| D}t || trt || s| Vqt || s| Vqd | vr| Vqd S) aBGet the tree changes for a merge tree relative to all its parents. Args: store: An ObjectStore for looking up objects. parent_tree_ids: An iterable of the SHAs of the parent trees. tree_id: The SHA of the merge tree. rename_detector: RenameDetector object for detecting renames. Returns: Iterator over lists of TreeChange objects, one per conflicted path in the merge. Each list contains one element per parent, with the TreeChange for that path relative to that parent. An element may be None if it never existed in one parent and was deleted in two others. A path is only included in the output if it is a conflict, i.e. its SHA in the merge tree is not found in any of the parents, or in the case of deletes, if not all of the old SHAs match. csg|]}t|dqS))rE)rI).0t)rEr8tree_idrr sz*tree_changes_for_merge..cs dgSrrr) num_parentsrrr2z(tree_changes_for_merge..cSs|jjSr)rr5crrrold_shasz'tree_changes_for_merge..old_shacSs|jSr)rrVrrrrHsz+tree_changes_for_merge..change_typecSsg|]}|dur|qSrr)rPrWrrrrSr2N) r%r enumeraterrrr rsorteditemsrNrO)r8Zparent_tree_idsrRrEZall_parent_changesZchanges_by_pathr+Zparent_changesrFr rXrH_ZchangesZhaver)rTrEr8rRrtree_changes_for_merges.     r]@c Cstt}t}d}|j}|j}|j}|j}t| D]`}| dd}|||d7}|dksh|t kr8|} |t | t | 7<|d|d}q8|dkr|} |t | t | 7<|S)zCount the blocks in an object. Splits the data into blocks either on lines or <=64-byte chunks of lines. Args: obj: The object to count blocks for. Returns: A dict of block hashcode -> total bytes occurring. rr$Zbig )rintrwriteseektruncategetvaluer from_iterableZ as_raw_chunksto_bytes _BLOCK_SIZEhashr%) objZ block_countsblocknZ block_writeZ block_seekZblock_truncateZblock_getvaluerWrLZ last_blockrrr _count_blocks)s*  rlcCsPt|t|kr||}}d}|D]$\}}||}|r&|t||7}q&|S)aWCount the number of common bytes in two block count dicts. Args: block1: The first dict of block hashcode -> total bytes. block2: The second dict of block hashcode -> total bytes. Returns: The number of bytes in common between blocks1 and blocks2. This is only approximate due to possible hash collisions. r)r%r[getmin)Zblocks1Zblocks2scorerjZcount1Zcount2rrr _common_bytesMs   rpcCs|dur i}|j|vr$t|||j<|j|vr.csg|]}|jjvr|qSrrr rPd) delete_pathsrrrSs )rr)rrrr)rrr_pruneszRenameDetector._prunecCs\tt}|jD]}||jj|jqtt}|jD]&}|jtk}||j j|j |fq6t }t }| D]\}} ||} t | | D]b\\} }} t | jt | jkrq|r|| j|| j|rtpt} |jt| | | qt| t| }| dd} |dkrr| | dD]&} || j|jtt| | q"qr|||dS)Nr)rlistrrr5rrrrrsetr[zipr/rBr.rr CHANGE_RENAME CHANGE_COPYrrr%r)rZadd_mapr delete_mapr Z is_deleterrr5Z sha_deletesZsha_addsrrnew_typeZnum_extra_addsrrr_find_exact_renamess4        z"RenameDetector._find_exact_renamescCst|jt|j|jdkS)N)r%rrr|rrrr_should_find_content_renamessz+RenameDetector._should_find_content_renamescCs*|r|jj|jjkrtS|jtkr&tStSr)rr rrDrrrr)r check_pathsr rrrr _rename_types  zRenameDetector._rename_typec Csg}|_|sdSi}|jdu}|jD]}t|jjr=r2z0RenameDetector._join_modifies..csg|]}|jjvr|qSrrrZmodifiesrrrSEr2z1RenameDetector._join_modifies..csg|]}|jjvr|qSrrrrrrrSFs)r{dictrrrr rmr/rBrr.rrDrvalues)rrrr r rrr_join_modifies8s   zRenameDetector._join_modifiescCs8g}||j||j||j|jtd|S)N)rK)r6rrrrrw)rr!rrr_sorted_changesJs     zRenameDetector._sorted_changescCs |jr dSdd|jD|_dS)NcSsg|]}|jtkr|qSr)rrCrrrrrSUsz3RenameDetector._prune_unchanged..)r~rrrrr_prune_unchangedRs zRenameDetector._prune_unchangedcCsP|||_||_||||||||| S)zAIterate TreeChanges between two tree SHAs, with rename detection.) rr~rrrrrrrr)rr9r:r@r=rrrrAXs z#RenameDetector.changes_with_renamesN)FF)rrrrRENAME_THRESHOLD MAX_FILESREWRITE_THRESHOLDrrrrrrrrrrrrrrrArrrrrxs, ! rx)r1r,rl)F)FNFF)N)N).r collectionsrrior itertoolsrr/Zdulwich.objectsrrrrDrrrrCZRENAME_CHANGE_TYPESrrsrrrrr#r,r1r<r>rIrNrOr]rgrlrprvrwobjectrxZ _is_tree_pyZ_merge_entries_pyZ_count_blocks_pyZdulwich._diff_tree ImportErrorrrrrsZ     ( $ : ;$  a