B
    `’»d¶\  ã               @   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 )z‘Create 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-hu9qqap1/pip/_internal/req/req_uninstall.pyÚ_script_names'   s    r-   c                s   t  ˆ ¡‡ fdd„ƒ}|S )Nc              ?   s6   t ƒ }x*ˆ | |ŽD ]}||kr| |¡ |V  qW d S )N)ÚsetÚadd)ÚargsÚkwÚseenÚitem)Úfnr+   r,   Úunique?   s
    
z_unique.<locals>.unique)Ú	functoolsÚwraps)r4   r5   r+   )r4   r,   Ú_unique=   s    r8   c             c   s–   t  t|  d¡ƒ¡}x||D ]t}tj | j|d ¡}|V  | d¡rtj 	|¡\}}|dd… }tj ||d ¡}|V  tj ||d ¡}|V  qW 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   z.pyNéýÿÿÿz.pycz.pyo)
ÚcsvÚreaderr   Úget_metadata_linesr!   r"   r#   ÚlocationÚendswithÚsplit)r%   ÚrÚrowr"   Údnr4   Úbaser+   r+   r,   Úuninstallation_pathsJ   s    

rE   c                sN   t jj‰tƒ }x:t| tdD ]*‰ t‡ ‡fdd„|D ƒƒ}|s| ˆ ¡ qW |S )zÈCompact 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>m   s   zcompact.<locals>.<genexpr>)r!   r"   rM   r.   ÚsortedrJ   Úanyr/   )ÚpathsÚshort_pathsÚshould_skipr+   )r"   rM   r,   Úcompactb   s    
rT   c       	         s   t dd„ | D ƒƒ}t|ƒ}ttdd„ | ¡ D ƒƒtd}tƒ }dd„ ‰x¤|D ]œ‰t‡fdd„|D ƒƒrhqLtƒ }tƒ }xPt ˆ¡D ]B\‰ }}| ‡ ‡‡fdd„|D ƒ¡ | ‡ ‡‡fd	d„|D ƒ¡ q€W || sL| 	|¡ | 
ˆtj ¡ qLW tt|j|ƒƒ|B S )
z«Returns 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 )N)r!   r"   Únormcase)rK   Úpr+   r+   r,   rN   }   s    z&compress_for_rename.<locals>.<genexpr>c             s   s   | ]}t j |¡d  V  qdS )r   N)r!   r"   r@   )rK   rV   r+   r+   r,   rN      s   )rF   c              W   s   t j t jj| Ž ¡S )N)r!   r"   rU   r#   )Úar+   r+   r,   Ú	norm_joinƒ   s    z&compress_for_rename.<locals>.norm_joinc             3   s    | ]}t j ˆ ¡ |¡V  qd S )N)r!   r"   rU   rH   )rK   Úw)Úrootr+   r,   rN   ˆ   s   c             3   s   | ]}ˆˆˆ |ƒV  qd S )Nr+   )rK   Úd)ÚdirnamerX   rZ   r+   r,   rN      s   c             3   s   | ]}ˆˆˆ |ƒV  qd S )Nr+   )rK   Úf)r\   rX   rZ   r+   r,   rN   ’   s   )Údictr.   rO   ÚvaluesrJ   rP   r!   ÚwalkÚupdateÚdifference_updater/   rM   ÚmapÚ__getitem__)	rQ   Úcase_mapÚ	remainingÚ	uncheckedÚ	wildcardsÚ	all_filesÚall_subdirsÚsubdirsÚfilesr+   )r\   rX   rZ   r,   Úcompress_for_renamev   s*    




rm   c             C   s  t | ƒ}t ƒ }t ƒ }t ƒ }xF|D ]>}| d¡r0q | d¡sBd|krT| tj |¡¡ | |¡ q W t ttjj|ƒƒ}t|ƒ}xt|D ]l}xft 	|¡D ]X\}}	}
xL|
D ]D}| d¡r²q¢tj 
||¡}tj |¡r¢tj |¡|kr¢| |¡ q¢W q’W q‚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 |d ¡’qS )rG   )r!   r"   r#   )rK   Úfolderr+   r+   r,   ú	<setcomp>Ê   s   z.compress_for_output_listing.<locals>.<setcomp>)r.   r?   r/   r!   r"   r\   rc   rU   rT   r`   r#   Úisfile)rQ   Úwill_removeÚ	will_skipÚfoldersrl   r"   Ú_normcased_filesrn   ÚdirpathÚ_ÚdirfilesÚfnameÚfile_r+   r+   r,   Úcompress_for_output_listingž   s0    





