
0c@_\                 @   s  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 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 m Z d  d l m Z d  d l m Z m Z m Z m Z m Z m Z m Z m Z m Z d  d	 l m  Z  m! Z! d  d
 l" m# Z# e# rvd  d l$ m% Z% m& Z& m' Z' m( Z( m) Z) m* Z* m+ Z+ m, Z, m- Z- d  d l. m/ Z/ e j0 e1  Z2 d d   Z3 d d   Z4 e4 d d    Z5 d d   Z6 d d   Z7 d d   Z8 Gd d   d e9  Z: Gd d   d e9  Z; Gd d   d e9  Z< d S)    )absolute_importN)pkg_resources)UninstallationError)bin_pybin_user)WINDOWScache_from_sourceuses_pycache)
indent_log)	FakeFileaskdist_in_usersitedist_is_localegg_link_pathis_localnormalize_pathrenamesrmtree)AdjacentTempDirectoryTempDirectory)MYPY_CHECK_RUNNING)	AnyCallableDictIterableIteratorListOptionalSetTuple)Distributionc             C   s   t  |   r t } n t } t j j | |  } | g } t r | j | d  | j | d  | r{ | j | d  n | j | d  | S)zCreate the fully qualified name of the files created by
    {console,gui}_scripts for the given ``dist``.
    Returns the list of file names
    z.exez.exe.manifestz-script.pywz
-script.py)r   r   r   ospathjoinr   append)distscript_nameZis_guibin_dirZexe_namepaths_to_remove r)   >/tmp/pip-build-jynh7p1z/pip/pip/_internal/req/req_uninstall.py_script_names'   s    		r+   c                s%   t  j      f d d    } | S)Nc              ?   sE   t    } x5   |  |   D]$ } | | k r | j |  | Vq Wd  S)N)setadd)argskwseenitem)fnr)   r*   unique?   s
    	z_unique.<locals>.unique)	functoolswraps)r2   r3   r)   )r2   r*   _unique=   s    !r6   c             c   s   t  j t |  j d    } x | D] } t j j |  j | d  } | V| j d  r% t j j	 |  \ } } | d d  } t j j | | d  } | Vt j j | | d  } | Vq% Wd S)	a  
    Yield all the uninstallation paths for dist based on RECORD-without-.py[co]

    Yield paths to all the files in RECORD. For each .py file in RECORD, add
    the .pyc and .pyo in the same directory.

    UninstallPathSet.add() takes care of the __pycache__ .py[co].
    RECORDr   z.pyN   z.pycz.pyo)
csvreaderr   get_metadata_linesr!   r"   r#   locationendswithsplit)r%   rrowr"   dnr2   baser)   r)   r*   uninstallation_pathsJ   s    rD   c                sk   t  j j  t   } xO t |  d t D];   t    f d d   | D  } | s( | j    q( W| S)zCompact a path set to contain the minimal number of paths
    necessary to contain all paths in the set. If /a/path/ and
    /a/path/to/a/file.txt are both in the set, leave only the
    shorter path.keyc             3   sO   |  ]E }   j  | j d    oF   t | j d   j     k Vq d S)*N)
startswithrstriplen).0	shortpath)r"   sepr)   r*   	<genexpr>m   s   zcompact.<locals>.<genexpr>)r!   r"   rL   r,   sortedrI   anyr-   )pathsshort_pathsZshould_skipr)   )r"   rL   r*   compactb   s    	rR   c       	         s^  t  d d   |  D  } t |  } t t d d   | j   D  d t } t   } d d    x | D]  t  f d d   | D  r ql t   } t   } xl t j   D][ \   } } | j     f d d   | D  | j     f d	 d   | D  q W| | sl | j	 |  | j
  t j  ql Wt t | j |   | BS)
