3
ûâdeÄ\  ã               @   sÒ  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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 d dlmZm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$m%Z%m&Z&m'Z'm(Z( d dl)m*Z*m+Z+ ee,ƒZ-ee.e/ee. dœdd„Z0e	dee f e	dee f dœdd„Z1e1eee. dœdd„ƒZ2ee. ee. dœdd„Z3ee. ee. dœdd„Z4ee. eee. ee. f dœdd„Z5G dd„ dƒZ6G d d!„ d!ƒZ7G d"d#„ d#ƒZ8dS )$é    N)Úcache_from_source)	ÚAnyÚCallableÚDictÚIterableÚIteratorÚListÚOptionalÚSetÚTuple)Úpkg_resources)ÚDistribution)ÚUninstallationError)Úget_bin_prefixÚget_bin_user)ÚWINDOWS)Úegg_link_path_from_location)Ú	getLoggerÚ
indent_log)ÚaskÚdist_in_usersiteÚdist_is_localÚis_localÚnormalize_pathÚrenamesÚrmtree)ÚAdjacentTempDirectoryÚTempDirectory)ÚdistÚscript_nameÚis_guiÚreturnc             C   sp   t | ƒrtƒ }ntƒ }tjj||ƒ}|g}trl|j|d ƒ |j|d ƒ |r^|j|d ƒ n|j|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)r   r   r    Úbin_dirZexe_nameÚpaths_to_remove© r(   ú>/tmp/pip-build-red6nood/pip/pip/_internal/req/req_uninstall.pyÚ_script_names   s    r*   .)Úfnr!   c                s(   t jˆ ƒtttt dœ‡ fdd„ƒ}|S )N)ÚargsÚkwr!   c              ?   s6   t ƒ }x*ˆ | |ŽD ]}||kr|j|ƒ |V  qW d S )N)ÚsetÚadd)r,   r-   ÚseenÚitem)r+   r(   r)   Úunique5   s
    
z_unique.<locals>.unique)Ú	functoolsÚwrapsr   r   )r+   r2   r(   )r+   r)   Ú_unique4   s    r5   )r   r!   c             c   s>  yt j| jdƒƒ}W n¦ tk
rº } zŠdj| d�}y&t| jdƒƒ}| sP|dkrVtƒ ‚W n8 tttfk
r�   dj| j	| j
ƒ}|dj|ƒ7 }Y nX |dj|ƒ7 }t|ƒ|‚W Y d	d	}~X nX x||D ]t}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Â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].

    If RECORD is not found, raises UninstallationError,
    with possible information from the INSTALLER file.

    https://packaging.python.org/specifications/recording-installed-packages/
    ÚRECORDz/Cannot uninstall {dist}, RECORD file not found.)r   Ú	INSTALLERÚpipz{}=={}zZ You might be able to recover from this via: 'pip install --force-reinstall --no-deps {}'.z' Hint: The package was installed by {}.Nr   z.pyé   z.pycz.pyoéýÿÿÿ)ÚcsvÚreaderÚget_metadata_linesÚFileNotFoundErrorÚformatÚnextÚ
ValueErrorÚOSErrorÚStopIterationÚproject_nameÚversionr   r"   r#   r$   ÚlocationÚendswithÚsplit)r   ÚrZmissing_record_exceptionÚmsgÚ	installerÚdepÚrowr#   Údnr+   Úbaser(   r(   r)   Úuninstallation_paths@   s2    


