3 ”Reš\ã@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/ej0e1ƒZ2d d„Z3dd„Z4e4dd„ƒZ5dd„Z6dd„Z7dd„Z8Gdd„de9ƒZ:Gdd„de9ƒZ;Gdd„de9ƒZ.unique)Ú functoolsÚwraps)r4r5r+)r4r,Ú_unique=sr8ccs–tjt|jdƒƒƒ}x||D]t}tjj|j|dƒ}|V|jdƒrtjj |ƒ\}}|dd…}tjj||dƒ}|Vtjj||dƒ}|VqWdS) 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]. ÚRECORDrz.pyNéz.pycz.pyoéýÿÿÿ) ÚcsvÚreaderr Úget_metadata_linesr!r"r#ÚlocationÚendswithÚsplit)r%ÚrÚrowr"Údnr4Úbaser+r+r,Úuninstallation_pathsJs    rFcsNtjj‰tƒ}x:t|td�D]*‰t‡‡fdd„|Dƒƒ}|s|jˆƒqW|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}ˆj|jdƒƒo0ˆt|jdƒjˆƒƒˆkVqdS)Ú*N)Ú startswithÚrstripÚlen)Ú.0Ú shortpath)r"Úsepr+r,ú mszcompact..)r!r"rNr.ÚsortedrKÚanyr/)ÚpathsÚ short_pathsÚ should_skipr+)r"rNr,Úcompactbs  rUc stdd„|Dƒƒ}t|ƒ}ttdd„|jƒDƒƒtd�}tƒ}dd„‰x¤|D]œ‰t‡fdd„|DƒƒrhqLtƒ}tƒ}xPtjˆƒD]B\‰}}|j‡‡‡fdd„|Dƒƒ|j‡‡‡fd d„|Dƒƒq€W||sL|j |ƒ|j ˆtj ƒqLWtt |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|]}tjj|ƒ|fVqdS)N)r!r"Únormcase)rLÚpr+r+r,rO}sz&compress_for_rename..css|]}tjj|ƒdVqdS)rN)r!r"rA)rLrWr+r+r,rOs)rGcWstjjtjj|ŽƒS)N)r!r"rVr#)Úar+r+r,Ú norm_joinƒsz&compress_for_rename..norm_joinc3s |]}tjjˆƒj|ƒVqdS)N)r!r"rVrI)rLÚw)Úrootr+r,rOˆsc3s|]}ˆˆˆ|ƒVqdS)Nr+)rLÚd)ÚdirnamerYr[r+r,rO�sc3s|]}ˆˆˆ|ƒVqdS)Nr+)rLÚf)r]rYr[r+r,rO’s)Údictr.rPÚvaluesrKrQr!ÚwalkÚupdateÚdifference_updater/rNÚmapÚ __getitem__) rRÚcase_mapÚ remainingÚ uncheckedÚ wildcardsÚ all_filesÚ all_subdirsÚsubdirsÚfilesr+)r]rYr[r,Úcompress_for_renamevs*      rnc Cs t|ƒ}tƒ}tƒ}tƒ}xF|D]>}|jdƒr0q |jdƒsBd|krT|jtjj|ƒƒ|j|ƒq Wtttjj|ƒƒ}t|ƒ}xt|D]l}xftj |ƒD]X\}} } xL| D]D} | jdƒr²q¢tjj || ƒ} tjj | ƒr¢tjj| ƒ|kr¢|j| ƒq¢Wq’Wq‚W|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. z.pycz __init__.pyz .dist-infocSsh|]}tjj|dƒ’qS)rH)r!r"r#)rLÚfolderr+r+r,ú Êsz.compress_for_output_listing..) r.r@r/r!r"r]rdrVrUrar#Úisfile) rRÚ will_removeÚ will_skipÚfoldersrmr"Ú_normcased_filesroÚdirpathÚ_ÚdirfilesÚfnameÚfile_r+r+r,Úcompress_for_output_listingžs0        r{c@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|_dS)N)Ú _save_dirsÚ_moves)Úselfr+r+r,Ú__init__Ôsz StashedUninstallPathSet.__init__c CsDy t|ƒ}Wntk r*tdd�}YnX||jtjj|ƒ<|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)Úkind)rÚOSErrorrr}r!r"rV)rr"Úsave_dirr+r+r,Ú_get_directory_stashÝs  z,StashedUninstallPathSet._get_directory_stashc Cs¼tjj|ƒ}tjj|ƒd}}d}xd||krfy|j|}PWntk rPYnXtjj|ƒ|}}q$Wtjj|ƒ}tdd�}||j|<tjj||ƒ}|r¶|tjjkr¶tjj |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.Nr�)r‚) r!r"rVr]r}ÚKeyErrorrÚrelpathÚcurdirr#)rr"ÚheadÚold_headr„r‡r+r+r,Ú_get_file_stashìs"      z'StashedUninstallPathSet._get_file_stashcCsltjj|ƒotjj|ƒ }|r*|j|ƒ}n |j|ƒ}|jj||fƒ|r^tjj|ƒr^tj|ƒ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)rr"Ú path_is_dirÚnew_pathr+r+r,Ústashs    zStashedUninstallPathSet.stashcCs0x|jjƒD]\}}|jƒq Wg|_i|_dS)z0Commits the uninstall by removing stashed files.N)r}ÚitemsÚcleanupr~)rrwr„r+r+r,Úcommits zStashedUninstallPathSet.commitcCsÎx|jD]}tjd|žŽqWx¢|jD]˜\}}yTtjd||ƒtjj|ƒsVtjj|ƒrbtj|ƒntjj |ƒrvt |ƒt ||ƒWq&t k r¼}ztj d|ƒtjd|ƒWYdd}~Xq&Xq&W|jƒdS)z2Undoes the uninstall by moving stashed files back.úMoving to %s from %szReplacing %s from %szFailed to restore %sz Exception: %sN)r•)r~ÚloggerÚinfoÚdebugr!r"rqr�ÚunlinkrŒrrrƒÚerrorr”)rrWr�r"Úexr+r+r,Úrollback&s    "z StashedUninstallPathSet.rollbackcCs t|jƒS)N)Úboolr~)rr+r+r,Ú can_rollback:sz$StashedUninstallPathSet.can_rollbackN) Ú__name__Ú __module__Ú __qualname__Ú__doc__r€r…r‹r‘r”rœÚpropertyržr+r+r+r,r|Ñs r|c@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ƒ|_dS)N)r.rRÚ_refuseÚpthr%r|Ú _moved_paths)rr%r+r+r,r€Cs zUninstallPathSet.__init__cCst|ƒS)zs Return True if the given path is one we are permitted to remove/modify, False otherwise. )r)rr"r+r+r,Ú _permittedKszUninstallPathSet._permittedcCsˆtjj|ƒ\}}tjjt|ƒtjj|ƒƒ}tjj|ƒs:dS|j|ƒrR|jj |ƒn |j j |ƒtjj |ƒddkr„t r„|j t |ƒƒdS)Néz.py)r!r"rAr#rrVÚexistsr¨rRr/r¥Úsplitextr r)rr"r‰Útailr+r+r,r/Ts   zUninstallPathSet.addcCsLt|ƒ}|j|ƒr<||jkr*t|ƒ|j|<|j|j|ƒn |jj|ƒdS)N)rr¨r¦ÚUninstallPthEntriesr/r¥)rÚpth_fileÚentryr+r+r,Úadd_pthhs   zUninstallPathSet.add_pthFc CsÂ|jstjd|jjƒdS|jjd|jj}tjd|ƒtƒ�x|sP|j|ƒr´|j}t |jƒ}x*t t |ƒƒD]}|j |ƒtj d|ƒqnWx|jjƒD] }|jƒq˜Wtjd|ƒWdQRXdS)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)rRr–r—r%Ú project_nameÚversionr Ú_allowed_to_proceedr§rnrPrUr‘r˜r¦r`Úremove)rÚ auto_confirmÚverboseÚdist_name_versionÚmovedÚ for_renamer"r¦r+r+r,rµrs"     zUninstallPathSet.removecCsndd„}|st|jƒ\}}nt|jƒ}tƒ}|d|ƒ|d|ƒ|d|jƒ|r`|dt|jƒƒtdd ƒdkS) zIDisplay which files would be deleted and prompt for confirmation c SsH|sdStj|ƒtƒ�&xtt|ƒƒD]}tj|ƒq(WWdQRXdS)N)r–r—r rPrU)ÚmsgrRr"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Ún)r½r¾)r{rRr.r¥rnr )rr·r¼rrrsr+r+r,r´’s     z$UninstallPathSet._allowed_to_proceedcCsV|jjstjd|jjƒdStjd|jjƒ|jjƒx|jj ƒD] }|jƒqBWdS)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`)rr¦r+r+r,rœ±s  zUninstallPathSet.rollbackcCs|jjƒdS)z?Remove temporary save dir: rollback will no longer be possible.N)r§r”)rr+r+r,r”¿szUninstallPathSet.commitc sèt|jƒ}t|ƒs.tjd|j|tjƒ||ƒS|dd„tj dƒtj dƒhDƒkrhtjd|j|ƒ||ƒS||ƒ}t |ƒ}dj t j |jƒƒ}|joœtjj|jƒ}t|jddƒ}|oÈ|jjd ƒoÈ|jj|ƒ �r¸|j|jƒ|jd ƒ�r xÎ|jd ƒjƒD]&}tjjtjj|j|ƒƒ} |j| ƒqôWn”|jd ƒ�rî|jd ƒ�rD|jd ƒ‰ng‰xj‡fd d„|jd ƒjƒDƒD]J} tjj|j| ƒ} |j| ƒ|j| dƒ|j| dƒ|j| dƒ�qfW�n6|�rÒtdj |jƒƒ‚�n|jjdƒ�r(|j|jƒtjj|jƒd} tjjtjj|jƒdƒ} |j| d| ƒnÆ|�r\|jjdƒ�r\x°t |ƒD]} |j| ƒ�qFWn’|�rÞt!|dƒ�} tjj"| j#ƒj$ƒƒ}WdQRX||jk�s®t%dj ||j|jƒƒ‚|j|ƒtjjtjj|ƒdƒ} |j| |jƒntj&d||jƒ|jdƒ�rb|j'dƒ�rbxZ|j(dƒD]L}t)|ƒ�r&t*}nt+}|jtjj||ƒƒt,�r|jtjj||ƒdƒ�qWg}|j-dd�}x$|j.ƒD]}|j/t0||dƒƒ�q|W|j-d d�}x$|j.ƒD]}|j/t0||d!ƒƒ�q®Wx|D]}|j|ƒ�qÐW|S)"Nz1Not uninstalling %s at %s, outside environment %scSsh|] }|r|’qSr+r+)rLrWr+r+r,rpÑsz-UninstallPathSet.from_dist..ÚstdlibÚ platstdlibzúsz.UninstallPathSet.from_dist..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©zeasy-install.pthz./z .dist-inforBz;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)1rr?rr–r—rGÚsysÚprefixÚ sysconfigÚget_pathrÚformatrÚ to_filenamer²Úegg_infor!r"rªÚgetattrÚ _providerr@r/Ú has_metadataÚ get_metadataÚ splitlinesÚnormpathr#rrAr]r°rFÚopenrVÚreadlineÚstripÚAssertionErrorr˜Úmetadata_isdirÚmetadata_listdirr rrrÚ 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¬                zUninstallPathSet.from_distN)FF)rŸr r¡r¢r€r¨r/r°rµr´rœr”Ú classmethodrír+r+r+r,r¤@s  r¤c@s,eZdZdd„Zdd„Zdd„Zdd„Zd S) r­cCs||_tƒ|_d|_dS)N)Úfiler.ÚentriesÚ _saved_lines)rr®r+r+r,r€JszUninstallPthEntries.__init__cCs>tjj|ƒ}tr.tjj|ƒd r.|jddƒ}|jj|ƒdS)Nrú\ú/)r!r"rVrÚ splitdriveÚreplacerðr/)rr¯r+r+r,r/Ps  zUninstallPthEntries.addcCstjd|jƒtjj|jƒs.tjd|jƒdSt|jdƒ�}|jƒ}||_ WdQRXt dd„|Dƒƒrld}nd}|r |d j |j d ƒƒ r |d |j d ƒ|d<xH|j D]>}y$tjd |ƒ|j||j d ƒƒWq¨tk räYq¨Xq¨Wt|jd ƒ�}|j|ƒWdQRXdS)NzRemoving pth entries from %s:z.Cannot remove entries from nonexistent file %sÚrbcss|]}d|kVqdS)s Nr+)rLÚliner+r+r,rOnsz-UninstallPthEntries.remove..z Ú r©zutf-8zRemoving entry: %sÚwbéÿÿÿÿrúrú)r–r˜rïr!r"rqÚwarningrÔÚ readlinesrñrQr@ÚencoderðrµÚ ValueErrorÚ writelines)rrçÚlinesÚendliner¯r+r+r,rµ`s*    zUninstallPthEntries.removec CsR|jdkrtjd|jƒdStjd|jƒt|jdƒ�}|j|jƒWdQRXdS)Nz.Cannot roll back changes to %s, none were madeFz!Rolling %s back to previous staterùT)rñr–ršrïr˜rÔrÿ)rrçr+r+r,rœ~s  zUninstallPthEntries.rollbackN)rŸr r¡r€r/rµrœr+r+r+r,r­Isr­)=Ú __future__rr<r6Úloggingr!rÇrÉÚ pip._vendorrÚpip._internal.exceptionsrÚpip._internal.locationsrrÚpip._internal.utils.compatrrr Úpip._internal.utils.loggingr Úpip._internal.utils.miscr r r rrrrrrÚpip._internal.utils.temp_dirrrÚpip._internal.utils.typingrÚtypingrrrrrrrrrZpip._vendor.pkg_resourcesr Ú getLoggerrŸr–r-r8rFrUrnr{Úobjectr|r¤r­r+r+r+r,Ús:    ,  ,   (3o