3
ûâdeŒE  ã               @   s  d dl Z d dlZd dlZd dlZd dlZd dlZd dl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 d dlmZmZmZmZmZmZmZ ejjZejjZe j e!ƒZ"ej#dƒZ$ej#dƒZ%ej#d	ej&ƒZ'e(e)d
œdd„Z*G dd„ deƒZ+ej,e+ƒ dS )é    N)ÚListÚOptionalÚTuple)Ú
BadCommandÚInstallationError)Ú
HiddenTextÚdisplay_pathÚhide_url)Úmake_command)ÚAuthInfoÚRemoteNotFoundErrorÚRemoteNotValidErrorÚ
RevOptionsÚVersionControlÚ(find_path_to_project_root_from_repo_rootÚvcsz(^git version (\d+)\.(\d+)(?:\.(\d+))?.*$z^[a-fA-F0-9]{40}$a/  ^
    # Optional user, e.g. 'git@'
    (\w+@)?
    # Server, e.g. 'github.com'.
    ([^/:]+):
    # The server-side path. e.g. 'user/project.git'. Must start with an
    # alphanumeric character so as not to be confusable with a Windows paths
    # like 'C:/foo/bar' or 'C:\foo\bar'.
    (\w[^:]*)
    $)ÚshaÚreturnc             C   s   t tj| ƒƒS )N)ÚboolÚ
HASH_REGEXÚmatch)r   © r   ú4/tmp/pip-build-red6nood/pip/pip/_internal/vcs/git.pyÚlooks_like_hash7   s    r   c                   s  e Zd ZdZdZdZd@ZdAZdZe	e
ee
 dœdd„ƒZe
e
edœdd„Zeedf dœdd„Zee
ee
 dœdd„ƒZee
e
eee
 ef dœdd„ƒZee
e
edœdd„ƒZee
eeedœdd „ƒZee
ee
 ed!œd"d#„ƒZe
eed$dœd%d&„Ze
eed$dœd'd(„Ze
eed$dœd)d*„Zee
e
dœd+d,„ƒZe	e
e
d-œd.d/„ƒZee
e
ed0œd1d2„ƒZ edBe
ee
 e
d0œd3d4„ƒZ!ee
ee
 dœd5d6„ƒZ"ee
ee
ee
 e#f d-œ‡ fd7d8„ƒZ$ee
d$dœd9d:„ƒZ%ee
ee
 dœ‡ fd;d<„ƒZ&e	e
ed=œd>d?„ƒZ'‡  Z(S )CÚGitÚgitz.gitÚcloneúgit+httpú	git+httpsúgit+sshúgit+gitúgit+fileÚGIT_DIRÚGIT_WORK_TREEÚHEAD)Úrevr   c             C   s   | gS )Nr   )r%   r   r   r   Úget_base_rev_argsK   s    zGit.get_base_rev_args)ÚurlÚdestr   c             C   sJ   | j t|ƒƒ\}}|jsdS | j||jƒs.dS t| j||jƒd ƒ}| S )NFr   )Zget_url_rev_optionsr	   r%   Úis_commit_id_equalr   Úget_revision_sha)Úselfr'   r(   Ú_Úrev_optionsZis_tag_or_branchr   r   r   Úis_immutable_rev_checkoutO   s    zGit.is_immutable_rev_checkout.)r   c             C   sF   | j dgddd�}tj|ƒ}|s0tjd|ƒ f S tdd„ |jƒ D ƒƒS )NÚversionFT)Úshow_stdoutÚstdout_onlyzCan't parse git version: %sc             s   s   | ]}t |ƒV  qd S )N)Úint)Ú.0Úcr   r   r   ú	<genexpr>c   s    z&Git.get_git_version.<locals>.<genexpr>)Úrun_commandÚGIT_VERSION_REGEXr   ÚloggerÚwarningÚtupleÚgroups)r+   r/   r   r   r   r   Úget_git_version]   s    
zGit.get_git_version)Úlocationr   c             C   sD   dddg}| j |d
dd|d�}|jƒ }|j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-refz-qr$   é   FT)Úextra_ok_returncodesr0   r1   Úcwdzrefs/heads/N)r>   )r6   ÚstripÚ
startswithÚlen)Úclsr=   ÚargsÚoutputÚrefr   r   r   Úget_current_branche   s    


