U
    P^~S                     @   s  d Z ddlm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	 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mZmZ dd	lmZmZ dd
lmZ ddlmZ erddlm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+ ddlm,Z, ddlm-Z- e'e%e. e%e. f Z/dgZ0e1e2Z3dd Z4dddZ5dd Z6G dd de7Z8G dd de9Z:G dd de9Z;e; Z<G dd de9Z=dS ) z)Handles all VCS (version control) support    )absolute_importN)pkg_resources)parse)
BadCommand)samefile)ask_path_exists
backup_dirdisplay_pathhide_url
hide_valuermtree)call_subprocessmake_command)MYPY_CHECK_RUNNING)get_url_scheme)
AnyDictIterableListMappingOptionalTextTupleTypeUnion)SpinnerInterface)
HiddenText)CommandArgsvcsc                 C   s*   t | }|dkrdS |ddddgtj kS )z3
    Return true if the name looks like a URL.
    NFhttphttpsfileftp)r   r   all_schemes)namescheme r&   A/tmp/pip-install-220asx0h/pip/pip/_internal/vcs/versioncontrol.pyis_url0   s    r(   c                 C   s.   t |}d| ||}|r*|d|7 }|S )z
    Return the URL for a VCS requirement.

    Args:
      repo_url: the remote VCS url, with any needed VCS prefix (e.g. "git+").
      project_name: the (unescaped) project name.
    z{}@{}#egg={}z&subdirectory={})r   to_filenameformat)repo_urlrevproject_namesubdiregg_project_namereqr&   r&   r'   make_vcs_requirement_url;   s
    