zReturns a set containing the paths that need to be renamed.

    This set may include directories when the original sequence of paths
    included every file on disk.
    c             s   s'   |  ] } t  j j |  | f Vq d  S)N)r!   r"   normcase)rJ   pr)   r)   r*   rM   }   s    z&compress_for_rename.<locals>.<genexpr>c             s   s%   |  ] } t  j j |  d  Vq d S)r   N)r!   r"   r?   )rJ   rT   r)   r)   r*   rM      s   rE   c              W   s   t  j j t  j j |     S)N)r!   r"   rS   r#   )ar)   r)   r*   	norm_join   s    z&compress_for_rename.<locals>.norm_joinc             3   s*   |  ]  } t  j j    j |  Vq d  S)N)r!   r"   rS   rG   )rJ   w)rootr)   r*   rM      s   c             3   s!   |  ] }     |  Vq d  S)Nr)   )rJ   d)dirnamerV   rX   r)   r*   rM      s   c             3   s!   |  ] }     |  Vq d  S)Nr)   )rJ   f)rZ   rV   rX   r)   r*   rM      s   )dictr,   rN   valuesrI   rO   r!   walkupdatedifference_updater-   rL   map__getitem__)	rP   Zcase_map	remainingZ	unchecked	wildcardsZ	all_filesZall_subdirssubdirsfilesr)   )rZ   rV   rX   r*   compress_for_renamev   s*    			
rg   c             C   sv  t  |   } t    } t    } t    } xa | D]Y } | j d  rF q. | j d  sa d | k rz | j t j j |   | j |  q. Wt  t t j j |   } t |  } x | D] } x t j	 |  D]~ \ } }	 }
 xl |
 D]d } | j d  r q t j j
 | |  } t j j |  r t j j |  | k r | j |  q Wq Wq W| d d   | D B} | | f S)as  Returns a tuple of 2 sets of which paths to display to user

    The first set contains paths that would be deleted. Files of a package
    are not added and the top-level directory of the package has a '*' added
    at the end - to signify that all it's contents are removed.

    The second set contains files that would have been skipped in the above
    folders.
    z.pycz__init__.pyz
.dist-infoc             S   s%   h  |  ] } t  j j | d    q S)rF   )r!   r"   r#   )rJ   folderr)   r)   r*   	<setcomp>   s   	z.compress_for_output_listing.<locals>.<setcomp>)r,   r>   r-   r!   r"   rZ   ra   rS   rR   r^   r#   isfile)rP   will_remove	will_skipZfoldersrf   r"   Z_normcased_filesrh   dirpath_ZdirfilesfnameZfile_r)   r)   r*   compress_for_output_listing   s0    			rp   c               @   sp   e  Z d  Z d Z d d   Z d d   Z d d   Z d d	   Z d
 d   Z d d   Z	 e
 d d    Z d S)StashedUninstallPathSetzWA set of file rename operations to stash files while
    tentatively uninstalling them.c             C   s   i  |  _  g  |  _ d  S)N)
_save_dirs_moves)selfr)   r)   r*   __init__   s    	z StashedUninstallPathSet.__init__c             C   sT   y t  |  } Wn! t k
 r3 t d d  } Yn X| |  j t j j |  <| j S)zStashes a directory.

        Directories are stashed adjacent to their original location if
        possible, or else moved/copied into the user's temp dir.kind	uninstall)r   OSErrorr   rr   r!   r"   rS   )rt   r"   save_dirr)   r)   r*   _get_directory_stash   s    z,StashedUninstallPathSet._get_directory_stashc             C   s   t  j j |  } t  j j |  d } } d } x~ | | k r y |  j | } PWn t k
 rf Yn Xt  j j |  | } } q4 Wt  j j |  } t d d  } | |  j | <t  j j | |  } | r | t  j j k r t  j j	 | j |  S| j S)zStashes a file.

        If no root has been provided, one will be created for the directory
        in the user's temp directory.Nrv   rw   )
