U
    @vg9\                     @   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#r
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0e1Z2dd Z3dd Z4e4dd Z5dd Z6dd Z7dd Z8G dd de9Z:G dd de9Z;G d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   sl   t | rt}nt}tj||}|g}trh||d  ||d  |rZ||d  n||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_nameis_guibin_direxe_namepaths_to_remove r+   C/tmp/pip-unpacked-wheel-gw11q0wt/pip/_internal/req/req_uninstall.py_script_names'   s    r-   c                    s   t   fdd}|S )Nc                  ?   s2   t  } | |D ]}||kr|| |V  qd S N)setadd)argskwseenitemfnr+   r,   unique?   s
    
z_unique.<locals>.unique)	functoolswraps)r6   r7   r+   r5   r,   _unique=   s    r:   c                 c   s   t t| d}|D ]t}tj| j|d }|V  |drtj	|\}}|dd }tj||d }|V  tj||d }|V  qd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   .pyN.pyc.pyo)
csvreaderr   get_metadata_linesr!   r"   r#   locationendswithsplit)r%   rrowr"   dnr6   baser+   r+   r,   uninstallation_pathsJ   s    
rJ   c                    sJ   t jjt }t| tdD ]* t fdd|D }|s|  q|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   s:   | ]2}  |d o0 t|d  kV  qdS )*N)
startswithrstriplen).0	shortpathr"   sepr+   r,   	<genexpr>l   s   zcompact.<locals>.<genexpr>)r!   r"   rT   r/   sortedrP   anyr0   )pathsshort_pathsshould_skipr+   rS   r,   compactb   s    r[   c           	         s   t dd | D }t|}ttdd | D td}t }dd |D ]tfdd|D rfqJt }t }tD ]B\ }}| fdd|D  | fd	d|D  q||| sJ|	| |
tj  qJtt|j||B S )
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||fV  qd S r.   )r!   r"   normcaserQ   pr+   r+   r,   rU   }   s     z&compress_for_rename.<locals>.<genexpr>c                 s   s   | ]}t j|d  V  qdS )r   N)r!   r"   rE   r]   r+   r+   r,   rU      s   rK   c                  W   s   t jt jj|  S r.   )r!   r"   r\   r#   )ar+   r+   r,   	norm_join   s    z&compress_for_rename.<locals>.norm_joinc                 3   s    | ]}t j |V  qd S r.   )r!   r"   r\   rN   )rQ   w)rootr+   r,   rU      s   c                 3   s   | ]} |V  qd S r.   r+   )rQ   ddirnamer`   rb   r+   r,   rU      s   c                 3   s   | ]} |V  qd S r.   r+   )rQ   frd   r+   r,   rU      s   )dictr/   rV   valuesrP   rW   r!   walkupdatedifference_updater0   rT   map__getitem__)	rX   case_map	remaining	unchecked	wildcards	all_filesall_subdirssubdirsfilesr+   rd   r,   compress_for_renamev   s6    


rv   c                 C   s   t | }t  }t  }t  }|D ]>}|dr.q|ds@d|krR|tj| || qt ttjj|}t|}|D ]d}t	|D ]T\}}	}
|
D ]D}|drqtj
||}tj|rtj||kr|| qqq||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.
    r>   z__init__.py
.dist-infoc                 S   s   h | ]}t j|d qS )rM   )r!   r"   r#   )rQ   folderr+   r+   r,   	<setcomp>   s    z.compress_for_output_listing.<locals>.<setcomp>)r/   rD   r0   r!   r"   re   rl   r\   r[   ri   r#   isfile)rX   will_remove	will_skipfoldersru   r"   _normcased_filesrx   dirpath_dirfilesfnamefile_r+   r+   r,   compress_for_output_listing   s4    

r   c                   @   sL   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 r.   )
_save_dirs_movesselfr+   r+   r,   __init__   s    z StashedUninstallPathSet.__init__c                 C   sD   zt |}W n tk
r*   tdd}Y nX || jt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.	uninstallkind)r   OSErrorr   r   r!   r"   r\   )r   r"   save_dirr+   r+   r,   _get_directory_stash   s    z,StashedUninstallPathSet._get_directory_stashc                 C   s   t j|}t j|d }}d}||krfz| j| }W qW n tk
rP   Y nX t j|| }}q"t j|}tdd}|| j|< t j||}|r|t jjkrt 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.Nr   r   )
r!   r"   r\   re   r   KeyErrorr   relpathcurdirr#   )r   r"   headold_headr   r   r+   r+   r,   _get_file_stash   s"    


z'StashedUninstallPathSet._get_file_stashc                 C   sl   t j|ot j| }|r*| |}n
| |}| j||f |r^t j|r^t | 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islinkr   r   r   r$   rmdirr   )r   r"   path_is_dirnew_pathr+   r+   r,   stash  s    


zStashedUninstallPathSet.stashc                 C   s,   | j  D ]\}}|  q
g | _i | _ dS )z0Commits the uninstall by removing stashed files.N)r   itemscleanupr   )r   r   r   r+   r+   r,   commit  s    
zStashedUninstallPathSet.commitc                 C   s   | j D ]}tjd|  q| j D ]\}}zTtd|| tj|sPtj|r\t| ntj	|rpt
| t|| W q  tk
r } ztd| td| W 5 d}~X Y q X q |   dS )z2Undoes the uninstall by moving stashed files back.Moving to %s
 from %szReplacing %s from %szFailed to restore %szException: %sN)r   )r   loggerinfodebugr!   r"   rz   r   unlinkr   r   r   r   errorr   )r   r^   r   r"   exr+   r+   r,   rollback&  s    
 z StashedUninstallPathSet.rollbackc                 C   s
   t | jS r.   )boolr   r   r+   r+   r,   can_rollback:  s    z$StashedUninstallPathSet.can_rollbackN)__name__
__module____qualname____doc__r   r   r   r   r   r   propertyr   r+   r+   r+   r,   r      s   	r   c                   @   s^   e Zd ZdZdd Zdd Zdd Zdd	 Z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 r.   )r/   rX   _refusepthr%   r   _moved_paths)r   r%   r+   r+   r,   r   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   )r   r"   r+   r+   r,   
_permittedK  s    zUninstallPathSet._permittedc                 C   s   t j|\}}t jt|t j|}t j|s:d S | |rR| j	| n| j
	| t j|d dkrtr| 	t| d S )N   r<   )r!   r"   rE   r#   r   r\   existsr   rX   r0   r   splitextr	   r   )r   r"   r   tailr+   r+   r,   r0   T  s    
zUninstallPathSet.addc                 C   sL   t |}| |r<|| jkr*t|| j|< | j| | n| j| d S r.   )r   r   r   UninstallPthEntriesr0   r   )r   pth_fileentryr+   r+   r,   add_pthh  s    

zUninstallPathSet.add_pthFc              	   C   s   | j std| jj dS | jjd | jj }td| t p |sP| |r| j}t	| j }t
t|D ]}|| td| ql| j D ]}|  qtd| W 5 Q R X d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)rX   r   r   r%   project_nameversionr
   _allowed_to_proceedr   rv   rV   r[   r   r   r   rh   remove)r   auto_confirmverbosedist_name_versionmoved
for_renamer"   r   r+   r+   r,   r   r  s&    


zUninstallPathSet.removec                 C   sn   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   sD   |sd S t |  t " tt|D ]}t | q&W 5 Q R X d S r.   )r   r   r
   rV   r[   )msgrX   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nr   )r   rX   r/   r   rv   r   )r   r   r   r{   r|   r+   r+   r,   r     s    



z$UninstallPathSet._allowed_to_proceedc                 C   sR   | j jstd| jj dS td| jj | j   | j	 D ]}|  q@d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   rh   )r   r   r+   r+   r,   r     s    
zUninstallPathSet.rollbackc                 C   s   | j   dS )z?Remove temporary save dir: rollback will no longer be possible.N)r   r   r   r+   r+   r,   r     s    zUninstallPathSet.commitc              	      s  t |j}t|s.td|j|tj | |S |dd t	dt	dhD krhtd|j| | |S | |}t
|}dt|j}|jotj|j}t|jdd }|r|jd	r|j|s||j |d
r|d
 D ]&}tjtj|j|}	||	 qn|dr|drB|d ng   fdd|d D D ]J}
tj|j|
}	||	 ||	d  ||	d  ||	d  qbn2|rtd|jn|jdr"||j tj|jd }tjtj|jd}||d|  n|rR|jdrRt |D ]}	||	 q>n|rt!|d}tj"|# $ }W 5 Q R X ||jkst%d||j|jf || tjtj|d}|||j nt&d||j |drT|'drT|(dD ]L}t)|rt*}nt+}|tj|| t,r|tj||d  qg }|j-dd}|. D ]}|/t0||d ql|j-d d}|. D ]}|/t0||d! q|D ]}|| q|S )"Nz1Not uninstalling %s at %s, outside environment %sc                 S   s   h | ]}|r|qS r+   r+   r]   r+   r+   r,   ry     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S r+   r+   r]   
namespacesr+   r,   
<listcomp>  s    z.UninstallPathSet.from_dist.<locals>.<listcomp>r<   r>   r?   zCannot 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./rw   rF   z;Egg-link %s does not match installed location of %s (at %s)z)Not sure how to uninstall: %s - Check: %sscriptsz.batconsole_scripts)groupFgui_scriptsT)1r   rC   r   r   r   rL   sysprefix	sysconfigget_pathr   formatr   to_filenamer   egg_infor!   r"   r   getattr	_providerrD   r0   has_metadataget_metadata
splitlinesnormpathr#   r   rE   re   r   rJ   openr\   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(   _scripts_to_remover   namer   sr+   r   r,   	from_dist  s    







 
zUninstallPathSet.from_distN)FF)r   r   r   r   r   r   r0   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   s0   t j|std| || _t | _d | _d S )Nz.Cannot remove entries from nonexistent file %s)r!   r"   rz   r   filer/   entries_saved_lines)r   r   r+   r+   r,   r   I  s    zUninstallPthEntries.__init__c                 C   s<   t j|}tr,t j|d s,|dd}| j| d S )Nr   \/)r!   r"   r\   r   
splitdrivereplacer   r0   )r   r   r+   r+   r,   r0   S  s    
zUninstallPthEntries.addc              	   C   s   t d| j t| jd}| }|| _W 5 Q R X tdd |D rLd}nd}|r~|d |ds~|d |d |d< | j	D ]>}z$t d	| |
|| d W q tk
r   Y qX qt| jd
}|| W 5 Q R X d S )NzRemoving pth entries from %s:rbc                 s   s   | ]}d |kV  qdS )s   
Nr+   )rQ   liner+   r+   r,   rU   j  s     z-UninstallPthEntries.remove.<locals>.<genexpr>z

zutf-8zRemoving entry: %swb)r   r   r   r   	readlinesr   rW   rD   encoder   r   
ValueError
writelines)r   r   linesendliner   r+   r+   r,   r   c  s"    
zUninstallPthEntries.removec              	   C   sR   | j d krtd| j dS td| j t| jd}|| j  W 5 Q R X d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
  )r   r   r+   r+   r,   r   z  s    
 zUninstallPthEntries.rollbackN)r   r   r   r   r0   r   r   r+   r+   r+   r,   r   H  s   
r   )=
__future__r   r@   r8   loggingr!   r   r   pip._vendorr   pip._internal.exceptionsr   pip._internal.locationsr   r   pip._internal.utils.compatr   r   r	   pip._internal.utils.loggingr
   pip._internal.utils.miscr   r   r   r   r   r   r   r   r   pip._internal.utils.temp_dirr   r   pip._internal.utils.typingr   typingr   r   r   r   r   r   r   r   r   Zpip._vendor.pkg_resourcesr    	getLoggerr   r   r-   r:   rJ   r[   rv   r   objectr   r   r   r+   r+   r+   r,   <module>   s<   ,,

(3o  