rz   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 )N)Ú
_save_dirsÚ_moves)Úselfr+   r+   r,   Ú__init__Ô   s    z StashedUninstallPathSet.__init__c             C   sD   y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"   rU   )r~   r"   Úsave_dirr+   r+   r,   Ú_get_directory_stashÝ   s    z,StashedUninstallPathSet._get_directory_stashc             C   s¼   t j |¡}t j |¡d }}d}xd||krfy| j| }P W n tk
rP   Y nX t j |¡| }}q$W t j |¡}tdd}|| j|< t j ||¡}|r¶|t jjkr¶t j 	|j|¡S |jS )z‚Stashes 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"   rU   r\   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   s0   x| j  ¡ D ]\}}| ¡  qW g | _i | _ dS )z0Commits the uninstall by removing stashed files.N)r|   ÚitemsÚcleanupr}   )r~   rv   rƒ   r+   r+   r,   Úcommit  s    zStashedUninstallPathSet.commitc             C   sÎ   x| j D ]}tjd|žŽ  qW x¢| j D ]˜\}}yTt d||¡ tj |¡sVtj |¡rbt |¡ ntj 	|¡rvt
|ƒ t||ƒ W q& tk
r¼ } zt d|¡ t d|¡ W dd}~X Y q&X q&W |  ¡  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"   rp   rŒ   Úunlinkr‹   r   r   r‚   Úerrorr“   )r~   rV   r   r"   Úexr+   r+   r,   Úrollback&  s    "z StashedUninstallPathSet.rollbackc             C   s
   t | jƒS )N)Ú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 )N)r.   rQ   Ú_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r„tr„|  	t|ƒ¡ d S )Né   z.py)r!   r"   r@   r#   r   rU   Úexistsr§   rQ   r/   r¤   Úsplitextr	   r   )r~   r"   rˆ   Útailr+   r+   r,   r/   T  s    
zUninstallPathSet.addc             C   sL   t |ƒ}|  |¡r<|| jkr*t|ƒ| j|< | j|  |¡ n| j |¡ d S )N)r   r§   r¥   ÚUninstallPthEntriesr/   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ƒ x |sP|  |¡r´| j}t	| j ƒ}x*t
t|ƒƒD ]}| |¡ t d|¡ qnW x| j ¡ D ]}| ¡  q˜W t d|¡ W d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)rQ   r•   r–   r%   Úproject_nameÚversionr
   Ú_allowed_to_proceedr¦   rm   rO   rT   r   r—   r¥   r_   Ú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   sH   |sd S t  | ¡ tƒ & xtt|ƒƒD ]}t  |¡ q(W W d Q R X d S )N)r•   r–   r
   rO   rT   )ÚmsgrQ   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¼   )rz   rQ   r.   r¤   rm   r   )r~   r¶   r»   rq   rr   r+   r+   r,   r³   ’  s    



