3
[aA                 @   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 d d	lmZ ej e!Z"d
d Z#dd Z$e$dd Z%dd Z&dd Z'G dd de(Z)G dd de(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)TempDirectoryc             C   sl   t | rt}nt}tjj||}|g}trh|j|d  |j|d  |rZ|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_nameis_guibin_direxe_namepaths_to_remove r   @/tmp/pip-install-65viz3iy/pip/pip/_internal/req/req_uninstall.py_script_names   s    r    c                s   t j  fdd}|S )Nc              ?   s6   t  }x* | |D ]}||kr|j| |V  qW d S )N)setadd)argskwseenitem)fnr   r   unique/   s
    
z_unique.<locals>.unique)	functoolswraps)r'   r(   r   )r'   r   _unique.   s    r+   c             c   s   t jt| jd}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].
    RECORDr   z.pyN   z.pycz.pyo)
csvreaderr   get_metadata_linesr   r   r   locationendswithsplit)r   rrowr   dnr'   baser   r   r   uninstallation_paths9   s    


r9   c                sN   t jjt }x:t| td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   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>Z   s   zcompact.<locals>.<genexpr>)r   r   rA   r!   sortedr>   anyr"   )pathsshort_paths
should_addr   )r   rA   r   compactP   s    
rH   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rqtjj||}tjj|rtjj||kr|j| qW qW qW |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 )r;   )r   r   r   )r?   folderr   r   r   	<setcomp>   s   z.compress_for_output_listing.<locals>.<setcomp>)listr!   r3   r"   r   r   dirnamemapnormcaserH   walkr   isfile)rE   will_remove	will_skipfoldersfilesr   Z_normcased_filesrI   dirpath_dirfilesfnamefile_r   r   r   compress_for_output_listingc   s0    





rZ   c               @   sf   e Zd ZdZd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   s2   t  | _t  | _i | _|| _tdd| _g | _d S )N	uninstall)kind)r!   rE   _refusepthr   r   save_dir_moved_paths)selfr   r   r   r   __init__   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   )rb   r   r   r   r   
_permitted   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rtr| j	t| d S )N   z.py)r   r   r4   r   r   rN   existsrd   rE   r"   r^   splitextr	   r   )rb   r   headtailr   r   r   r"      s    
zUninstallPathSet.addc             C   sL   t |}| j|r<|| jkr*t|| j|< | j| j| n| jj| d S )N)r   rd   r_   UninstallPthEntriesr"   r^   )rb   pth_fileentryr   r   r   add_pth   s    

zUninstallPathSet.add_pthc             C   s(   t jj| jjt jj|d jt jjS )Nre   )r   r   r   r`   
splitdrivelstriprA   )rb   r   r   r   r   _stash   s    zUninstallPathSet._stashFc             C   s   | j stjd| jj dS | jjd | jj }tjd| t  |sP| j|r| jj	  xBt
t| j D ]0}| j|}tjd| | jj| t|| qjW x| jj D ]}|j  qW 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)rE   loggerinfor   project_nameversionr
   _allowed_to_proceedr`   createrC   rH   rp   debugra   r   r   r_   valuesremove)rb   auto_confirmverbosedist_name_versionr   new_pathr_   r   r   r   rz      s$    


zUninstallPathSet.removec             C   sZ   dd }|st | j\}}nt| j}t }|d| |d| |d| j tdd	dkS )
zIDisplay which files would be deleted and prompt for confirmation
        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)rr   rs   r
   rC   rH   )msgrE   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Proceed (y/n)? yn)r   r   )rZ   rE   rK   r!   r^   r   )rb   r|   r   rQ   rR   r   r   r   rv      s    	


z$UninstallPathSet._allowed_to_proceedc             C   s   | j jdkr tjd| jj dS tjd| jj x.| jD ]$}| j|}tj	d| t
|| q8W x| jj D ]}|j  qlW dS )z1Rollback the changes previously made by remove().Nz'Can't roll back %s; was not uninstalledFzRolling back uninstall of %szReplacing %s)r`   r   rr   errorr   rt   rs   ra   rp   rx   r   r_   ry   rollback)rb   r   tmp_pathr_   r   r   r   r     s    

zUninstallPathSet.rollbackc             C   s   | j j  g | _dS )z?Remove temporary save dir: rollback will no longer be possible.N)r`   cleanupra   )rb   r   r   r   commit  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
|}djtj|j}|jot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|	 qW n|jdr|jdrD|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  qfW n6|rt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\xt |D ]}	|j|	 qFW n|rt!|d}tjj"|j# j$ }W d Q R X ||jkst%d||j|jf |j| tjjtjj|d}|j||j ntj&d||j |jdrb|j'drbxZ|j(dD ]L}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! qW x|D ]}|j| qW |S )"Nz1Not uninstalling %s at %s, outside environment %sc             S   s   h | ]}|r|qS r   r   )r?   pr   r   r   rJ   "  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?   r   )
namespacesr   r   
<listcomp>K  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.eggre   zeasy-install.pthz./z
.dist-infor5   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   r2   r   rr   rs   r:   sysprefix	sysconfigget_pathr   formatr   to_filenamert   egg_infor   r   rf   getattr	_providerr3   r"   has_metadataget_metadata
splitlinesnormpathr   r   r4   rL   rm   r9   openrN   readlinestripAssertionErrorrx   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)__name__
__module____qualname____doc__rc   rd   r"   rm   rp   rz   rv   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 )
rj   c             C   s0   t jj|std| || _t | _d | _d S )Nz.Cannot remove entries from nonexistent file %s)r   r   rP   r   filer!   entries_saved_lines)rb   rk   r   r   r   rc     s    
zUninstallPthEntries.__init__c             C   s>   t jj|}tr.t jj|d  r.|jdd}| jj| d S )Nr   \/)r   r   rN   r   rn   replacer   r"   )rb   rl   r   r   r   r"     s    zUninstallPthEntries.addc             C   s   t jd| j 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 qX qW t| jd
}|j| W d Q R X d S )NzRemoving pth entries from %s:rbc             s   s   | ]}d |kV  qdS )s   
Nr   )r?   liner   r   r   rB     s    z-UninstallPthEntries.remove.<locals>.<genexpr>z

re   zutf-8zRemoving entry: %swbr   r   )rr   rx   r   r   	readlinesr   rD   r3   encoder   rz   
ValueError
writelines)rb   r   linesendlinerl   r   r   r   rz     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   rr   r   r   rx   r   r   )rb   r   r   r   r   r     s    

zUninstallPthEntries.rollbackN)r   r   r   rc   r"   rz   r   r   r   r   r   rj     s   	
rj   )+
__future__r   r/   r)   loggingr   r   r   pip._vendorr   pip._internal.exceptionsr   pip._internal.locationsr   r   Zpip._internal.utils.compatr   r   r	   pip._internal.utils.loggingr
   pip._internal.utils.miscr   r   r   r   r   r   r   r   pip._internal.utils.temp_dirr   	getLoggerr   rr   r    r+   r9   rH   rZ   objectr[   rj   r   r   r   r   <module>   s.   (
1  