a
    h>                     @   s  d dl mZ d dlZd dlZd dlZd dlmZ d dl	mZ
 d dl	mZ d dl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 erd dlmZm Z  d dlm!Z! d dlm"Z"m#Z# e
j$Z$e
j%Z%e&e'Z(e)dZ*dd Z+G dd deZ,e-e, dS )    )absolute_importN)parse)request)
BadCommandInstallationError)display_pathhide_url)make_command)TempDirectory)MYPY_CHECK_RUNNING)RemoteNotFoundErrorVersionControl!find_path_to_setup_from_repo_rootvcs)OptionalTuple)
HiddenText)AuthInfo
RevOptionsz^[a-fA-F0-9]{40}$c                 C   s   t t| S N)bool
HASH_REGEXmatch)sha r   7/usr/lib/python3/dist-packages/pip/_internal/vcs/git.pylooks_like_hash+   s    r   c                       s   e Zd ZdZdZdZdZdZdZe	dd Z
d	d
 Zdd Zedd Zdd Zedd Zedd Zedd Zedd Zdd Zdd Zdd Zedd  Zed!d" Zed.d$d%Zed&d' Ze fd(d)Zed*d+ Ze fd,d-Z  ZS )/Gitgitz.gitclone)r   zgit+httpz	git+httpszgit+sshzgit+gitzgit+file)ZGIT_DIRZGIT_WORK_TREEHEADc                 C   s   | gS r   r   revr   r   r   get_base_rev_args;   s    zGit.get_base_rev_argsc                 C   sJ   |  t|\}}|jsdS | ||js.dS t| ||jd }| S )NFr   )Zget_url_rev_optionsr   r"   is_commit_id_equalr   get_revision_sha)selfurldest_rev_optionsZis_tag_or_branchr   r   r   is_immutable_rev_checkout?   s    zGit.is_immutable_rev_checkoutc                 C   s^   d}| j dgddd}||r:|t|d   d }nd}d|dd d	 }t|S )
Nzgit version versionFT)show_stdoutstdout_onlyr    .   )run_command
startswithlensplitjoinparse_version)r&   ZVERSION_PFXr,   r   r   r   get_git_versionP   s    
zGit.get_git_versionc                 C   sB   g d}| j |ddd|d}| }|dr>|tdd S dS )zl
        Return the current branch, or None if HEAD isn't at a branch
        (e.g. detached HEAD).
        )zsymbolic-ref-qr       FTZextra_ok_returncodesr-   r.   cwdzrefs/heads/N)r2   stripr3   r4   )clslocationargsoutputrefr   r   r   get_current_branch_   s    

zGit.get_current_branchc                 C   sl   | ds|d }tdd<}| j|j|d | jdddd|gd	|jd
 W d   n1 s^0    Y  dS )z@Export the Git repository at the url to the destination location/export)kind)r'   zcheckout-indexz-az-fz--prefixF)r-   r=   N)endswithr
   Zunpackpathr2   )r&   r@   r'   Ztemp_dirr   r   r   rF   x   s    
z
Git.exportc           
   	   C   s   | j d|g|dddd}i }| dD ]T}|d}|s>q*z|jdd	d
\}}W n  tyt   td|Y n0 |||< q*d|}d|}	||}|dur|dfS ||	}|dfS )z
        Return (sha_or_none, is_branch), where sha_or_none is a commit hash
        if the revision names a remote branch or tag, otherwise None.

        Args:
          dest: the repository directory.
          rev: the revision name.
        zshow-refFTignore)r=   r-   r.   on_returncode
    )maxsplitzunexpected show-ref line: {!r}zrefs/remotes/origin/{}zrefs/tags/{}N)r2   r>   r5   rstrip
ValueErrorformatget)
r?   r(   r"   rB   Zrefsliner   rC   Z
branch_refZtag_refr   r   r   r%      s0    





zGit.get_revision_shac                 C   s.   | drdS t|sdS | ||r*dS dS )a$  
        Return true if rev is a ref or is a commit that we don't have locally.

        Branches and tags are not considered in this method because they are
        assumed to be always available locally (which is a normal outcome of
        ``git clone`` and ``git fetch --tags``).
        zrefs/TF)r3   r   
has_commit)r?   r(   r"   r   r   r   _should_fetch   s    	
zGit._should_fetchc                 C   s   |j }|dusJ | ||\}}|durF||}|r<|nd|_|S t|sZtd| | ||sj|S | jt	dd||
 |d | j|dd}||}|S )z
        Resolve a revision to a new RevOptions object with the SHA1 of the
        branch, tag, or ref if found.

        Args:
          rev_options: a RevOptions object.
        Nz:Did not find branch or tag '%s', assuming revision or ref.fetchr9   r=   Z
FETCH_HEADr!   )Zarg_revr%   Zmake_newbranch_namer   loggerZwarningrW   r2   r	   to_argsget_revision)r?   r(   r'   r*   r"   r   Z	is_branchr   r   r   resolve_revision   s*    


zGit.resolve_revisionc                 C   s   |sdS |  ||kS )z
        Return whether the current commit hash equals the given name.

        Args:
          dest: the repository directory.
          name: a string name.
        F)r]   )r?   r(   namer   r   r   r$      s    	zGit.is_commit_id_equalc                 C   s   |  }td||t| | tdd|| |jr| |||}t|dd }|d u r| 	||jstdd|
 }| j||d n4| ||krd|}dd|d	|g}| j||d | | d S )
