U
    楡c@                  	   @   s  d dl mZ d dlmZ d dlZd dlmZmZmZm	Z	m
Z
mZmZ d dlZd dlmZmZ d dlmZmZmZmZmZmZ d dlmZmZ d dlmZmZmZ d d	lm Z m!Z! d d
l"m#Z# d dl$m%Z% d dl&m'Z( ddl)m*Z*m+Z+m,Z,m-Z- ddl.m/Z/m0Z0 d dl1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z: d dl;m<Z< e6r^ddl=m>Z> d dl?m@Z@ d dlAmBZB eeB ZCe, ZDdZEeFe<eFdddZGdd ZHeFdeFddddZIeJeJddd ZKde fe5e9e*d!f  e3eL e9deLf e8e  dd"d#d$ZMe3eL e7eJeJf d%d&d'ZNe9e*e<eJf e7e<eJf d(d)d*ZOe3eL e7eJe2e7e<eJf d!f eLeLf d%d+d,ZPd8e4e+ d-eQeJe7eLe4d. f d/d0d1ZRd.eJe*d2d3d4ZSd-e5eL e4e* d5d6d7ZTdS )9    )BytesIO)PathN)S_IFDIRS_IFLNKS_ISLNKS_ISDIRS_IFMTS_IFREGS_IXUSR)PROC_CREATIONFLAGShandle_process_output)defenc
force_textforce_bytesis_posixis_winsafe_decode)UnmergedEntriesErrorHookExecutionError)tree_to_streamtraverse_tree_recursivetraverse_trees_recursive)IndexFileSHA1Writerfinalize_process)IStream)str_tree_type   )BaseIndexEntry
IndexEntryCE_NAMEMASKCE_STAGESHIFT)packunpack)	DictIOListSequenceTYPE_CHECKINGTupleTypeUnioncast)PathLike)	IndexFile)GitCmdObjectDB)TreeCacheTup)write_cache
read_cachewrite_tree_from_cache	entry_keystat_mode_to_index_modeS_IFGITLINKrun_commit_hook	hook_path)namegit_dirreturnc                 C   s   t |d| S )zK:return: path to the given named hook in the given git repository directoryhooks)ospjoin)r8   r9    r>   1/tmp/pip-unpacked-wheel-_pbxsds5/git/index/fun.pyr7   J   s    r7   c                 C   s   t | d S )Nr   )r<   splitext)pathr>   r>   r?   _has_file_extensionO   s    rB   r-   )r8   indexargsr:   c              
   G   s2  t | |jj}t|tjs dS tj }tt	|j
|d< d|d< |g}zVtrvt|svt||jj }d|g}tj|t| |tjtj|jjttd}W n. tk
r } zt|||W 5 d}~X Y n`X g }g }	t||j|	jt d|}
d|	}|jdkr.t|
t}
t|t}t||j||
dS )	zRun the commit hook of the given name. Silently ignores hooks that do not exist.
    :param name: name of hook, like 'pre-commit'
    :param index: IndexFile instance
    :param args: arguments passed to hook file
    :raises HookExecutionError:NZGIT_INDEX_FILE:Z
GIT_EDITORzbash.exe)envstdoutstderrcwd	close_fdscreationflags r   ) r7   repor9   osaccessX_OKenvironcopyr   strrA   r   rB   r   relative_toZworking_diras_posix
subprocessPopenlistPIPEr   r   	Exceptionr   r   appendr   r=   
returncoder   r   )r8   rC   rD   hprF   cmdZrelative_hpexZstdout_listZstderr_listrG   rH   r>   r>   r?   r6   S   s>    


	



r6   )moder:   c                 C   s8   t | rtS t| s t| tkr$tS t| t@ r2dp4dB S )zYConvert the given mode from a stat call to the corresponding index mode
    and return iti  i  )r   r   r   r   r5   r	   r
   )r`   r>   r>   r?   r4      s
    r4   r   )entriesstreamextension_dataShaStreamClsr:   c                 C   s  ||}|j }|j}d}|d |td|t|  | D ]}| }	||j ||j t|j}
t|
t	d}t|t
@ }|t|kstd|j ||jt@ B }|td|j|j|j|j|j|j|j|	 || | |	 d d@ }|d	|	| |    q8|d
k	r|| |  d
S )a  Write the cache represented by entries to a stream

    :param entries: **sorted** list of entries
    :param stream: stream to wrap into the AdapterStreamCls - it is used for
        final output.

    :param ShaStreamCls: Type to use when writing to the stream. It produces a sha
        while writing to it, before the data is passed on to the wrapped stream

    :param extension_data: any kind of data to write as a trailer, it must begin
        a 4 byte identifier, followed by its size ( 4 bytes )      DIRC>LL)encodingz"Path %s too long to fit into index>LLLLLL20sH       N)tellwriter!   lenZctime_bytesZmtime_bytesrS   rA   r   r   r   AssertionErrorflagsCE_NAMEMASK_INVdevinoder`   uidgidsizebinshaZ	write_sha)ra   rb   rc   rd   Z
stream_sharm   rn   versionentrybeginoffsetZpath_strrA   plenrq   	real_sizer>   r>   r?   r0      sD    