rP   )Úpathsr!   c                sN   t jj‰tƒ }x:t| td�D ]*‰ t‡ ‡fdd„|D ƒƒ}|s|jˆ ƒ 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}ˆ j |jd ƒƒo0ˆ t|jd ƒjˆƒƒ ˆkV  qdS )Ú*N)Ú
startswithÚrstripÚlen)Ú.0Ú	shortpath)r#   Úsepr(   r)   ú	<genexpr>v   s   zcompact.<locals>.<genexpr>)r"   r#   rY   r.   ÚsortedrV   Úanyr/   )rQ   Úshort_pathsZshould_skipr(   )r#   rY   r)   Úcompactl   s    
r^   c       	         s   dd„ | D ƒ}t |ƒ}tdd„ |jƒ D ƒtd�}t ƒ }ttdœdd„‰x¤|D ]œ‰t‡fd	d
„|D ƒƒrhqLt ƒ }t ƒ }xPtjˆƒD ]B\‰ }}|j‡ ‡‡fdd
„|D ƒƒ |j‡ ‡‡fdd
„|D ƒƒ q€W || sL|j	|ƒ |j
ˆ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   i | ]}|t jj|ƒ“qS r(   )r"   r#   Únormcase)rW   Úpr(   r(   r)   ú
<dictcomp>…   s    z'compress_for_rename.<locals>.<dictcomp>c             S   s   h | ]}t jj|ƒd  ’qS )r   )r"   r#   rH   )rW   r`   r(   r(   r)   ú	<setcomp>‡   s    z&compress_for_rename.<locals>.<setcomp>)rR   )Úar!   c              W   s   t jjt jj| Ž ƒS )N)r"   r#   r_   r$   )rc   r(   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#   r_   rT   )rW   Úw)Úrootr(   r)   rZ   Ž   s    z&compress_for_rename.<locals>.<genexpr>c             3   s   | ]}ˆˆˆ |ƒV  qd S )Nr(   )rW   Úd)Údirnamerd   rf   r(   r)   rZ   •   s    c             3   s   | ]}ˆˆˆ |ƒV  qd S )Nr(   )rW   Úf)rh   rd   rf   r(   r)   rZ   –   s    )r.   r[   ÚvaluesrV   Ústrr\   r"   ÚwalkÚupdateÚdifference_updater/   rY   ÚmapÚ__getitem__)	rQ   Zcase_mapÚ	remainingZ	uncheckedÚ	wildcardsZ	all_filesZall_subdirsÚsubdirsÚfilesr(   )rh   rd   rf   r)   Úcompress_for_rename   s"    
 
ru   c             C   s  t | ƒ}t ƒ }t ƒ }t ƒ }xF|D ]>}|jdƒr0q |jdƒsBd|krT|jtjj|ƒƒ |j|ƒ q W t ttjj|ƒƒ}t|ƒ}xt|D ]l}xftj	|ƒD ]X\}}	}
xL|
D ]D}|jdƒr²q¢tjj
||ƒ}tjj|ƒr¢tjj|ƒ|kr¢|j|ƒ 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j|d ƒ’qS )rS   )r"   r#   r$   )rW   Úfolderr(   r(   r)   rb   Î   s    z.compress_for_output_listing.<locals>.<setcomp>)r.   rG   r/   r"   r#   rh   ro   r_   r^   rl   r$   Úisfile)rQ   Úwill_removeÚ	will_skipZfoldersrt   r#   Z_normcased_filesrv   ÚdirpathÚ_ZdirfilesÚfnameZfile_r(   r(   r)   Úcompress_for_output_listing¡   s.    




r}   c               @   s|   e Zd ZdZddœdd„Zeedœdd„Zeedœd	d
„Zeedœdd„Zddœdd„Z	ddœdd„Z
eedœdd„ƒZdS )ÚStashedUninstallPathSetzWA set of file rename operations to stash files while
    tentatively uninstalling them.N)r!   c             C   s   i | _ g | _d S )N)Ú
_save_dirsÚ_moves)Úselfr(   r(   r)   Ú__init__×   s    z StashedUninstallPathSet.__init__)r#   r!   c             C   sD   yt |ƒ}W n tk
r*   tdd�}Y nX || jtjj|ƒ< |jS )z�Stashes 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   rB   r   r   r"   r#   r_   )r�   r#   Úsave_dirr(   r(   r)   Ú_get_directory_stashß   s    z,StashedUninstallPathSet._get_directory_stashc             C   s¼   t jj|ƒ}t jj|ƒd }}d}xd||krfy| j| }P W n tk
rP   Y nX t jj|ƒ| }}q$W t jj|ƒ}tdd�}|| j|< t jj||ƒ}|r¶|t jjkr¶t j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#   r_   rh   r   ÚKeyErrorr   ÚrelpathÚcurdirr$   )r�   r#   ÚheadZold_headr…   rˆ   r(   r(   r)   Ú_get_file_stashí   s"    



z'StashedUninstallPathSet._get_file_stashc             C   sl   t jj|ƒot jj|ƒ }|r*| j|ƒ}n
| j|ƒ}| jj||fƒ |r^t jj|ƒr^t j|ƒ t	||ƒ |S )z�Stashes 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#   Zpath_is_dirÚnew_pathr(   r(   r)   Ústash  s    


