U ��.e&\�@s|ddlmZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl m Z mZddlmZmZmZddlmZddlmZmZmZmZmZmZmZmZmZdd lm Z m!Z!dd l"m#Z#e#�r dd l$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-dd l.m/Z/e�0e1�Z2d d�Z3dd�Z4e4dd��Z5dd�Z6dd�Z7dd�Z8Gdd�de9�Z:Gdd�de9�Z;Gdd�de9�Z.unique)� functools�wraps)r3r4r(r2r)�_unique=sr7ccs�t�t|�d���}|D]t}tj�|j|d�}|V|�d�rtj� |�\}}|dd�}tj�||d�}|Vtj�||d�}|VqdS)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]. ZRECORDr�.pyN������.pyc�.pyo) �csv�readerr Zget_metadata_linesr!r"r#�location�endswith�split)r%�r�rowr"Zdnr3�baser(r(r)�uninstallation_pathsJs   rDcsJtjj�t�}t|td�D]*�t��fdd�|D��}|s|���q|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.��keyc3s:|]2}��|�d��o0�t|�d������kVqdS)�*N)� startswith�rstrip�len)�.0Z shortpath�r"�sepr(r)� ls�zcompact..)r!r"rMr,�sortedrJ�anyr-)�pathsZ short_pathsZ should_skipr(rLr)�compactbs� rRc s�tdd�|D��}t|�}ttdd�|��D��td�}t�}dd��|D]��t�fdd�|D��rfqJt�}t�}t���D]B\�}}|����fdd�|D��|����fd d�|D��q|||sJ|� |�|� �tj �qJtt |j |��|BS) 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. css|]}tj�|�|fVqdSr+)r!r"�normcase�rK�pr(r(r)rN}sz&compress_for_rename..css|]}tj�|�dVqdS)rN)r!r"r@rTr(r(r)rNs�rEcWstj�tjj|��Sr+)r!r"rSr#)�ar(r(r)� norm_join�sz&compress_for_rename..norm_joinc3s |]}tj����|�VqdSr+)r!r"rSrH)rK�w)�rootr(r)rN�s�c3s|]}���|�VqdSr+r()rK�d��dirnamerWrYr(r)rN�s�c3s|]}���|�VqdSr+r()rK�fr[r(r)rN�s�)�dictr,rO�valuesrJrPr!�walk�update�difference_updater-rM�map� __getitem__) rQZcase_mapZ remainingZ uncheckedZ wildcardsZ all_filesZ all_subdirsZsubdirs�filesr(r[r)�compress_for_renamevs6 �� ���  rfc Cs�t|�}t�}t�}t�}|D]>}|�d�r.q|�d�s@d|krR|�tj�|��|�|�qtttjj|��}t|�}|D]d}t� |�D]T\}} } | D]D} | �d�r�q�tj� || �} tj� | �r�tj�| �|kr�|�| �q�q�q||dd�|D�B}||fS)asReturns 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-infocSsh|]}tj�|d��qS)rG)r!r"r#)rK�folderr(r(r)� �sz.compress_for_output_listing..) r,r?r-r!r"r\rcrSrRr`r#�isfile) rQ� will_remove� will_skipZfoldersrer"Z_normcased_filesrh�dirpath�_ZdirfilesZfnameZfile_r(r(r)�compress_for_output_listing�s4     ��roc@sLeZdZdZdd�Zdd�Zdd�Zdd �Zd d �Zd d �Z e dd��Z dS)�StashedUninstallPathSetzWA set of file rename operations to stash files while tentatively uninstalling them.cCsi|_g|_dSr+)� _save_dirs�_moves��selfr(r(r)�__init__�sz StashedUninstallPathSet.__init__cCsDz t|�}Wntk r*tdd�}YnX||jtj�|�<|jS)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�Zkind)r�OSErrorrrqr!r"rS)rtr"�save_dirr(r(r)�_get_directory_stash�s  z,StashedUninstallPathSet._get_directory_stashcCs�tj�|�}tj�|�d}}d}||krfz|j|}Wq�Wntk rPYnXtj�|�|}}q"tj�|�}tdd�}||j|<tj�||�}|r�|tjjkr�tj� |j|�S|jS)z�Stashes a file. If no root has been provided, one will be created for the directory in the user's temp directory.Nrvrw) r!r"rSr\rq�KeyErrorr�relpath�curdirr#)rtr"�headZold_headryr|r(r(r)�_get_file_stash�s"     z'StashedUninstallPathSet._get_file_stashcCsltj�|�otj�|� }|r*|�|�}n |�|�}|j�||f�|r^tj�|�r^t�|�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�islinkrzrrrr$�rmdirr)rtr"Z path_is_dir�new_pathr(r(r)�stashs    zStashedUninstallPathSet.stashcCs,|j��D]\}}|��q g|_i|_dS)z0Commits the uninstall by removing stashed files.N)rq�itemsZcleanuprr)rtrnryr(r(r)�commits zStashedUninstallPathSet.commitc Cs�|jD]}tjd|��q|jD]�\}}zTt�d||�tj�|�sPtj�|�r\t� |�ntj� |�rpt |�t ||�Wq t k r�}zt�d|�t�d|�W5d}~XYq Xq |��dS)z2Undoes the uninstall by moving stashed files back.�Moving to %s from %szReplacing %s from %szFailed to restore %sz Exception: %sN)r�)rr�logging�info�logger�debugr!r"rjr��unlinkr�rrrx�errorr�)rtrUr�r"Zexr(r(r)�rollback&s     z StashedUninstallPathSet.rollbackcCs t|j�Sr+)�boolrrrsr(r(r)� can_rollback:sz$StashedUninstallPathSet.can_rollbackN) �__name__� __module__� __qualname__�__doc__rurzrr�r�r��propertyr�r(r(r(r)rp�s rpc@s^eZdZdZdd�Zdd�Zdd�Zdd �Zdd d �Zd d�Z dd�Z dd�Z e dd��Z dS)�UninstallPathSetzMA set of file paths to be removed in the uninstallation of a requirement.cCs(t�|_t�|_i|_||_t�|_dSr+)r,rQ�_refuse�pthr%rp� _moved_paths)rtr%r(r(r)ruCs zUninstallPathSet.__init__cCst|�S)zs Return True if the given path is one we are permitted to remove/modify, False otherwise. )r)rtr"r(r(r)� _permittedKszUninstallPathSet._permittedcCs�tj�|�\}}tj�t|�tj�|��}tj�|�s:dS|�|�rR|j� |�n |j � |�tj� |�ddkr�t r�|� t |��dS)N�r8)r!r"r@r#rrS�existsr�rQr-r��splitextr r)rtr"r~�tailr(r(r)r-Ts   zUninstallPathSet.addcCsLt|�}|�|�r<||jkr*t|�|j|<|j|�|�n |j�|�dSr+)rr�r��UninstallPthEntriesr-r�)rt�pth_file�entryr(r(r)�add_pthhs   zUninstallPathSet.add_pthFc Cs�|jst�d|jj�dS|jjd|jj}t�d|�t��p|sP|�|�r�|j}t |j�}t t |��D]}|� |�t� d|�ql|j��D] }|��q�t�d|�W5QRXdS)z[Remove paths in ``self.paths`` with confirmation (unless ``auto_confirm`` is True).z7Can't uninstall '%s'. No files were found to uninstall.N�-zUninstalling %s:zRemoving file or directory %szSuccessfully uninstalled %s)rQr�r�r%� project_name�versionr �_allowed_to_proceedr�rfrOrRr�r�r�r_�remove)rtZ auto_confirm�verboseZdist_name_versionZmovedZ for_renamer"r�r(r(r)r�rs&��    zUninstallPathSet.removecCsndd�}|st|j�\}}nt|j�}t�}|d|�|d|�|d|j�|r`|dt|j��tdd�d kS) zIDisplay which files would be deleted and prompt for confirmation c SsD|sdSt�|�t��"tt|��D]}t�|�q&W5QRXdSr+)r�r�r rOrR)�msgrQr"r(r(r)�_display�s  z6UninstallPathSet._allowed_to_proceed.._displayz Would remove:z+Would not remove (might be manually added):z%Would not remove (outside of prefix):zWill actually move:zProceed (y/n)? )�y�nr�)rorQr,r�rfr )rtr�r�rkrlr(r(r)r��s     z$UninstallPathSet._allowed_to_proceedcCsR|jjst�d|jj�dSt�d|jj�|j��|j� �D] }|��q@dS)z1Rollback the changes previously made by remove().z'Can't roll back %s; was not uninstalledNzRolling back uninstall of %s) r�r�r�r�r%r�r�r�r�r_)rtr�r(r(r)r��s� zUninstallPathSet.rollbackcCs|j��dS)z?Remove temporary save dir: rollback will no longer be possible.N)r�r�rsr(r(r)r��szUninstallPathSet.commitc s�t|j�}t|�s.t�d|j|tj�||�S|dd�t� d�t� d�hD�krht�d|j|�||�S||�}t |�}d� t � |j��}|jo�tj�|j�}t|jdd�}|�r�|j�d ��r�|j�|��s�|�|j�|�d ��r|�d ���D]&}tj�tj�|j|��} |�| �q�n�|�d ��r�|�d ��rB|�d ��ng��fd d�|�d ���D�D]J} tj�|j| �} |�| �|�| d�|�| d�|�| d��qb�n|�r�td� |j���n�|j�d��r |�|j�tj�|j�d} tj�tj�|j�d�} |�| d| �n�|�rP|j�d��rPt |�D]} |�| ��q.ZstdlibZ platstdlibz�s�z.UninstallPathSet.from_dist..r8r:r;z�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�zeasy-install.pthz./rgrAz)Not sure how to uninstall: %s - Check: %sZscriptsz.bat�console_scripts)�groupF� gui_scriptsT)0rr>rr�r�rF�sys�prefix� sysconfigZget_pathr�formatrZ to_filenamer�Zegg_infor!r"r��getattrZ _providerr?r-Z has_metadataZ get_metadata� splitlines�normpathr#rr@r\r�rD�openrS�readline�stripr�Zmetadata_isdirZmetadata_listdirr rrrZ get_entry_map�keys�extendr*)�clsr%Z dist_pathr'Zdevelop_egg_linkZdevelop_egg_link_egg_infoZegg_info_existsZdistutils_egg_infoZinstalled_filer"Z top_level_pkgZeasy_install_eggZeasy_install_pth�fhZ link_pointerZscriptr&Z_scripts_to_remover��namer��sr(r�r)� from_dist�s� �� � � �  � �     �  �� �   ��     zUninstallPathSet.from_distN)FF)r�r�r�r�rur�r-r�r�r�r�r�� classmethodr�r(r(r(r)r�@s  r�c@s,eZdZdd�Zdd�Zdd�Zdd�Zd S) r�cCs0tj�|�std|��||_t�|_d|_dS)Nz.Cannot remove entries from nonexistent file %s)r!r"rjr�filer,�entries� _saved_lines)rtr�r(r(r)ruIs �zUninstallPthEntries.__init__cCs<tj�|�}tr,tj�|�ds,|�dd�}|j�|�dS)Nr�\�/)r!r"rSr� splitdrive�replacer�r-)rtr�r(r(r)r-Ss  zUninstallPthEntries.addc Cs�t�d|j�t|jd��}|��}||_W5QRXtdd�|D��rLd}nd}|r~|d�|�d��s~|d|�d�|d<|j D]>}z$t�d |�|� ||�d��Wq�t k r�Yq�Xq�t|jd ��}|� |�W5QRXdS) NzRemoving pth entries from %s:�rbcss|]}d|kVqdS)s Nr()rK�liner(r(r)rNjsz-UninstallPthEntries.remove..z � �����zutf-8zRemoving entry: %s�wb) r�r�r�r�� readlinesr�rPr?�encoder�r�� ValueError� writelines)rtr��linesZendliner�r(r(r)r�cs"  zUninstallPthEntries.removec CsR|jdkrt�d|j�dSt�d|j�t|jd��}|�|j�W5QRXdS)Nz.Cannot roll back changes to %s, none were madeFz!Rolling %s back to previous stater�T)r�r�r�r�r�r�r�)rtr�r(r(r)r�zs �zUninstallPthEntries.rollbackN)r�r�r�rur-r�r�r(r(r(r)r�Hs r�)=Z __future__rr<r5r�r!r�r�Z pip._vendorrZpip._internal.exceptionsrZpip._internal.locationsrrZpip._internal.utils.compatrrr Zpip._internal.utils.loggingr Zpip._internal.utils.miscr r r rrrrrrZpip._internal.utils.temp_dirrrZpip._internal.utils.typingr�typingrrrrrrrrrZpip._vendor.pkg_resourcesr Z getLoggerr�r�r*r7rDrRrfro�objectrpr�r�r(r(r(r)�s<    ,  ,    (3o