r0   )rb   r:   c                 C   sX   |  d}|dkrtd| ttttf td|  d}|\}}|dksPt||fS )z=Return tuple(version_long, num_entries) from the given stream   rf   zInvalid index file header: %rrg   rj   r   re   )readrp   r+   r(   intr"   )rb   Ztype_idunpackedry   num_entriesr>   r>   r?   read_header   s    
r   )rz   r:   c                  G   sH   t | dkr.| d }t|ts"t|j|jfS tttt	f | } | S dS )z:return: Key suitable to be used for the index.entries dictionary
    :param entry: One instance of type BaseIndexEntry or the path and the stager   r   N)
ro   
isinstancer   rp   rA   stager+   r(   r,   r   )rz   Zentry_firstr>   r>   r?   r3      s    r3   c                 C   s,  t | \}}d}i }| j}| j}||k r| }td|dd }td|dd }	td|d\}
}}}}}}}|t@ }||t}| | d d@ }||| |   t||||||	|
||||f}||||jf< |d7 }q | d}t	|d	kst
d
t	| |dd }|dd }||||fS )a}  Read a cache file from the given stream
    :return: tuple(version, entries_dict, extension_data, content_sha)
    * version is the integer version number
    * entries dict is a dictionary which maps IndexEntry instances to a path at a stage
    * extension_data is '' or 4 bytes of type + 4 bytes of size + size bytes
    * content_sha is a 20 byte sha on all cache file contentsr   z>8srj   ri   .   rk   r      zNIndex Footer was not at least a sha on content as it was only %i bytes in sizeiN)r   r   rm   r"   r   decoder   r   r   ro   rp   )rb   ry   r   countra   r   rm   r{   ctimemtimers   inor`   ru   rv   rw   sharq   Z	path_sizerA   r}   rz   rc   Zcontent_shar>   r>   r?   r1      s2    	
	


r1   r.   r/   )ra   odbslsir:   c                 C   s<  g }|j }|j}||k r| | }|jdkr2t||d7 }|jd|}|dkrp||j|j|j|d f q|j|| }	|}
|
|k r| |
 }|jd|}|dks|j|| |	krq|
d7 }
qt	| |t
|d |
|d \}}||t|	f |
}qt }t||j |d |ttt| |}|j|fS )a  Create a tree from the given sorted list of entries and put the respective
    trees into the given object database

    :param entries: **sorted** list of IndexEntries
    :param odb: object database to store the trees in
    :param si: start index at which we should start creating subtrees
    :param sl: slice indicating the range we should process on the entries list
    :return: tuple(binsha, list(tree_entry, ...)) a tuple of a sha and a list of
        tree entries being a tuple of hexsha, mode, namer   r   /r   N)startstopr   r   rA   findr[   rx   r`   r2   slicer   r   r   rn   seekstorer   r   ro   getvalue)ra   r   r   r   Z
tree_itemsciendrz   ZrboundbasexiZoentryZorboundr   Z_tree_entry_listsioZistreamr>   r>   r?   r2     s6    
 
 
r2   )
tree_entryr   r:   c                 C   s    t | d | d |t> | d fS )Nr   r   re   )r   r    )r   r   r>   r>   r?   _tree_entry_to_baseindexentryU  s    r   )r   	tree_shasr:   c                 C   s  g }t |dkr:t| |d dD ]}|t|d q |S t |dkrVtdt | t| |dD ]<\}}}|dk	r|dk	r|dk	rl|d |d kr|d |d kr|d |d ks|d |d kr$|d |d kr$|d |d kr$|t|d |t|d	 |t|d nF|d |d ksH|d |d krZ|t|d n|t|d nD|d |d ks|d |d kr|t|d |t|d	 nP|dkrnD|d |d ks|d |d kr|t|d |t|d qb|dkr.|dk	st|t|d qb|dkrJ|t|d qb|d |d ksn|d |d kr|t|d	 |t|d qb|t|d qb|S )
a  
    :return: list of BaseIndexEntries representing the aggressive merge of the given
        trees. All valid entries are on stage 0, whereas the conflicting ones are left
        on stage 1, 2 or 3, whereas stage 1 corresponds to the common ancestor tree,
        2 to our tree and 3 to 'their' tree.
    :param tree_shas: 1, 2 or 3 trees as identified by their binary 20 byte shas
        If 1 or two, the entries will effectively correspond to the last given tree
        If 3 are given, a 3 way merge is performedr   r   rL   r      zCannot handle %i trees at onceNr   re   )ro   r   r[   r   
ValueErrorr   rp   )r   r   outrz   r   ZoursZtheirsr>   r>   r?   aggressive_tree_mergeY  sT    	


0$$
$	

$r   )r   )Uior   pathlibr   rN   statr   r   r   r   r   r	   r
   rV   Zgit.cmdr   r   Z
git.compatr   r   r   r   r   r   Zgit.excr   r   Zgit.objects.funr   r   r   Zgit.utilr   r   Z
gitdb.baser   Z	gitdb.typr   os.pathrA   r<   typr   r   r   r    utilr!   r"   typingr#   r$   r%   r&   r'   r(   r)   r*   r+   Z	git.typesr,   r   r-   Zgit.dbr.   Zgit.objects.treer/   r5   rr   __all__rS   r7   rB   r6   r   r4   bytesr0   r   r3   r1   r   r2   r   r   r>   r>   r>   r?   <module>   sf   $	 ,-
@"3    :