r1   c                 C   s`   | }t jt j| dsD| }t j| } | |krtd| dS qt|| rRdS t j| |S )z
    Find the path to `setup.py` by searching up the filesystem from `location`.
    Return the path to `setup.py` relative to `repo_root`.
    Return None if `setup.py` is in `repo_root` or cannot be found.
    zsetup.pyzGCould not find setup.py for directory %s (tried all parent directories)N)	ospathexistsjoindirnameloggerwarningr   relpath)locationZ	repo_rootorig_locationlast_locationr&   r&   r'   !find_path_to_setup_from_repo_rootK   s    
r=   c                   @   s   e Zd ZdS )RemoteNotFoundErrorN)__name__
__module____qualname__r&   r&   r&   r'   r>   f   s   r>   c                   @   sF   e Zd ZdZdddZdd Zedd Zd	d
 Zdd Z	dd Z
dS )
RevOptionsz
    Encapsulates a VCS-specific revision to install, along with any VCS
    install options.

    Instances of this class should be treated as if immutable.
    Nc                 C   s(   |dkrg }|| _ || _|| _d| _dS )z
        Args:
          vc_class: a VersionControl subclass.
          rev: the name of the revision to install.
          extra_args: a list of extra options.
        N)
extra_argsr,   vc_classbranch_name)selfrD   r,   rC   r&   r&   r'   __init__s   s    zRevOptions.__init__c                 C   s   d | jj| jS )Nz<RevOptions {}: rev={!r}>)r*   rD   r$   r,   rF   r&   r&   r'   __repr__   s    zRevOptions.__repr__c                 C   s   | j d kr| jjS | j S N)r,   rD   default_arg_revrH   r&   r&   r'   arg_rev   s    
zRevOptions.arg_revc                 C   s0   g }| j }|dk	r"|| j|7 }|| j7 }|S )z<
        Return the VCS-specific command arguments.
        N)rL   rD   get_base_rev_argsrC   )rF   argsr,   r&   r&   r'   to_args   s    
zRevOptions.to_argsc                 C   s   | j s
dS d| j S )N z (to revision {}))r,   r*   rH   r&   r&   r'   
to_display   s    zRevOptions.to_displayc                 C   s   | j j|| jdS )z
        Make a copy of the current instance, but with a new rev.

        Args:
          rev: the name of the revision for the new object.
        rC   )rD   make_rev_optionsrC   )rF   r,   r&   r&   r'   make_new   s    zRevOptions.make_new)NN)r?   r@   rA   __doc__rG   rI   propertyrL   rO   rQ   rT   r&   r&   r&   r'   rB   j   s   
  

rB   c                       s|   e Zd Zi ZddddddgZ fddZd	d
 Zedd Zedd Z	edd Z
dd Zdd Zdd Zdd Z  ZS )
VcsSupportsshgithgbzrsftpsvnc                    s:   t j| j tt dd r(t j| j tt|   d S )Nuses_fragment)	urllib_parseuses_netlocextendschemesgetattrr^   superrW   rG   rH   	__class__r&   r'   rG      s    zVcsSupport.__init__c                 C   s
   | j  S rJ   )	_registry__iter__rH   r&   r&   r'   rh      s    zVcsSupport.__iter__c                 C   s   t | j S rJ   )listrg   valuesrH   r&   r&   r'   backends   s    zVcsSupport.backendsc                 C   s   dd | j D S )Nc                 S   s   g | ]
}|j qS r&   )r6   ).0backendr&   r&   r'   
<listcomp>   s     z'VcsSupport.dirnames.<locals>.<listcomp>)rk   rH   r&   r&   r'   dirnames   s    zVcsSupport.dirnamesc                 C   s    g }| j D ]}||j q
|S rJ   )rk   ra   rb   )rF   rb   rm   r&   r&   r'   r#      s    
zVcsSupport.all_schemesc                 C   sH   t |dstd|j d S |j| jkrD| | j|j< td|j d S )Nr$   zCannot register VCS %szRegistered VCS backend: %s)hasattrr7   r8   r?   r$   rg   debug)rF   clsr&   r&   r'   register   s    
zVcsSupport.registerc                 C   s   || j kr| j |= d S rJ   )rg   rF   r$   r&   r&   r'   
unregister   s    
zVcsSupport.unregisterc                 C   s6   | j  D ]&}||r
td||j |  S q
dS )zv
        Return a VersionControl object if a repository of that type is found
        at the given directory.
        zDetermine that %s uses VCS: %sN)rg   rj   controls_locationr7   rq   r$   )rF   r:   vcs_backendr&   r&   r'   get_backend_for_dir   s    
 
zVcsSupport.get_backend_for_dirc                 C   s   |  }| j|S )z9
        Return a VersionControl object or None.
        )lowerrg   getrt   r&   r&   r'   get_backend   s    zVcsSupport.get_backend)r?   r@   rA   rg   rb   rG   rh   rV   rk   ro   r#   rs   ru   rx   r{   __classcell__r&   r&   re   r'   rW      s   



	rW   c                	   @   s8  e Zd ZdZdZdZdZdZdZe	dd Z
e	dd Ze	dd	 Ze	d
d Zedd Ze	d8ddZe	dd Zdd Ze	dd Ze	dd Zedd Zdd Zedd Ze	dd Zd d! Zd"d# Zd$d% Ze	d&d' Zd(d) Zd*d+ Ze	d,d- Ze	d.d/ Z e	d9d2d3Z!e	d4d5 Z"e	d6d7 Z#dS ):VersionControlrP   r&   Nc                 C   s   |  d| j S )z
        Return whether the vcs prefix (e.g. "git+") should be added to a
        repository's remote url when used in a requirement.
        z{}:)ry   
startswithr*   r$   )rr   
remote_urlr&   r&   r'   should_add_vcs_url_prefix  s    z(VersionControl.should_add_vcs_url_prefixc                 C   s   dS )z~
        Return the path to setup.py, relative to the repo root.
        Return None if setup.py is in the repo root.
        Nr&   rr   r:   r&   r&   r'   get_subdirectory  s    zVersionControl.get_subdirectoryc                 C   s
   |  |S )zR
        Return the revision string that should be used in a requirement.
        )get_revision)rr   repo_dirr&   r&   r'   get_requirement_revision  s    z'VersionControl.get_requirement_revisionc                 C   sV   |  |}|dkrdS | |r.d| j|}| |}| |}t||||d}|S )aC  
        Return the requirement string to use to redownload the files
        currently at the given repository directory.

        Args:
          project_name: the (unescaped) project name.

        The return value has a form similar to the following:

            {repository_url}@{revision}#egg={project_name}
        Nz{}+{})r.   )get_remote_urlr   r*   r$   r   r   r1   )rr   r   r-   r+   revisionr.   r0   r&   r&   r'   get_src_requirement  s    



z"VersionControl.get_src_requirementc                 C   s   t dS )z
        Return the base revision arguments for a vcs command.

        Args:
          rev: the name of a revision to install.  Cannot be None.
        NNotImplementedError)r,   r&   r&   r'   rM   8  s    z VersionControl.get_base_rev_argsc                 C   s   t | ||dS )z
        Return a RevOptions object.

        Args:
          rev: the name of a revision to install.
          extra_args: a list of extra options.
        rR   )rB   )rr   r,   rC   r&   r&   r'   rS   B  s    
zVersionControl.make_rev_optionsc                 C   s&   t j|\}}|t jjp$t|S )zy
           posix absolute paths start with os.path.sep,
           win32 ones start with drive (like c:\folder)
        )r2   r3   
splitdriver~   sepbool)rr   repodrivetailr&   r&   r'   _is_local_repositoryN  s    z#VersionControl._is_local_repositoryc                 C   s   t dS )z
        Export the repository at the url to the destination location
        i.e. only download the files, without vcs informations

        :param url: the repository URL starting with a vcs prefix.
        Nr   rF   r:   urlr&   r&   r'   exportX  s    zVersionControl.exportc                 C   s   |dfS )aZ  
        Parse the repository URL's netloc, and return the new netloc to use
        along with auth information.

        Args:
          netloc: the original repository URL netloc.
          scheme: the repository URL's scheme without the vcs prefix.

        This is mainly for the Subversion class to override, so that auth
        information can be provided via the --username and --password options
        instead of through the URL.  For other subclasses like Git without
        such an option, auth information must stay in the URL.

        Returns: (netloc, (username, password)).
        )NNr&   )rr   netlocr%   r&   r&   r'   get_netloc_and_authb  s    z"VersionControl.get_netloc_and_authc           	      C   s   t |\}}}}}d|kr*td||ddd }| ||\}}d}d|krf|dd\}}t ||||df}|||fS )z
        Parse the repository URL to use, and return the URL, revision,
        and auth info to use.

        Returns: (url, rev, (username, password)).
        +zvSorry, {!r} is a malformed VCS url. The format is <vcs>+<protocol>://<url>, e.g. svn+http://myrepo/svn/MyApp#egg=MyApp   N@rP   )r_   urlsplit
ValueErrorr*   splitr   rsplit
urlunsplit)	rr   r   r%   r   r3   queryfrag	user_passr,   r&   r&   r'   get_url_rev_and_authu  s    	z#VersionControl.get_url_rev_and_authc                 C   s   g S )zM
        Return the RevOptions "extra arguments" to use in obtain().
        r&   )usernamepasswordr&   r&   r'   make_rev_args  s    zVersionControl.make_rev_argsc           
      C   sT   |  |j\}}}|\}}d}|dk	r.t|}| ||}| j||d}	t||	fS )z
        Return the URL and RevOptions object to use in obtain() and in
        some cases export(), as a tuple (url, rev_options).
        NrR   )r   secretr   r   rS   r
   )
rF   r   Z
secret_urlr,   r   r   Zsecret_passwordr   rC   rev_optionsr&   r&   r'   get_url_rev_options  s    z"VersionControl.get_url_rev_optionsc                 C   s   t | dS )zi
        Normalize a URL for comparison by unquoting it and removing any
        trailing slash.
        /)r_   unquoterstripr   r&   r&   r'   normalize_url  s    zVersionControl.normalize_urlc                 C   s   |  ||  |kS )zV
        Compare two repo URLs for identity, ignoring incidental differences.
        )r   )rr   url1url2r&   r&   r'   compare_urls  s    zVersionControl.compare_urlsc                 C   s   t dS )z
        Fetch a revision from a repository, in the case that this is the
        first fetch from the repository.

        Args:
          dest: the directory to fetch the repository to.
          rev_options: a RevOptions object.
        Nr   rF   destr   r   r&   r&   r'   	fetch_new  s    
zVersionControl.fetch_newc                 C   s   t dS )z}
        Switch the repo at ``dest`` to point to ``URL``.

        Args:
          rev_options: a RevOptions object.
        Nr   r   r&   r&   r'   switch  s    zVersionControl.switchc                 C   s   t dS )z
        Update an already-existing repo to the given ``rev_options``.

        Args:
          rev_options: a RevOptions object.
        Nr   r   r&   r&   r'   update  s    zVersionControl.updatec                 C   s   t dS )z
        Return whether the id of the current commit equals the given name.

        Args:
          dest: the repository directory.
          name: a string name.
        Nr   )rr   r   r$   r&   r&   r'   is_commit_id_equal  s    	z!VersionControl.is_commit_id_equalc           	      C   s  |  |\}}tj|s,| ||| dS | }| |r| |}| ||j	rt
d| j t|| | ||jst
dt|| j| | ||| n
t
d dS t
d| j| jt|| d}nt
d|| j| j d}t
d	| j| td
|d  |d }|dkr$td |dkrXt
dt| t| | ||| dS |dkrt|}t
dt|| t|| | ||| dS |dkrt
d| jt||| | ||| dS )a  
        Install or update in editable mode the package represented by this
        VersionControl object.

        :param dest: the repository directory in which to install or update.
        :param url: the repository URL starting with a vcs prefix.
        Nz)%s in %s exists, and has correct URL (%s)zUpdating %s %s%sz$Skipping because already up-to-date.z%s %s in %s exists with URL %s)z%(s)witch, (i)gnore, (w)ipe, (b)ackup )siwbz0Directory %s already exists, and is not a %s %s.)z(i)gnore, (w)ipe, (b)ackup )r   r   r   z+The plan is to install the %s repository %szWhat to do?  %sr   r   ar   zDeleting %sr   zBacking up %s to %sr   zSwitching %s %s to %s%s)r   r2   r3   r4   r   rQ   is_repository_directoryr   r   r   r7   rq   	repo_nametitler	   r   r,   infor   r8   r$   r   sysexitr   r   shutilmover   )	rF   r   r   r   rev_displayexisting_urlpromptresponsedest_dirr&   r&   r'   obtain  s    	






  
zVersionControl.obtainc                 C   s&   t j|rt| | j||d dS )z
        Clean up current location and download the url repository
        (and vcs infos) into location

        :param url: the repository URL starting with a vcs prefix.
        r   N)r2   r3   r4   r   r   r   r&   r&   r'   unpack?  s    zVersionControl.unpackc                 C   s   t dS )z
        Return the url used at location

        Raises RemoteNotFoundError if the repository does not have a remote
        url configured.
        Nr   r   r&   r&   r'   r   K  s    zVersionControl.get_remote_urlc                 C   s   t dS )zR
        Return the current commit id of the files at the given location.
        Nr   r   r&   r&   r'   r   U  s    zVersionControl.get_revisionTraisec
                 C   s|   t | jf| }z t|||||||| j||	d
W S  tk
rv }
 z(|
jtjkrdtd| j| jf n W 5 d}
~
X Y nX dS )z
        Run a VCS subcommand
        This is simply a wrapper around call_subprocess that adds the VCS
        command name, and checks that the VCS is available
        )on_returncodeextra_ok_returncodescommand_descextra_environunset_environspinnerlog_failed_cmdzCCannot find command %r - do you have %r installed and in your PATH?N)r   r$   r   r   OSErrorerrnoENOENTr   )rr   cmdshow_stdoutcwdr   r   r   r   r   r   er&   r&   r'   run_command\  s&    
zVersionControl.run_commandc                 C   s,   t d|| j| j tjtj|| jS )zL
        Return whether a directory path is a repository directory.
        zChecking in %s for %s (%s)...)r7   rq   r6   r$   r2   r3   r4   r5   )rr   r3   r&   r&   r'   r     s      z&VersionControl.is_repository_directoryc                 C   s
   |  |S )a6  
        Check if a location is controlled by the vcs.
        It is meant to be overridden to implement smarter detection
        mechanisms for specific vcs.

        This can do more than is_repository_directory() alone.  For example,
        the Git override checks that Git is actually available.
        )r   r   r&   r&   r'   rv     s    z VersionControl.controls_location)NN)TNr   NNNNT)$r?   r@   rA   r$   r6   r   rb   r   rK   classmethodr   r   r   r   staticmethodrM   rS   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rv   r&   r&   r&   r'   r}      sr   




	
	









]
	
        '
	r}   )N)>rU   
__future__r   r   loggingr2   r   r   pip._vendorr   pip._vendor.six.moves.urllibr   r_   pip._internal.exceptionsr   pip._internal.utils.compatr   pip._internal.utils.miscr   r   r	   r
   r   r   Zpip._internal.utils.subprocessr   r   pip._internal.utils.typingr   Zpip._internal.utils.urlsr   typingr   r   r   r   r   r   r   r   r   r   pip._internal.utils.uir   r   r   strZAuthInfo__all__	getLoggerr?   r7   r(   r1   r=   	Exceptionr>   objectrB   rW   r   r}   r&   r&   r&   r'   <module>   s<    0

HG