U
    
Ha]                     @   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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)m*Z* ee+Z,ee-e.ee- dddZ/e	dee f e	dee f dddZ0e0eee- dddZ1ee- ee- dddZ2ee- ee- dddZ3ee- eee- ee- f dddZ4G dd dZ5G dd  d Z6G d!d" d"Z7d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)	getLogger
indent_log)askdist_in_usersitedist_is_localegg_link_pathis_localnormalize_pathrenamesrmtree)AdjacentTempDirectoryTempDirectory)distscript_nameis_guireturnc                 C   sp   t | rt }nt }tj||}|g}trl||d  ||d  |r^||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)r   r   r    bin_direxe_namepaths_to_remove r)   C/tmp/pip-unpacked-wheel-tx790h60/pip/_internal/req/req_uninstall.py_script_names   s    r+   .)fnr!   c                    s(   t  tttt d fdd}|S )N)argskwr!   c                  ?   s2   t  } | |D ]}||kr|| |V  qd S N)setadd)r-   r.   seenitemr,   r)   r*   unique5   s
    
z_unique.<locals>.unique)	functoolswrapsr   r   )r,   r5   r)   r4   r*   _unique4   s    r8   r   r!   c                 c   s8  zt | d}W n tk
r } zdj| d}z$t| d}|rN|dkrTt W n8 tttfk
r   d| j	| j
}|d|7 }Y nX |d|7 }t||W 5 d	}~X Y nX |D ]t}tj| j|d
 }|V  |drtj|\}}	|	d	d }
tj||
d }|V  tj||
d }|V  qd	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   .py.pyc.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    

rV   )pathsr!   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>r   s   zcompact.<locals>.<genexpr>)r"   r#   ra   r0   sortedr]   anyr1   )rW   short_pathsshould_skipr)   r`   r*   compacti   s    rg   c           	         s   dd | D }t |}tdd | D td}t  }ttd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   i | ]}t j||qS r)   )r"   r#   normcaser^   pr)   r)   r*   
<dictcomp>   s     
 z'compress_for_rename.<locals>.<dictcomp>c                 S   s   h | ]}t j|d  qS )r   )r"   r#   rN   ri   r)   r)   r*   	<setcomp>   s     z&compress_for_rename.<locals>.<setcomp>rX   )ar!   c                  W   s   t jt jj|  S r/   )r"   r#   rh   r$   )rm   r)   r)   r*   	norm_join   s    z&compress_for_rename.<locals>.norm_joinc                 3   s    | ]}t j |V  qd S r/   )r"   r#   rh   r[   )r^   w)rootr)   r*   rb      s   z&compress_for_rename.<locals>.<genexpr>c                 3   s   | ]} |V  qd S r/   r)   )r^   ddirnamern   rp   r)   r*   rb      s   c                 3   s   | ]} |V  qd S r/   r)   )r^   frr   r)   r*   rb      s   )r0   rc   valuesr]   strrd   r"   walkupdatedifference_updater1   ra   map__getitem__)	rW   case_map	remaining	unchecked	wildcards	all_filesall_subdirssubdirsfilesr)   rr   r*   compress_for_rename|   s.    

r   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 )rZ   )r"   r#   r$   )r^   folderr)   r)   r*   rl      s    z.compress_for_output_listing.<locals>.<setcomp>)r0   rM   r1   r"   r#   rs   rz   rh   rg   rw   r$   isfile)rW   will_remove	will_skipfoldersr   r#   _normcased_filesr   dirpath_dirfilesfnamefile_r)   r)   r*   compress_for_output_listing   s4    

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 r/   )
_save_dirs_movesselfr)   r)   r*   __init__   s    z StashedUninstallPathSet.__init__r#   r!   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   rH   r   r   r"   r#   rh   )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#   rh   rs   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#   r   r   unlinkr   r   r   rH   errorr   )r   rj   r   r#   exr)   r)   r*   rollback#  s    
 z StashedUninstallPathSet.rollbackc                 C   s
   t | jS r/   )boolr   r   r)   r)   r*   can_rollback6  s    z$StashedUninstallPathSet.can_rollback)__name__