r!   r"   rS   rZ   rr   KeyErrorr   relpathcurdirr#   )rt   r"   headZold_headry   r|   r)   r)   r*   _get_file_stash   s"    z'StashedUninstallPathSet._get_file_stashc             C   s   t  j j |  o" t  j j |  } | r= |  j |  } n |  j |  } |  j j | | f  | r t  j j |  r t  j |  t	 | |  | S)zStashes the directory or file and returns its new location.
        Handle symlinks as files to avoid modifying the symlink targets.
        )
r!   r"   isdirislinkrz   r   rs   r$   rmdirr   )rt   r"   Zpath_is_dirnew_pathr)   r)   r*   stash  s    %zStashedUninstallPathSet.stashc             C   s@   x' |  j  j   D] \ } } | j   q Wg  |  _ i  |  _  d S)z0Commits the uninstall by removing stashed files.N)rr   itemscleanuprs   )rt   rn   ry   r)   r)   r*   commit  s    	zStashedUninstallPathSet.commitc             C   s  x! |  j  D] } t j d |  q
 Wx |  j  D] \ } } yt t j d | |  t j j |  st t j j |  r t j |  n t j j	 |  r t
 |  t | |  Wq. t k
 r } z% t j d |  t j d |  WYd d } ~ Xq. Xq. W|  j   d S)z2Undoes the uninstall by moving stashed files back.zMoving to %s
 from %szReplacing %s from %szFailed to restore %szException: %sN)rs   loggerinfodebugr!   r"   rj   r   unlinkr   r   r   rx   errorr   )rt   rT   r   r"   exr)   r)   r*   rollback&  s    $
'z StashedUninstallPathSet.rollbackc             C   s   t  |  j  S)N)boolrs   )rt   r)   r)   r*   can_rollback:  s    z$StashedUninstallPathSet.can_rollbackN)__name__
__module____qualname____doc__ru   rz   r   r   r   r   propertyr   r)   r)   r)   r*   rq      s   	rq   c               @   s   e  Z d  Z d Z d d   Z d d   Z d d   Z d d	   Z d
 d
 d d  Z d d   Z	 d d   Z
 d d   Z e d d    Z d S)UninstallPathSetzMA set of file paths to be removed in the uninstallation of a
    requirement.c             C   s:   t    |  _ t    |  _ i  |  _ | |  _ t   |  _ d  S)N)r,   rP   _refusepthr%   rq   _moved_paths)rt   r%   r)   r)   r*   ru   C  s
    		zUninstallPathSet.__init__c             C   s
   t  |  S)zs
        Return True if the given path is one we are permitted to
        remove/modify, False otherwise.

        )r   )rt   r"   r)   r)   r*   
_permittedK  s    zUninstallPathSet._permittedc             C   s   t  j j |  \ } } t  j j t |  t  j j |   } t  j j |  sU d  S|  j |  rw |  j j	 |  n |  j
 j	 |  t  j j |  d d k r t r |  j	 t |   d  S)N   z.py)r!   r"   r?   r#   r   rS   existsr   rP   r-   r   splitextr	   r   )rt   r"   r~   tailr)   r)   r*   r-   T  s    '"zUninstallPathSet.addc             C   sh   t  |  } |  j |  rT | |  j k r= t |  |  j | <|  j | j |  n |  j j |  d  S)N)r   r   r   UninstallPthEntriesr-   r   )rt   pth_fileentryr)   r)   r*   add_pthh  s    zUninstallPathSet.add_pthFc             C   s   |  j  s# t j d |  j j  d S|  j j d |  j j } t j d |  t    | sl |  j |  r |  j } t	 |  j   } x7 t
 t |   D]# } | j |  t j d |  q Wx! |  j j   D] } | j   q Wt j d |  Wd QRXd S)z[Remove paths in ``self.paths`` with confirmation (unless
        ``auto_confirm`` is True).z7Can't uninstall '%s'. No files were found to uninstall.N-zUninstalling %s:zRemoving file or directory %szSuccessfully uninstalled %s)rP   r   r   r%   project_nameversionr
   _allowed_to_proceedr   rg   rN   rR   r   r   r   r]   remove)rt   auto_confirmverboseZdist_name_versionmovedZ
