o 7]h] @sddlZddlZddlZddlZddlmZddlmZmZm Z m Z m Z m Z m Z mZmZddlmZddlmZmZddlmZddlmZddlmZdd lmZmZdd lmZm Z m!Z!m"Z"m#Z#dd l$m%Z%m&Z&ee'Z(d e)d e)de*de e)fddZ+dede efdede effddZ,e,dede e)fddZ-de e)dee)fddZ.de e)dee)fddZ/de e)deee)ee)ffddZ0Gd d!d!Z1Gd"d#d#Z2Gd$d%d%Z3dS)&N)cache_from_source) AnyCallableDictIterableIteratorListOptionalSetTuple)UninstallationError)get_bin_prefix get_bin_user)BaseDistribution)WINDOWS)egg_link_path_from_location) getLogger indent_log)askis_localnormalize_pathrenamesrmtree)AdjacentTempDirectory TempDirectorybin_dir script_nameis_guireturnccsZtj||}|VtsdS|dV|dV|r%|dVdS|dVdS)zCreate the fully qualified name of the files created by {console,gui}_scripts for the given ``dist``. Returns the list of file names Nz.exez .exe.manifestz -script.pywz -script.py)ospathjoinr)rrrexe_namer#A/usr/lib/python3/dist-packages/pip/_internal/req/req_uninstall.py _script_namess  r%fn.cs,tdtdtdttffdd }|S)Nargskwrc?s8t}|i|D]}||vr|||Vq dSN)setadd)r'r(seenitemr&r#r$unique&s z_unique..unique) functoolswrapsrr)r&r/r#r.r$_unique%s r2distc cs|j}|dus Jd|}|durAdj|d}|j}|r#|dkr6d|j|j}|d|7}t||d|7}t||D]7}tj ||}|V| d rztj |\}} | dd } tj || d }|Vtj || d }|VqCdS) 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/ Nz not installedz/Cannot uninstall {dist}, RECORD file not found.)r3pipz{}=={}zZ You might be able to recover from this via: 'pip install --force-reinstall --no-deps {}'.z' Hint: The package was installed by {}..py.pyc.pyo) locationiter_declared_entriesformat installerraw_nameversionr rr r!endswithsplit) r3r9entriesmsgr<depentryr dnr&baser#r#r$uninstallation_paths1s8    rGpathscsJtjjt}t|tdD]tfdd|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.keyc3s<|]}|dot|dkVqdS)*N) startswithrstriplen).0 shortpathr sepr#r$ fs  zcompact..)rr rRr*sortedrNanyr+)rH short_paths should_skipr#rQr$compact]s rXc sdd|D}t|}tdd|Dtd}t}dtdtfdd |D]Ltfd d |Dr4q&t}t}tD]!\}}|fd d |D|fd d |Dq?||sr| || tj q&tt |j ||BS)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. cSsi|] }tj||qSr#)rr normcaserOpr#r#r$ vz'compress_for_rename..cSsh|] }tj|dqS)r)rr r@rZr#r#r$ xsz&compress_for_rename..rIarcWstjtjj|Sr))rr rYr!)r_r#r#r$ norm_join{sz&compress_for_rename..norm_joinc3s"|] }tj|VqdSr))rr rYrL)rOw)rootr#r$rSs z&compress_for_rename..c3|] }|VqdSr)r#)rOddirnamer`rbr#r$rSc3rcr)r#)rOfrer#r$rSrg)r*rTvaluesrNstrrUrwalkupdatedifference_updater+rRmap __getitem__) rHcase_map remaining unchecked wildcards all_files all_subdirssubdirsfilesr#rer$compress_for_renameps$ rxc Cst|}t}t}t}|D]}|drq|ds d|vr)|tj|||qtttjj|}t|}|D]2}t |D]*\}} } | D]"} | drTqLtj || } tj | rntj| |vrn|| qLqEq>|dd|DB}||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. r7z __init__.pyz .dist-infocSsh|] }tj|dqS)rK)rr r!)rOfolderr#r#r$r^r]z.compress_for_output_listing..) r*r?r+rr rfrnrYrXrkr!isfile) rH will_remove will_skipfoldersrwr _normcased_filesrydirpath_dirfilesfnamefile_r#r#r$compress_for_output_listings6       rc@sveZdZdZdddZdedefddZdedefd d Zdedefd d Zdd dZ dddZ e de fddZ dS)StashedUninstallPathSetzWA set of file rename operations to stash files while tentatively uninstalling them.rNcCsi|_g|_dSr)) _save_dirs_movesselfr#r#r$__init__s z StashedUninstallPathSet.__init__r cCsBzt|}Wntytdd}Ynw||jtj|<|jS)zStashes a directory. Directories are stashed adjacent to their original location if possible, or else moved/copied into the user's temp dir. uninstallkind)rOSErrorrrrr rY)rr save_dirr#r#r$_get_directory_stashs  z,StashedUninstallPathSet._get_directory_stashcCstj|}tj|d}}d}||kr3z|j|}Wn&ty%Ynwtj||}}||kstj|}tdd}||j|<tj||}|rZ|tjjkrZtj |j|S|jS)zStashes a file. If no root has been provided, one will be created for the directory in the user's temp directory.Nrr) rr rYrfrKeyErrorrrelpathcurdirr!)rr headold_headrrr#r#r$_get_file_stashs&     z'StashedUninstallPathSet._get_file_stashcCsltj|o tj| }|r||}n||}|j||f|r/tj|r/t|t |||S)zStashes the directory or file and returns its new location. Handle symlinks as files to avoid modifying the symlink targets. ) rr isdirislinkrrrappendrmdirr)rr path_is_dirnew_pathr#r#r$stashs    zStashedUninstallPathSet.stashcCs,|jD]\}}|qg|_i|_dS)z0Commits the uninstall by removing stashed files.N)ritemscleanupr)rrrr#r#r$commits  zStashedUninstallPathSet.commitc Cs|jD] }tjdg|Rq|jD]L\}}z*td||tj|s*tj|r0t|n tj |r:t |t ||Wqt y^}zt d|td|WYd}~qd}~ww|dS)z2Undoes the uninstall by moving stashed files back.zMoving to %s from %szReplacing %s from %szFailed to restore %sz Exception: %sN)rloggerinfodebugrr rzrunlinkrrrrerrorr)rr[rr exr#r#r$rollbacks     z StashedUninstallPathSet.rollbackcCs t|jSr))boolrrr#r#r$ can_rollback(s z$StashedUninstallPathSet.can_rollbackrN)__name__ __module__ __qualname____doc__rrjrrrrrpropertyrrr#r#r#r$rs   rc@seZdZdZdeddfddZdedefdd Zdeddfd d Z d ed eddfddZ ddededdfddZ dedefddZ dddZ dddZededdfddZdS)UninstallPathSetzMA set of file paths to be removed in the uninstallation of a requirement.r3rNcCs(t|_t|_i|_||_t|_dSr))r*_paths_refuse_pth_distr _moved_paths)rr3r#r#r$r1s  zUninstallPathSet.__init__r cCst|S)zs Return True if the given path is one we are permitted to remove/modify, False otherwise. )r)rr r#r#r$ _permitted8szUninstallPathSet._permittedcCstj|\}}tjt|tj|}tj|sdS||r)|j |n|j |tj |ddkrB| t |dSdS)Nr5) rr r@r!rrYexistsrrr+rsplitextr)rr rtailr#r#r$r+@s   zUninstallPathSet.addpth_filerDcCsNt|}||r||jvrt||j|<|j||dS|j|dSr))rrrUninstallPthEntriesr+r)rrrDr#r#r$add_pthSs   zUninstallPathSet.add_pthF auto_confirmverbosecCs|js td|jjdS|jjd|jj}td|tF|s)||r_|j}t |j}t t |D] }| |t d|q7|jD]}|qJtd|WddSWddS1sjwYdS)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)rrrrr=r>r_allowed_to_proceedrrxrTrXrrrriremove)rrrdist_name_versionmoved for_renamer pthr#r#r$r\s*    "zUninstallPathSet.removecCsdtdttddfdd}|st|j\}}nt|j}t}|d||d||d |j|r9|d t|jtd d d kS)z@Display which files would be deleted and prompt for confirmationrBrHrNcSsZ|sdSt|ttt|D]}t|qWddS1s&wYdSr))rrrrTrX)rBrHr 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)? )ynr)rjrrrr*rrxr)rrrr{r|r#r#r$rys     z$UninstallPathSet._allowed_to_proceedcCsR|jjstd|jjdStd|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) rrrrrr=rrrri)rrr#r#r$rs  zUninstallPathSet.rollbackcCs|jdS)z?Remove temporary save dir: rollback will no longer be possible.N)rrrr#r#r$rszUninstallPathSet.commitc s|j}|j}|durtd|j||St|}|js*td|j|tj||S|ddt dt dhDvrGtd|j|||S||}t |j }|j of|duoftj|of||jd }|r|durr|||}|dur|D] } |tj|| q|n|d rz|d } Wn tygYnw| jd d fd d|d DD]&} tj|| } || || d|| d|| dqn|jrtd|j |jr||tj|d} tjtj|d}| |d| nf|j!r t"|D]} || qnT|rmt#|}tj$|%&}Wdn 1s=wY||ksVJd|d|j d|d||tjtj|d}| ||nt'd|||j(r|t)}nt*}z'|+dD]}|tj||j,t-r|tj||j,dqWn tt.fyYnwdt/dt0dt1t0fd d!}|||D]}||q|S)"Nz-Not uninstalling %s since it is not installedz1Not uninstalling %s at %s, outside environment %scSsh|]}|r|qSr#r#rZr#r#r$r^s z-UninstallPathSet.from_dist..stdlib platstdlibzsz.UninstallPathSet.from_dist..r5r7r8zCannot 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.rzeasy-install.pthz./z Egg-link z& does not match installed location of z (at )z)Not sure how to uninstall: %s - Check: %sscriptsz.batr3rrcssR|D]!}|jdkrt||jdEdHq|jdkr&t||jdEdHqdS)Nconsole_scriptsF gui_scriptsT)iter_entry_pointsgroupr%name)r3r entry_pointr#r#r$iter_scripts_to_remove2s   z:UninstallPathSet.from_dist..iter_scripts_to_remove)2r9 info_locationrrcanonical_namerlocalsysprefix sysconfigget_pathrr="installed_with_setuptools_egg_inforr rr?setuptools_filenamer+r:r!is_file read_textFileNotFoundError splitlinesinstalled_by_distutilsr r;installed_as_eggr@rfrinstalled_with_dist_inforGopenrYreadlinestripr in_usersiterr iterdirrrNotADirectoryErrorrrjr)clsr3 dist_locationrnormalized_dist_locationpaths_to_removedevelop_egg_linksetuptools_flat_installationinstalled_filesinstalled_filenamespace_packages top_level_pkgr easy_install_eggeasy_install_pthfh link_pointerrscriptrsr#rr$ from_dists                    zUninstallPathSet.from_dist)FFr)rrrrrrrjrrr+rrrrr classmethodrr#r#r#r$r-s   rc@sHeZdZdeddfddZdeddfddZd d d Zdefd d ZdS)rrrNcCs||_t|_d|_dSr))filer*rA _saved_lines)rrr#r#r$rCs zUninstallPthEntries.__init__rDcCs<tj|}trtj|ds|dd}|j|dS)Nr\/)rr rYr splitdrivereplacerAr+)rrDr#r#r$r+Hs  zUninstallPthEntries.addc Cs0td|jtj|jstd|jdSt|jd}|}||_ Wdn1s/wYt dd|Dr@d}nd}|rY|d | d sY|d| d |d<|j D]}ztd |||| d Wq\tyyYq\wt|jd }||WddS1swYdS) NzRemoving pth entries from %s:z.Cannot remove entries from nonexistent file %srbcss|]}d|vVqdS)s Nr#)rOliner#r#r$rSbsz-UninstallPthEntries.remove..z  zutf-8zRemoving entry: %swb)rrrrr rzwarningr readlinesrrUr?encoderAr ValueError writelines)rrlinesendlinerDr#r#r$rWs.    "zUninstallPthEntries.removecCsh|jdurtd|jdStd|jt|jd}||jWddS1s-wYdS)Nz.Cannot roll back changes to %s, none were madeFz!Rolling %s back to previous stater T)rrrrrrr)rrr#r#r$rrs  zUninstallPthEntries.rollbackr) rrrrjrr+rrrr#r#r#r$rBs  r)4r0rrrimportlib.utilrtypingrrrrrrr r r pip._internal.exceptionsr pip._internal.locationsr rpip._internal.metadatarpip._internal.utils.compatrpip._internal.utils.egg_linkrpip._internal.utils.loggingrrpip._internal.utils.miscrrrrrpip._internal.utils.temp_dirrrrrrjrr%r2rGrXrxrrrrr#r#r#r$s6 ,    * +&"2i