__module____qualname____doc__r   rv   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.Nr9   c                 C   s(   t  | _t  | _i | _|| _t | _d S r/   )r0   rW   _refusepthr   r   _moved_paths)r   r   r)   r)   r*   r   >  s
    zUninstallPathSet.__init__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*   
_permittedE  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| d S )N   r=   )r"   r#   rN   r$   r   rh   existsr   rW   r1   r   splitextr   )r   r#   r   tailr)   r)   r*   r1   M  s    
zUninstallPathSet.add)pth_fileentryr!   c                 C   sL   t |}| |r<|| jkr*t|| j|< | j| | n| j| d S r/   )r   r   r   UninstallPthEntriesr1   r   )r   r   r   r)   r)   r*   add_pth`  s    

zUninstallPathSet.add_pthF)auto_confirmverboser!   c              	   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)rW   r   r   r   rJ   rK   r   _allowed_to_proceedr   r   rc   rg   r   r   r   ru   remove)r   r   r   dist_name_versionmoved
for_renamer#   r   r)   r)   r*   r   i  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 )zIDisplay which files would be deleted and prompt for confirmation
        N)rP   rW   r!   c              	   S   sD   |sd S t |  t " tt|D ]}t | q&W 5 Q R X d S r/   )r   r   r   rc   rg   )rP   rW   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   )rv   r   r   rW   r0   r   r   r   )r   r   r   r   r   r)   r)   r*   r     s    	


z$UninstallPathSet._allowed_to_proceedr   c                 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   rJ   r   r   r   ru   )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n0|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!|}tj"|# $ }W 5 Q R X ||jkst%d||j|j|| tjtj|d}|||j nt&d||j |drV|'drV|(dD ]P}t)|rt* }nt+ }|tj|| t,r|tj||d  qg }|j-dd}|. D ]}|/t0||d qn|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)   ri   r)   r)   r*   rl     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)   ri   
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./r   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   rL   r   r   r   rY   sysprefix	sysconfigget_pathr   rE   r   to_filenamerJ   egg_infor"   r#   r   getattr	_providerrM   r1   has_metadataget_metadata
splitlinesnormpathr$   r   rN   rs   r   rV   openrh   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_dist)FF)r   r   r   r   r   r   rv   r   r   r1   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 r/   )filer0   entries_saved_lines)r   r   r)   r)   r*   r   ;  s    zUninstallPthEntries.__init__)r   r!   c                 C   s<   t j|}tr,t j|d s,|dd}| j| d S )Nr   \/)r"   r#   rh   r   
splitdrivereplacer  r1   )r   r   r)   r)   r*   r1   @  s    
zUninstallPthEntries.addr   c              	   C   s
  t d| j tj| js.t d| j d S 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:z.Cannot remove entries from nonexistent file %srbc                 s   s   | ]}d |kV  qdS )s   
Nr)   )r^   liner)   r)   r*   rb   \  s     z-UninstallPthEntries.remove.<locals>.<genexpr>z

zutf-8zRemoving entry: %swb)r   r   r  r"   r#   r   warningr   	readlinesr  rd   rM   encoder  r   rG   
writelines)r   r   linesendliner   r)   r)   r*   r   O  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   l  s    
 zUninstallPthEntries.rollback)	r   r   r   rv   r   r1   r   r   r   r)   r)   r)   r*   r   :  s   r   )8rA   r6   r"   r   r   importlib.utilr   typingr   r   r   r   r   r   r	   r
   r   pip._vendorr   Zpip._vendor.pkg_resourcesr   pip._internal.exceptionsr   pip._internal.locationsr   r   pip._internal.utils.compatr   pip._internal.utils.loggingr   r   pip._internal.utils.miscr   r   r   r   r   r   r   r   pip._internal.utils.temp_dirr   r   r   r   rv   r   r+   r8   rV   rg   r   r   r   r   r   r)   r)   r)   r*   <module>   s6   ,(
()%$2h  