U
    
HaC                     @   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  e!Z"e#dZ$e#dZ%e#d	ej&Z'd
d Z(G dd deZ)e*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[^:]*)
$c                 C   s   t t| S N)bool
HASH_REGEXmatch)sha r   9/tmp/pip-unpacked-wheel-tx790h60/pip/_internal/vcs/git.pylooks_like_hash4   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eedf dddZe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$ Zed2d&d'Zed(d) Ze fd*d+Zed,d- Ze fd.d/Ze	d0d1 Z   Z!S )3Gitgitz.gitclone)zgit+httpz	git+httpszgit+sshzgit+gitzgit+file)GIT_DIRGIT_WORK_TREEHEADc                 C   s   | gS r   r   revr   r   r   get_base_rev_argsE   s    zGit.get_base_rev_argsc                 C   sJ   |  t|\}}|jsdS | ||js.dS t| ||jd }| S )NFr   )get_url_rev_optionsr	   r!   is_commit_id_equalr   get_revision_sha)selfurldest_rev_optionsis_tag_or_branchr   r   r   is_immutable_rev_checkoutJ   s    zGit.is_immutable_rev_checkout.)returnc                 C   s:   | j dgddd}t|}|s$dS tdd | D S )NversionFT)show_stdoutstdout_onlyr   c                 s   s   | ]}t |V  qd S r   )int).0cr   r   r   	<genexpr>b   s     z&Git.get_git_version.<locals>.<genexpr>)run_commandGIT_VERSION_REGEXr   tuplegroups)r&   r.   r   r   r   r   get_git_version[   s      
zGit.get_git_versionc                 C   sD   dddg}| 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extra_ok_returncodesr/   r0   cwdzrefs/heads/N)r5   strip
startswithlen)clslocationargsoutputrefr   r   r   get_current_branchd   s    

zGit.get_current_branchc              	   C   s   | j d|g|dddd}i }| dD ]V}|d}|s>q*z|jdd	d
\}}W n" tk
rv   td|Y nX |||< q*d| }d| }	||}
|
dk	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/   r0   on_returncode
    )maxsplitzunexpected show-ref line: zrefs/remotes/origin/z
refs/tags/N)r5   r@   splitrstrip
ValueErrorget)rC   r(   r!   rF   refslineZref_shaZref_name
branch_reftag_refr   r   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)rA   r   
has_commit)rC   r(   r!   r   r   r   _should_fetch   s    

zGit._should_fetchc                 C   s   |j }|dk	st| ||\}}|dk	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.fetchr:   r?   
FETCH_HEADr    )arg_revAssertionErrorr%   make_newbranch_namer   loggerwarningrY   r5   r
   to_argsget_revision)rC   r(   r'   r*   r!   r   	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)rd   )rC   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 kr| 	||jstdd|
 }| j||d q| ||krd| }dd|d	|g}| j||d n| |}||}td
||j | | d S )NzCloning %s%s to %sr   r:   r`   checkoutr[   zorigin/z-bz--trackzResolved %s to commit %s)
to_displayra   infor   r5   r
   r!   rf   getattrr$   rc   rH   rd   r_   update_submodules)	r&   r(   r'   r*   rev_displayr`   cmd_argstrack_branchr   r   r   r   	fetch_new  s6      
    

zGit.fetch_newc                 C   sB   | j tdd||d tdd| }| j ||d | | d S )Nconfigzremote.origin.urlr[   rh   r:   )r5   r
   rc   rl   r&   r(   r'   r*   rn   r   r   r   switch%  s    
z
Git.switchc                 C   sp   |   dkr"| jdddg|d n| jddg|d | |||}tddd| }| j||d | | d S )N)r<   	   rZ   r:   z--tagsr[   resetz--hard)r9   r5   rf   r
   rc   rl   rr   r   r   r   update0  s    z
Git.updatec                 C   s   | j dddgddd|d}| }z|d }W n tk
rF   tY nX |D ]}|d	rL|} qdqL|d
d }| | S )z
        Return URL of the first remote encountered.

        Raises RemoteNotFoundError if the repository does not have a remote
        url configured.
        rq   z--get-regexpzremote\..*\.urlr;   FTr=   r   zremote.origin.url rM   r<   )r5   
splitlines
IndexErrorr   rA   rP   _git_remote_to_pip_urlr@   )rC   rD   stdoutremotesfound_remoteremoter'   r   r   r   get_remote_url?  s$    

zGit.get_remote_urlc                 C   sN   t d| r| S tj| r*t|  S t| }|rB|	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pathlibPurePathas_uri	SCP_REGEXexpandr   )r'   Z	scp_matchr   r   r   ry   ^  s    

zGit._git_remote_to_pip_urlc                 C   s@   z | j dddd| g|dd W n tk
r6   Y dS X dS dS )	zU
        Check if rev is a commit that is available in the local repository.
        	rev-parser:   z--verifyzsha^F)r?   log_failed_cmdTN)r5   r   )rC   rD   r!   r   r   r   rX   ~  s    
zGit.has_commitNc                 C   s*   |d krd}| j d|gdd|d}| S )Nr   r   FTr/   r0   r?   )r5   r@   )rC   rD   r!   current_revr   r   r   rd     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 Python project root, relative to the repo root.
        Return None if the project root is in the repo root.
        r   z	--git-dirFTr   z..)r5   r@   r   r   isabsjoinabspathr   )rC   rD   git_dir	repo_rootr   r   r   get_subdirectory  s    
zGit.get_subdirectoryc                    s   t |\}}}}}|dr|dt|d  }|tj|ddd }|dd }	|d|	 t	||	d ||||f }d|krd|kst
|d	d
}t |\}}
}|dd}n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.
        fileN/\+r<   z://zfile:zgit+z
git+ssh://zssh:// )urlsplitendswithrB   lstripurllibrequesturl2pathnamereplacefind
urlunsplitr^   superget_url_rev_and_auth)rC   r'   schemenetlocr   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t j|dsd S | jdddddg|d d S )Nz.gitmodules	submodulerv   z--initz--recursiver:   r[   )r   r   r   r   r5   )rC   rD   r   r   r   rl     s    zGit.update_submodulesc                    s|   t  |}|r|S z| jddg|ddddd}W n6 tk
rT   td| Y d S  tk
rh   Y d S X tj	|
dS )	Nr   z--show-toplevelFTraise)r?   r/   r0   rJ   r   zKcould not determine if %s is under git control because git is not availablez
)r   get_repository_rootr5   r   ra   debugr   r   r   normpathrQ   )rC   rD   locrr   r   r   r     s(    
zGit.get_repository_rootc                 C   s   dS )zNIn either https or ssh form, requirements must be prefixed with git+.
        Tr   )repo_urlr   r   r   should_add_vcs_url_prefix  s    zGit.should_add_vcs_url_prefix)N)"__name__
__module____qualname__rg   dirname	repo_nameschemesunset_environdefault_arg_revstaticmethodr"   r,   r   r1   r9   classmethodrH   r%   rY   rf   r$   rp   rs   rv   r~   ry   rX   rd   r   r   rl   r   r   __classcell__r   r   r   r   r   9   sR   
	

.

,
#



!
	r   )+loggingos.pathr   r   r   urllib.parser   urllib.requesttypingr   r   r   pip._internal.exceptionsr   r   pip._internal.utils.miscr   r   r	   pip._internal.utils.subprocessr
    pip._internal.vcs.versioncontrolr   r   r   r   r   r   r   parser   r   	getLoggerr   ra   compiler6   r   VERBOSEr   r   r   registerr   r   r   r   <module>   s4   $


	   D