zStashedUninstallPathSet.stashc             C   s0   x| j jƒ D ]\}}|jƒ  qW 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Î   x| j D ]}tjd|žŽ  qW x¢| j D ]˜\}}yTtjd||ƒ tjj|ƒsVtjj|ƒrbtj|ƒ ntjj	|ƒrvt
|ƒ t||ƒ W q& tk
r¼ } ztjd|ƒ tjd|ƒ W Y dd}~X q&X q&W | jƒ  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#   rw   r�   ÚunlinkrŒ   r   r   rB   Úerrorr“   )r�   r`   r�   r#   Úexr(   r(   r)   Úrollback$  s    "z StashedUninstallPathSet.rollbackc             C   s
   t | jƒS )N)Úboolr€   )r�   r(   r(   r)   Úcan_rollback7  s    z$StashedUninstallPathSet.can_rollback)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r‚   rk   r†   r‹   r�   r“   r›   Úpropertyrœ   r�   r(   r(   r(   r)   r~   Ó   s   r~   c               @   s¦   e Zd ZdZeddœdd„Zeedœdd„Zeddœd	d
„Z	eeddœdd„Z
deeddœdd„Zeedœdd„Zddœdd„Zddœdd„Zeed dœdd„ƒZdS )ÚUninstallPathSetzMA set of file paths to be removed in the uninstallation of a
    requirement.N)r   r!   c             C   s(   t ƒ | _t ƒ | _i | _|| _tƒ | _d S )N)r.   rQ   Ú_refuseÚpthr   r~   Ú_moved_paths)r�   r   r(   r(   r)   r‚   @  s
    zUninstallPathSet.__init__)r#   r!   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)   Ú
_permittedG  s    zUninstallPathSet._permittedc             C   s„   t jj|ƒ\}}t jjt|ƒt jj|ƒƒ}t jj|ƒs:d S | j|ƒrR| jj	|ƒ n| j
j	|ƒ t jj|ƒd dkr€| j	t|ƒƒ d S )Né   z.py)r"   r#   rH   r$   r   r_   Úexistsr§   rQ   r/   r¤   Úsplitextr   )r�   r#   rŠ   Útailr(   r(   r)   r/   O  s    
zUninstallPathSet.add)Úpth_fileÚentryr!   c             C   sL   t |ƒ}| j|ƒr<|| jkr*t|ƒ| j|< | j| j|ƒ n| jj|ƒ d S )N)r   r§   r¥   ÚUninstallPthEntriesr/   r¤   )r�   r¬   r­   r(   r(   r)   Úadd_pthb  s    

zUninstallPathSet.add_pthF)Úauto_confirmÚverboser!   c             C   sÂ   | j stjd| jjƒ dS | jjd | jj }tjd|ƒ tƒ �x |sP| j|ƒr´| j}t	| j ƒ}x*t
t|ƒƒD ]}|j|ƒ tjd|ƒ qnW x| jjƒ D ]}|jƒ  q˜W tj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   rD   rE   r   Ú_allowed_to_proceedr¦   ru   r[   r^   r�   r±   r¥   rj   Úremove)r�   r°   r±   Zdist_name_versionÚmovedZ
for_renamer#   r¥   r(   r(   r)   r´   k  s"    


zUninstallPathSet.remove)r±   r!   c             C   s|   t tt  ddœdd„}|s*t| jƒ\}}nt| jƒ}tƒ }|d|ƒ |d|ƒ |d| jƒ |rn|dt| jƒƒ td	dƒdkS )z@Display which files would be deleted and prompt for confirmationN)rJ   rQ   r!   c          
   S   sH   |sd S t j| ƒ tƒ �& xtt|ƒƒD ]}t j|ƒ q(W W d Q R X d S )N)r•   r–   r   r[   r^   )rJ   rQ   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¸   r¹   )rk   r   r}   rQ   r.   r¤   ru   r   )r�   r±   r¶   rx   ry   r(   r(   r)   r³   ˆ  s    	


z$UninstallPathSet._allowed_to_proceed)r!   c             C   sV   | j jstjd| jjƒ dS tjd| jjƒ | j jƒ  x| jj	ƒ D ]}|jƒ  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   rD   r–   r›   r¥   rj   )r�   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“   )r�   r(   r(   r)   r“   ±  s    zUninstallPathSet.commitc                sì  t |jƒ}t|ƒs.tjd|j|tjƒ | |ƒS |dd„ tj	dƒtj	dƒhD ƒkrhtjd|j|ƒ | |ƒS | |ƒ}t
|jƒ}djtj|jƒƒ}|jožtjj|jƒ}t|jdd ƒ}|oÊ|jjd	ƒoÊ|jj|ƒ �rº|j|jƒ |jd
ƒ�r"xÎ|jd
ƒjƒ D ]&}tjjtjj|j|ƒƒ}	|j|	ƒ qöW n”|jdƒ�rî|jdƒ�rF|jdƒ‰ ng ‰ xj‡ fdd„|jdƒjƒ D ƒD ]J}
tjj|j|
ƒ}	|j|	ƒ |j|	d ƒ |j|	d ƒ |j|	d ƒ �qhW �n4|�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Ä|�r^|jjdƒ�r^x®t |ƒD ]}	|j|	ƒ �qHW n�|�rÞt!|ƒ�}tjj"|j#ƒ j$ƒ ƒ}W d Q R X ||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ƒ�rf|j'dƒ�rfx^|j(dƒD ]P}t)|ƒ�r(t*ƒ }nt+ƒ }|jtjj||ƒƒ t,�r|jtjj||ƒd ƒ �qW g }|j-dd�}x$|j.ƒ D ]}|j/t0||dƒƒ �q€W |j-dd�}x$|j.ƒ D ]}|j/t0||d ƒƒ �q²W x|D ]}|j|ƒ �qÔW |S )!Nz1Not uninstalling %s at %s, outside environment %sc             S   s   h | ]}|r|’qS r(   r(   )rW   r`   r(   r(   r)   rb   Á  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(   )rW   r`   )Ú
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-infoz;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   rF   r   r•   r–   rR   ÚsysÚprefixÚ	sysconfigÚget_pathr   rD   r?   r   Úto_filenameÚegg_infor"   r#   r©   ÚgetattrÚ	_providerrG   r/   Úhas_metadataÚget_metadataÚ
splitlinesÚnormpathr$   r   rH   rh   r¯   rP   Ú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&   Z_scripts_to_remover¿   ÚnamerÁ   Úsr(   )r¼   r)   Ú	from_distµ  s®    