zGit.get_current_branch)r(   r%   r   c             C   sÆ   | j d|g|dddd�}i }xh|jƒ jdƒD ]V}|jdƒ}|s@q,y|jdd	d
�\}}W n" tk
rx   td|›�ƒ‚Y nX |||< q,W d|› �}d|› �}	|j|ƒ}
|
dk	r´|
dfS |j|	ƒ}
|
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@   r0   r1   Úon_returncodeÚ
úú é   )Úmaxsplitzunexpected show-ref line: zrefs/remotes/origin/z
refs/tags/N)r6   rA   ÚsplitÚrstripÚ
ValueErrorÚget)rD   r(   r%   rF   ÚrefsÚlineZref_shaÚref_nameZ
branch_refZtag_refr   r   r   r   r*   ~   s.    




zGit.get_revision_shac             C   s.   |j dƒrdS t|ƒsdS | j||ƒ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)rB   r   Ú
has_commit)rD   r(   r%   r   r   r   Ú_should_fetch¬   s    	
zGit._should_fetch)r(   r'   r-   r   c             C   s¢   |j }|dk	st‚| j||ƒ\}}|dk	rF|j|ƒ}|r<|nd|_|S t|ƒsZtjd|ƒ | j||ƒsj|S | j	t
dd||jƒ ƒ|d� | j|dd�}|j|ƒ}|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.Úfetchz-q)r@   Z
FETCH_HEAD)r%   )Zarg_revÚAssertionErrorr*   Úmake_newÚbranch_namer   r8   r9   rX   r6   r
   Úto_argsÚget_revision)rD   r(   r'   r-   r%   r   Z	is_branchr   r   r   Úresolve_revisionÃ   s&    

zGit.resolve_revision)r(   Únamer   c             C   s   |sdS | j |ƒ|kS )z§
        Return whether the current commit hash equals the given name.

        Args:
          dest: the repository directory.
          name: a string name.
        F)r^   )rD   r(   r`   r   r   r   r)   ñ   s    	zGit.is_commit_id_equalNc       	      C   s   |j ƒ }tjd||t|ƒƒ | jƒ dkr@| jtddd||ƒƒ n| jtdd||ƒƒ |jrî| j|||ƒ}t	|dd ƒ}tj
d||ƒ |d kr¸| j||jƒsìtd	d|jƒ ƒ}| j||d
� n4| j|ƒ|krìd|› �}d	d|d|g}| j||d
� n| j|ƒ}|j|ƒ}tjd||jƒ | j|ƒ d S )NzCloning %s%s to %srN   é   r   z--filter=blob:nonez-qr\   zRev options %s, branch_name %sÚcheckout)r@   zorigin/z-bz--trackzResolved %s to commit %s)rN   ra   )Z
to_displayr8   Úinfor   r<   r6   r
   r%   r_   ÚgetattrÚdebugr)   r]   rH   r^   r[   Úupdate_submodules)	r+   r(   r'   r-   Úrev_displayr\   Úcmd_argsZtrack_branchr   r   r   r   Ú	fetch_new   sD    




zGit.fetch_newc             C   sB   | j tdd|ƒ|d� tdd|jƒ ƒ}| j ||d� | j|ƒ d S )NÚconfigzremote.origin.url)r@   rb   z-q)r6   r
   r]   rf   )r+   r(   r'   r-   rh   r   r   r   Úswitch7  s    
z
Git.switchc             C   sp   | j ƒ d	kr"| jdddg|d� n| jddg|d� | j|||ƒ}tddd|jƒ ƒ}| j||d� | j|ƒ d S )
Nr>   é	   rY   z-qz--tags)r@   Úresetz--hard)r>   rl   )r<   r6   r_   r
   r]   rf   )r+   r(   r'   r-   rh   r   r   r   ÚupdateA  s    z
Git.updatec             C   s‚   | j dddgddd|d�}|jƒ }y|d }W n tk
rF   t‚Y nX x|D ]}|jd	ƒrN|}P qNW |jd
ƒd }| j|jƒ ƒS )z¢
        Return URL of the first remote encountered.

        Raises RemoteNotFoundError if the repository does not have a remote
        url configured.
        rj   z--get-regexpzremote\..*\.urlr>   FT)r?   r0   r1   r@   r   zremote.origin.url rM   )r>   )r6   Ú
splitlinesÚ
IndexErrorr   rB   rP   Ú_git_remote_to_pip_urlrA   )rD   r=   ÚstdoutÚremotesÚfound_remoteÚremoter'   r   r   r   Úget_remote_urlO  s"    



zGit.get_remote_url)r'   r   c             C   sN   t jd| ƒr| S tjj| ƒr*tj| ƒjƒ S tj| ƒ}|rB|j	dƒS t
| ƒ‚dS )a8  
        Convert a remote url from what git uses to what pip accepts.

        There are 3 legal forms **url** may take:

            1. A fully qualified url: ssh://git@example.com/foo/bar.git
            2. A local project.git folder: /path/to/bare/repository.git
            3. SCP shorthand for form 1: git@example.com:foo/bar.git

        Form 1 is output as-is. Form 2 must be converted to URI and form 3 must
        be converted to form 1.

        See the corresponding test test_git_remote_url_to_pip() for examples of
        sample inputs/outputs.
        z\w+://zssh://\1\2/\3N)Úrer   ÚosÚpathÚexistsÚpathlibZPurePathZas_uriÚ	SCP_REGEXÚexpandr   )r'   Z	scp_matchr   r   r   rq   m  s    

zGit._git_remote_to_pip_url)r=   r%   r   c             C   s>   y | j dddd| g|dd� W n tk
r4   dS X dS dS )	zU
        Check if rev is a commit that is available in the local repository.
        z	rev-parsez-qz--verifyzsha^F)r@   Úlog_failed_cmdTN)r6   r   )rD   r=   r%   r   r   r   rW   Œ  s    zGit.has_commitc             C   s*   |d krd}| j d|gdd|d�}|jƒ S )Nr$   z	rev-parseFT)r0   r1   r@   )r6   rA   )rD   r=   r%   Úcurrent_revr   r   r   r^   œ  s    zGit.get_revisionc             C   sT   | j ddgdd|d�jƒ }tjj|ƒs4tjj||ƒ}tjjtjj|dƒƒ}t||ƒS )z‘
        Return the path to Python project root, relative to the repo root.
        Return None if the project root is in the repo root.
        z	rev-parsez	--git-dirFT)r0   r1   r@   z..)r6   rA   rx   ry   ÚisabsÚjoinÚabspathr   )rD   r=   Úgit_dirZ	repo_rootr   r   r   Úget_subdirectory¨  s    zGit.get_subdirectoryc                sâ   t |ƒ\}}}}}|jdƒr†|dt|jdƒƒ … }|tjj|ƒjddƒjdƒ }|jdƒd }	|d|	… t	||	d… ||||fƒ }d|krÆd|ksšt
‚|jd	d
ƒ}tƒ j|ƒ\}}
}|jddƒ}ntƒ j|ƒ\}}
}||
|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.
        ÚfileNú/ú\ú+r>   z://zfile:zgit+z
git+ssh://zssh://Ú )ÚurlsplitÚendswithrC   ÚlstripÚurllibÚrequestÚurl2pathnameÚreplaceÚfindÚ
urlunsplitrZ   ÚsuperÚget_url_rev_and_auth)rD   r'   ÚschemeÚnetlocry   ÚqueryÚfragmentÚinitial_slashesÚnewpathÚ
after_plusr%   Ú	user_pass)Ú	__class__r   r   r”   º  s     

zGit.get_url_rev_and_authc             C   s6   t jjt jj|dƒƒsd S | jdddddg|d� d S )Nz.gitmodulesÚ	submodulern   z--initz--recursivez-q)r@   )rx   ry   rz   r�   r6   )rD   r=   r   r   r   rf   Ù  s
    zGit.update_submodulesc                sx   t ƒ j|ƒ}|r|S y| jddg|ddddd�}W n2 tk
rR   tjd|ƒ d S  tk
rd   d S X tjj	|j
dƒƒS )	Nz	rev-parsez--show-toplevelFTÚraise)r@   r0   r1   rJ   r~   zKcould not determine if %s is under git control because git is not availablez
)r“   Úget_repository_rootr6   r   r8   re   r   rx   ry   ÚnormpathrQ   )rD   r=   ÚlocÚr)r�   r   r   r    â  s&    zGit.get_repository_root)Úrepo_urlr   c             C   s   dS )zEIn either https or ssh form, requirements must be prefixed with git+.Tr   )r¤   r   r   r   Úshould_add_vcs_url_prefixû  s    zGit.should_add_vcs_url_prefix)r   r   r   r    r!   )r"   r#   )N))Ú__name__Ú
__module__Ú__qualname__r`   ÚdirnameÚ	repo_nameÚschemesZunset_environZdefault_arg_revÚstaticmethodÚstrr   r&   r   r.   r   r2   r<   Úclassmethodr   rH   r*   rX   r   r   r_   r)   ri   rk   rn   rv   rq   rW   r^   r„   r   r”   rf   r    r¥   Ú__classcell__r   r   )r�   r   r   ;   s\        -+7
$r   )-ÚloggingÚos.pathrx   r{   rw   Úurllib.parser�   Úurllib.requestÚtypingr   r   r   Zpip._internal.exceptionsr   r   Zpip._internal.utils.miscr   r   r	   Zpip._internal.utils.subprocessr
   Z pip._internal.vcs.versioncontrolr   r   r   r   r   r   r   ÚparserŠ   r’   Ú	getLoggerr¦   r8   Úcompiler7   r   ÚVERBOSEr|   r­   r   r   r   Úregisterr   r   r   r   Ú<module>   s2   $



   I