for_renamer"   r   r)   r)   r*   r   r  s"    	
	zUninstallPathSet.removec             C   s   d d   } | s* t  |  j  \ } } n t |  j  } t   } | d |  | d |  | d |  j  | r | d t |  j   t d d
  d k S)zIDisplay which files would be deleted and prompt for confirmation
        c          
   S   sV   | s
 d  St  j |   t   / x' t t |   D] } t  j |  q4 WWd  QRXd  S)N)r   r   r
   rN   rR   )msgrP   r"   r)   r)   r*   _display  s    
z6UninstallPathSet._allowed_to_proceed.<locals>._displayzWould remove:z+Would not remove (might be manually added):z%Would not remove (outside of prefix):zWill actually move:zProceed (y/n)? yn)r   r   )rp   rP   r,   r   rg   r   )rt   r   r   rk   rl   r)   r)   r*   r     s    
	z$UninstallPathSet._allowed_to_proceedc             C   sq   |  j  j s& t j d |  j j  d St j d |  j j  |  j  j   x! |  j j	   D] } | j   qY Wd S)z1Rollback the changes previously made by remove().z'Can't roll back %s; was not uninstalledNzRolling back uninstall of %s)
r   r   r   r   r%   r   r   r   r   r]   )rt   r   r)   r)   r*   r     s    zUninstallPathSet.rollbackc             C   s   |  j  j   d S)z?Remove temporary save dir: rollback will no longer be possible.N)r   r   )rt   r)   r)   r*   r     s    zUninstallPathSet.commitc                s8  t  | j  } t |  sA t j d | j | t j  |  |  S| d d   t j	 d  t j	 d  h D k r t j d | j |  |  |  S|  |  } t
 |  } d j t j | j   } | j o t j j | j  } t | j d d   } | rZ| j j d	  rZ| j j |  rZ| j | j  | j d
  rx| j d
  j   D]7 } t j j t j j | j |   }	 | j |	  qXWq| j d  r| j d  r| j d    n g    x(  f d d   | j d  j   D D]^ }
 t j j | j |
  }	 | j |	  | j |	 d  | j |	 d  | j |	 d  qWn| r{t d j | j    n|| j j d  r| j | j  t j j | j  d } t j j t j j | j  d  } | j | d |  n| r0| j j d  r0x t  |  D] }	 | j |	  qWn | rt! | d  % } t j j" | j#   j$    } Wd  QRX| | j k st% d j | | j | j    | j |  t j j t j j |  d  } | j | | j  n t j& d | | j  | j d  r| j' d  rxt | j( d  D]c } t) |  r@t* } n t+ } | j t j j | |   t, r%| j t j j | |  d  q%Wg  } | j- d d  } x- | j.   D] } | j/ t0 | | d   qW| j- d d   } x- | j.   D] } | j/ t0 | | d!   qWx | D] } | j |  qW| S)"Nz1Not uninstalling %s at %s, outside environment %sc             S   s   h  |  ] } | r |  q Sr)   r)   )rJ   rT   r)   r)   r*   ri     s   	 z-UninstallPathSet.from_dist.<locals>.<setcomp>stdlib
