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