z$UninstallPathSet._allowed_to_proceedc             C   sV   | j jst d| jj¡ dS t d| jj¡ | j  ¡  x| j 	¡ D ]}| ¡  qBW 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¥   r_   )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oœtj |j¡}t|jdd ƒ}|rº|j d	¡rº|j |¡sº| |j¡ | d
¡r"xÎ| d
¡ ¡ D ]&}tj tj |j|¡¡}	| |	¡ qöW n”| d¡rð| d¡rF| d¡‰ ng ‰ xj‡ fdd„| d¡ ¡ D ƒD ]J}
tj |j|
¡}	| |	¡ | |	d ¡ | |	d ¡ | |	d ¡ qhW n6|rÔtd |j¡ƒ‚n|j d¡r*| |j¡ tj |j¡d }tj tj |j¡d¡}| |d| ¡ nÆ|r^|j d¡r^x°t |ƒD ]}	| |	¡ qHW n’|ràt!|dƒ}tj "| #¡  $¡ ¡}W d Q R X ||jks°t%d ||j|j¡ƒ‚| |¡ tj tj |¡d¡}| ||j¡ nt &d||j¡ | d¡rd| 'd¡rdxZ| (d¡D ]L}t)|ƒr(t*}nt+}| tj ||¡¡ t,r| tj ||¡d ¡ qW g }|j-dd}x$| .¡ D ]}| /t0||dƒ¡ q~W |j-d d}x$| .¡ D ]}| /t0||d!ƒ¡ q°W x|D ]}| |¡ qÒW |S )"Nz1Not uninstalling %s at %s, outside environment %sc             S   s   h | ]}|r|’qS r+   r+   )rK   rV   r+   r+   r,   ro   Ñ  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+   )rK   rV   )Ú
namespacesr+   r,   ú
<listcomp>ú  s    z.UninstallPathSet.from_dist.<locals>.<listcomp>z.pyz.pycz.pyoz©Cannot 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-inforA   z;Egg-link {} does not match installed location of {} (at {})z)Not sure how to uninstall: %s - Check: %sÚscriptsz.batÚconsole_scripts)ÚgroupFÚgui_scriptsT)1r   r>   r   r•   r–   rF   ÚsysÚprefixÚ	sysconfigÚget_pathr   Úformatr   Úto_filenamer±   Úegg_infor!   r"   r©   ÚgetattrÚ	_providerr?   r/   Úhas_metadataÚget_metadataÚ
splitlinesÚnormpathr#   r   r@   r\   r¯   rE   ÚopenrU   Ú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§   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)r~   r­   r+   r+   r,   r   J  s    zUninstallPthEntries.__init__c             C   s<   t j |¡}tr,t j |¡d s,| dd¡}| j |¡ d S )Nr   ú\ú/)r!   r"   rU   r   Ú
splitdriveÚreplacerï   r/   )r~   r®   r+   r+   r,   r/   P  s    
zUninstallPthEntries.addc          	   C   s  t  d| j¡ tj | j¡s2t  d | j¡¡ d S t| jdƒ}| 	¡ }|| _
W d Q R X tdd„ |D ƒƒrpd}nd}|r¢|d  | d	¡¡s¢|d | d	¡ |d< xH| jD ]>}y$t  d
|¡ | ||  d	¡¡ W qª tk
ræ   Y qªX qªW t| jdƒ}| |¡ W d Q R X d S )NzRemoving pth entries from %s:z.Cannot remove entries from nonexistent file {}Úrbc             s   s   | ]}d |kV  qdS )s   
Nr+   )rK   Úliner+   r+   r,   rN   o  s    z-UninstallPthEntries.remove.<locals>.<genexpr>z
Ú
éÿÿÿÿzutf-8zRemoving entry: %sÚwb)r•   r—   rî   r!   r"   rp   ÚwarningrÊ   rÓ   Ú	readlinesrð   rP   r?   Úencoderï   r´   Ú
ValueErrorÚ
writelines)r~   ræ   ÚlinesÚendliner®   r+   r+   r,   r´   `  s,    

zUninstallPthEntries.removec          	   C   sR   | j d krt d| j¡ dS t d| j¡ t| jdƒ}| | j ¡ W d 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›     s    

zUninstallPthEntries.rollbackN)rž   rŸ   r    r   r/   r´   r›   r+   r+   r+   r,   r¬   I  s   r¬   )=Ú
__future__r   r;   r6   Ú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-   r8   rE   rT   rm   rz   Úobjectr{   r£   r¬   r+   r+   r+   r,   Ú<module>   s:   ,,
(3o  