zUninstallPathSet.from_dist)FF)rž   rŸ   r    r¡   r   r‚   rk   rœ   r§   r/   r¯   r´   r³   r›   r“   Úclassmethodræ   r(   r(   r(   r)   r£   <  s   	r£   c               @   sH   e Zd Zeddœdd„Zeddœdd„Zddœd	d
„Zedœdd„ZdS )r®   N)r¬   r!   c             C   s   || _ tƒ | _d | _d S )N)Úfiler.   ÚentriesÚ_saved_lines)r�   r¬   r(   r(   r)   r‚   C  s    zUninstallPthEntries.__init__)r­   r!   c             C   s>   t jj|ƒ}tr.t jj|ƒd  r.|jddƒ}| jj|ƒ d S )Nr   ú\ú/)r"   r#   r_   r   Ú
splitdriveÚreplaceré   r/   )r�   r­   r(   r(   r)   r/   H  s    
zUninstallPthEntries.add)r!   c             C   s  t jd| jƒ tjj| jƒs.t jd| jƒ d S t| jdƒ�}|jƒ }|| _	W d Q R X t
dd„ |D ƒƒrld}nd}|r |d j|jd	ƒƒ r |d |jd	ƒ |d< xH| jD ]>}y$t jd
|ƒ |j|| jd	ƒƒ W q¨ tk
rä   Y q¨X q¨W t| jdƒ�}|j|ƒ W d Q R X d 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(   )rW   Úliner(   r(   r)   rZ   b  s    z-UninstallPthEntries.remove.<locals>.<genexpr>z
Ú
r¨   zutf-8zRemoving entry: %sÚwbéÿÿÿÿró   ró   )r•   r±   rè   r"   r#   rw   ÚwarningrÎ   Ú	readlinesrê   r\   rG   Úencoderé   r´   rA   Ú
writelines)r�   rá   ÚlinesÚendliner­   r(   r(   r)   r´   W  s(    
zUninstallPthEntries.removec          	   C   sR   | j d krtjd| jƒ dS tjd| jƒ t| jdƒ�}|j| 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›   r  s    
zUninstallPthEntries.rollback)	rž   rŸ   r    rk   r‚   r/   r´   rœ   r›   r(   r(   r(   r)   r®   B  s   r®   )9r;   r3   r"   rÂ   rÄ   Úimportlib.utilr   Útypingr   r   r   r   r   r   r	   r
   r   Úpip._vendorr   Zpip._vendor.pkg_resourcesr   Zpip._internal.exceptionsr   Zpip._internal.locationsr   r   Zpip._internal.utils.compatr   Zpip._internal.utils.egg_linkr   Zpip._internal.utils.loggingr   r   Zpip._internal.utils.miscr   r   r   r   r   r   r   Zpip._internal.utils.temp_dirr   r   rž   r•   rk   rœ   r*   r5   rP   r^   ru   r}   r~   r£   r®   r(   r(   r(   r)   Ú<module>   s8   ,$	(+"$2i  