NzCloning %s%s to %sr   r9   rZ   checkoutrY   z	origin/{}z-bz--track)Z
to_displayr[   infor   r2   r	   r"   r^   getattrr$   r\   rD   rS   update_submodules)r&   r(   r'   r*   Zrev_displayrZ   cmd_argsZtrack_branchr   r   r   	fetch_new  s$    


zGit.fetch_newc                 C   sB   | j tdd||d tdd| }| j ||d | | d S )Nconfigzremote.origin.urlrY   r`   r9   )r2   r	   r\   rc   r&   r(   r'   r*   rd   r   r   r   switch$  s    
z
Git.switchc                 C   sr   |   tdkr$| jg d|d n| jddg|d | |||}tddd| }| j||d | | d S )Nz1.9.0)rX   r9   z--tagsrY   rX   r9   resetz--hard)r8   r7   r2   r^   r	   r\   rc   rg   r   r   r   update/  s    z
Git.updatec                 C   sv   | j g dddd|d}| }z|d }W n tyB   tY n0 |D ]}|drH|} q`qH|dd	 }| S )
z
        Return URL of the first remote encountered.

        Raises RemoteNotFoundError if the repository does not have a remote
        url configured.
        )rf   z--get-regexpzremote\..*\.urlr:   FTr<   r   zremote.origin.url rN   r;   )r2   
splitlines
IndexErrorr   r3   r5   r>   )r?   r@   stdoutZremotesZfound_remoteZremoter'   r   r   r   get_remote_url>  s$    


zGit.get_remote_urlc                 C   s>   z | j dddd| g|dd W n ty4   Y dS 0 dS dS )	zU
        Check if rev is a commit that is available in the local repository.
        	rev-parser9   z--verifyzsha^F)r=   log_failed_cmdTN)r2   r   )r?   r@   r"   r   r   r   rV   \  s    
zGit.has_commitNc                 C   s*   |d u rd}| j d|gdd|d}| S )Nr    ro   FTr-   r.   r=   )r2   r>   )r?   r@   r"   Zcurrent_revr   r   r   r]   l  s    zGit.get_revisionc                 C   sT   | j ddgdd|d }tj|s4tj||}tjtj|d}t||S )z~
        Return the path to setup.py, relative to the repo root.
        Return None if setup.py is in the repo root.
        ro   z	--git-dirFTrq   z..)r2   r>   osrI   isabsr6   abspathr   )r?   r@   Zgit_dirZ	repo_rootr   r   r   get_subdirectoryx  s    
zGit.get_subdirectoryc                    s   t |\}}}}}|dr|dt|d  }|t|ddd }|dd }	|d|	 t||	d ||||f }d|vrd|vsJ |d	d
}t	t
| |\}}
}|dd}nt	t
| |\}}
}||
|fS )a9  
        Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'.
        That's required because although they use SSH they sometimes don't
        work with a ssh:// scheme (e.g. GitHub). But we need a scheme for
        parsing. Hence we remove it again afterwards and return it as a stub.
        fileNrE   \+r;   z://zfile:zgit+z
git+ssh://zssh://r/   )urlsplitrH   r4   lstripurllib_requestZurl2pathnamereplacefind
urlunsplitsuperr   get_url_rev_and_auth)r?   r'   ZschemeZnetlocrI   ZqueryZfragmentinitial_slashesnewpathZ
after_plusr"   Z	user_pass	__class__r   r   r     s,    

zGit.get_url_rev_and_authc                 C   s0   t jt j|dsd S | jg d|d d S )Nz.gitmodules)Z	submodulerj   z--initz--recursiver9   rY   )rr   rI   existsr6   r2   )r?   r@   r   r   r   rc     s    zGit.update_submodulesc                    s|   t t| |}|r|S z| jddg|ddddd}W n2 tyV   td| Y d S  tyh   Y d S 0 tj	
|dS )	Nro   z--show-toplevelFTraise)r=   r-   r.   rK   rp   zKcould not determine if %s is under git control because git is not availablez
)r   r   get_repository_rootr2   r   r[   debugr   rr   rI   normpathrQ   )r?   r@   Zlocrr   r   r   r     s(    
zGit.get_repository_root)N)__name__
__module____qualname__r_   dirnameZ	repo_nameZschemesZunset_environZdefault_arg_revstaticmethodr#   r+   r8   classmethodrD   rF   r%   rW   r^   r$   re   rh   rj   rn   rV   r]   ru   r   rc   r   __classcell__r   r   r   r   r   /   sL   


-

,



!
r   ).Z
__future__r   Zloggingos.pathrr   reZpip._vendor.packaging.versionr   r7   Zpip._vendor.six.moves.urllibZurllib_parser   r{   Zpip._internal.exceptionsr   r   Zpip._internal.utils.miscr   r   Zpip._internal.utils.subprocessr	   Zpip._internal.utils.temp_dirr
   Zpip._internal.utils.typingr   Z pip._internal.vcs.versioncontrolr   r   r   r   typingr   r   r   r   r   ry   r~   Z	getLoggerr   r[   compiler   r   r   registerr   r   r   r   <module>   s4   

    