platstdlibz<Not uninstalling %s at %s, as it is in the standard library.z{}.egg-infor"   z	.egg-infozinstalled-files.txtztop_level.txtznamespace_packages.txtc                s(   g  |  ] } | r |   k r |  q Sr)   r)   )rJ   rT   )
namespacesr)   r*   
<listcomp>  s   	 z.UninstallPathSet.from_dist.<locals>.<listcomp>z.pyz.pycz.pyozCannot uninstall {!r}. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.z.eggr   zeasy-install.pthz./z
.dist-infor@   z;Egg-link {} does not match installed location of {} (at {})z)Not sure how to uninstall: %s - Check: %sscriptsz.batgroupconsole_scriptsFgui_scriptsT)1r   r=   r   r   r   rE   sysprefix	sysconfigget_pathr   formatr   to_filenamer   egg_infor!   r"   r   getattr	_providerr>   r-   has_metadataget_metadata
splitlinesnormpathr#   r   r?   rZ   r   rD   openrS   readlinestripAssertionErrorr   metadata_isdirmetadata_listdirr   r   r   r   get_entry_mapkeysextendr+   )clsr%   	dist_pathr(   develop_egg_linkdevelop_egg_link_egg_infoegg_info_existsdistutils_egg_infoinstalled_filer"   top_level_pkgeasy_install_eggeasy_install_pthfhlink_pointerscriptr'   Z_scripts_to_remover   namer   sr)   )r   r*   	from_dist  s    


			%		$zUninstallPathSet.from_distN)r   r   r   r   ru   r   r-   r   r   r   r   r   classmethodr   r)   r)   r)   r*   r   @  s   	
 r   c               @   s@   e  Z d  Z d d   Z d d   Z d d   Z d d   Z d	 S)
r   c             C   s"   | |  _  t   |  _ d  |  _ d  S)N)filer,   entries_saved_lines)rt   r   r)   r)   r*   ru   J  s    	zUninstallPthEntries.__init__c             C   sU   t  j j |  } t rA t  j j |  d rA | j d d  } |  j j |  d  S)Nr   \/)r!   r"   rS   r   
splitdrivereplacer   r-   )rt   r   r)   r)   r*   r-   P  s    
zUninstallPthEntries.addc             C   sZ  t  j d |  j  t j j |  j  s? t  j d |  j  d  St |  j d   } | j   } | |  _	 Wd  QRXt
 d d   | D  r d } n d } | r | d j | j d	   r | d | j d	  | d <xT |  j D]I } y. t  j d
 |  | j | | j d	   Wq t k
 r(Yq Xq Wt |  j d   } | j |  Wd  QRXd  S)NzRemoving pth entries from %s:z.Cannot remove entries from nonexistent file %srbc             s   s   |  ] } d  | k Vq d S)s   
Nr)   )rJ   liner)   r)   r*   rM   n  s    z-UninstallPthEntries.remove.<locals>.<genexpr>z

r   zutf-8zRemoving entry: %swbr   r   )r   r   r   r!   r"   rj   warningr   	readlinesr   rO   r>   encoder   r   
ValueError
writelines)rt   r   linesendliner   r)   r)   r*   r   `  s*    	#	zUninstallPthEntries.removec          	   C   si   |  j  d  k r& t j d |  j  d St j d |  j  t |  j d   } | j |  j   Wd  QRXd S)Nz.Cannot roll back changes to %s, none were madeFz!Rolling %s back to previous stater   T)r   r   r   r   r   r   r   )rt   r   r)   r)   r*   r   ~  s    zUninstallPthEntries.rollbackN)r   r   r   ru   r-   r   r   r)   r)   r)   r*   r   I  s   r   )=
__future__r   r:   r4   loggingr!   r   r   Zpip._vendorr   Zpip._internal.exceptionsr   Zpip._internal.locationsr   r   Zpip._internal.utils.compatr   r   r	   Zpip._internal.utils.loggingr
   Zpip._internal.utils.miscr   r   r   r   r   r   r   r   r   Zpip._internal.utils.temp_dirr   r   Zpip._internal.utils.typingr   Ztypingr   r   r   r   r   r   r   r   r   Zpip._vendor.pkg_resourcesr    	getLoggerr   r   r+   r6   rD   rR   rg   rp   objectrq   r   r   r)   r)   r)   r*   <module>   s8   @@(3o 
