3 Bu_\@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/ej0e1Z2d dZ3ddZ4e4ddZ5ddZ6ddZ7ddZ8Gddde9Z:Gddde9Z;Gddde9Z.unique) functoolswraps)r4r5r+)r4r,_unique=sr8ccstjt|jd}x||D]t}tjj|j|d}|V|jdrtjj |\}}|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.pyNz.pycz.pyo) csvreaderr get_metadata_linesr!r"r#locationendswithsplit)r%rrowr"dnr4baser+r+r,uninstallation_pathsJs    rFcsNtjjt}x:t|tdD]*tfdd|D}|s|jqW|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:|]2}j|jdo0t|jdjkVqdS)*N) startswithrstriplen).0 shortpath)r"sepr+r, mszcompact..)r!r"rNr.sortedrKanyr/)paths short_paths should_skipr+)r"rNr,compactbs  rUc stdd|D}t|}ttdd|jDtd}t}ddx|D]tfdd|DrhqLt}t}xPtjD]B\}}|jfdd|D|jfd d|DqW||sL|j ||j tj qLWtt |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. css|]}tjj||fVqdS)N)r!r"normcase)rLpr+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_joinsz&compress_for_rename..norm_joinc3s |]}tjjj|VqdS)N)r!r"rVrI)rLw)rootr+r,rOsc3s|]}|VqdS)Nr+)rLd)dirnamerYr[r+r,rOsc3s|]}|VqdS)Nr+)rLf)r]rYr[r+r,rOs)dictr.rPvaluesrKrQr!walkupdatedifference_updater/rNmap __getitem__) rRcase_map remaining unchecked wildcards all_files all_subdirssubdirsfilesr+)r]rYr[r,compress_for_renamevs*      rnc Cs t|}t}t}t}xF|D]>}|jdr0q |jdsBd|krT|jtjj||j|q Wtttjj|}t|}xt|D]l}xftj |D]X\}} } xL| D]D} | jdrqtjj || } tjj | rtjj| |kr|j| qWqWqW|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. z.pycz __init__.pyz .dist-infocSsh|]}tjj|dqS)rH)r!r"r#)rLfolderr+r+r, sz.compress_for_output_listing..) r.r@r/r!r"r]rdrVrUrar#isfile) rR will_remove will_skipfoldersrmr"_normcased_filesrodirpath_dirfilesfnamefile_r+r+r,compress_for_output_listings0        r{c@sLeZdZdZddZddZddZdd Zd d Zd d Z e ddZ 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)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)rOSErrorrr}r!r"rV)rr"save_dirr+r+r,_get_directory_stashs  z,StashedUninstallPathSet._get_directory_stashc Cstjj|}tjj|d}}d}xd||krfy|j|}PWntk rPYnXtjj||}}q$Wtjj|}tdd}||j|<tjj||}|r|tjjkrtjj |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.Nr)r) r!r"rVr]r}KeyErrorrrelpathcurdirr#)rr"headold_headrrr+r+r,_get_file_stashs"      z'StashedUninstallPathSet._get_file_stashcCsltjj|otjj| }|r*|j|}n |j|}|jj||f|r^tjj|r^tj|t |||S)zStashes the directory or file and returns its new location. Handle symlinks as files to avoid modifying the symlink targets. ) r!r"isdirislinkrrr~r$rmdirr)rr" path_is_dirnew_pathr+r+r,stashs    zStashedUninstallPathSet.stashcCs0x|jjD]\}}|jq Wg|_i|_dS)z0Commits the uninstall by removing stashed files.N)r}itemscleanupr~)rrwrr+r+r,commits zStashedUninstallPathSet.commitcCsx|jD]}tjd|qWx|jD]\}}yTtjd||tjj|sVtjj|rbtj|ntjj |rvt |t ||Wq&t k r}ztj d|tjd|WYdd}~Xq&Xq&W|jdS)z2Undoes the uninstall by moving stashed files back.Moving to %s from %szReplacing %s from %szFailed to restore %sz Exception: %sN)r)r~loggerinfodebugr!r"rqrunlinkrrrrerrorr)rrWrr"exr+r+r,rollback&s    "z StashedUninstallPathSet.rollbackcCs t|jS)N)boolr~)rr+r+r, can_rollback:sz$StashedUninstallPathSet.can_rollbackN) __name__ __module__ __qualname____doc__rrrrrrpropertyrr+r+r+r,r|s r|c@s^eZdZdZddZddZddZdd Zdd d Zd dZ ddZ ddZ e ddZ dS)UninstallPathSetzMA set of file paths to be removed in the uninstallation of a requirement.cCs(t|_t|_i|_||_t|_dS)N)r.rR_refusepthr%r| _moved_paths)rr%r+r+r,rCs 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._permittedcCstjj|\}}tjjt|tjj|}tjj|s:dS|j|rR|jj |n |j j |tjj |ddkrt r|j t |dS)Nz.py)r!r"rAr#rrVexistsrrRr/rsplitextr r)rr"rtailr+r+r,r/Ts   zUninstallPathSet.addcCsLt|}|j|r<||jkr*t||j|<|j|j|n |jj|dS)N)rrrUninstallPthEntriesr/r)rpth_fileentryr+r+r,add_pthhs   zUninstallPathSet.add_pthFc Cs|jstjd|jjdS|jjd|jj}tjd|tx|sP|j|r|j}t |j}x*t t |D]}|j |tj d|qnWx|jjD] }|jqWtjd|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)rRrrr% project_nameversionr _allowed_to_proceedrrnrPrUrrrr`remove)r auto_confirmverbosedist_name_versionmoved for_renamer"rr+r+r,rrs"     zUninstallPathSet.removecCsndd}|st|j\}}nt|j}t}|d||d||d|j|r`|dt|jtdd dkS) zIDisplay which files would be deleted and prompt for confirmation c SsH|sdStj|t&xtt|D]}tj|q(WWdQRXdS)N)rrr rPrU)msgrRr"r+r+r,_displays  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)? yn)rr)r{rRr.rrnr )rrrrrrsr+r+r,rs     z$UninstallPathSet._allowed_to_proceedcCsV|jjstjd|jjdStjd|jj|jjx|jj D] }|jqBWdS)z1Rollback the changes previously made by remove().z'Can't roll back %s; was not uninstalledNzRolling back uninstall of %s) rrrrr%rrrrr`)rrr+r+r,rs  zUninstallPathSet.rollbackcCs|jjdS)z?Remove temporary save dir: rollback will no longer be possible.N)rr)rr+r+r,rszUninstallPathSet.commitc st|j}t|s.tjd|j|tj||S|ddtj dtj dhDkrhtjd|j|||S||}t |}dj t j |j}|jotjj|j}t|jdd}|o|jjd o|jj| r|j|j|jd r x|jd jD]&}tjjtjj|j|} |j| qWn|jd r|jd rD|jd ngxjfd d|jd jDD]J} tjj|j| } |j| |j| d|j| d|j| dqfWn6|rtdj |jn|jjdr(|j|jtjj|jd} tjjtjj|jd} |j| d| n|r\|jjdr\xt |D]} |j| qFWn|rt!|d} tjj"| j#j$}WdQRX||jkst%dj ||j|j|j|tjjtjj|d} |j| |jntj&d||j|jdrb|j'drbxZ|j(dD]L}t)|r&t*}nt+}|jtjj||t,r|jtjj||dqWg}|j-dd}x$|j.D]}|j/t0||dq|W|j-d d}x$|j.D]}|j/t0||d!qWx|D]}|j|qW|S)"Nz1Not uninstalling %s at %s, outside environment %scSsh|] }|r|qSr+r+)rLrWr+r+r,rpsz-UninstallPathSet.from_dist..stdlib platstdlibzsz.UninstallPathSet.from_dist..z.pyz.pycz.pyozCannot 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.eggrzeasy-install.pthz./z .dist-inforBz;Egg-link {} does not match installed location of {} (at {})z)Not sure how to uninstall: %s - Check: %sscriptsz.batconsole_scripts)groupF gui_scriptsT)1rr?rrrrGsysprefix sysconfigget_pathrformatr to_filenameregg_infor!r"rgetattr _providerr@r/ has_metadata get_metadata splitlinesnormpathr#rrAr]rrFopenrVreadlinestripAssertionErrorrmetadata_isdirmetadata_listdirr rrr get_entry_mapkeysextendr-)clsr% dist_pathr*develop_egg_linkdevelop_egg_link_egg_infoegg_info_existsdistutils_egg_infoinstalled_filer" top_level_pkgeasy_install_eggeasy_install_pthfh link_pointerscriptr(_scripts_to_removernamersr+)rr, from_dists                zUninstallPathSet.from_distN)FF)rrrrrrr/rrrrr classmethodrr+r+r+r,r@s  rc@s,eZdZddZddZddZddZd S) rcCs||_t|_d|_dS)N)filer.entries _saved_lines)rrr+r+r,rJszUninstallPthEntries.__init__cCs>tjj|}tr.tjj|d r.|jdd}|jj|dS)Nr\/)r!r"rVr splitdrivereplacerr/)rrr+r+r,r/Ps  zUninstallPthEntries.addcCstjd|jtjj|js.tjd|jdSt|jd}|j}||_ WdQRXt dd|Drld}nd}|r|d j |j d  r|d |j d |d<xH|j D]>}y$tjd ||j||j d Wqtk rYqXqWt|jd }|j|WdQRXdS)NzRemoving pth entries from %s:z.Cannot remove entries from nonexistent file %srbcss|]}d|kVqdS)s Nr+)rLliner+r+r,rOnsz-UninstallPthEntries.remove..z  rzutf-8zRemoving entry: %swbrr)rrrr!r"rqwarningr readlinesrrQr@encoderr ValueError writelines)rrlinesendlinerr+r+r,r`s*    zUninstallPthEntries.removec CsR|jdkrtjd|jdStjd|jt|jd}|j|jWdQRXdS)Nz.Cannot roll back changes to %s, none were madeFz!Rolling %s back to previous staterT)rrrrrrr)rrr+r+r,r~s  zUninstallPthEntries.rollbackN)rrrrr/rrr+r+r+r,rIsr)= __future__rr<r6loggingr!rr pip._vendorrpip._internal.exceptionsrpip._internal.locationsrrpip._internal.utils.compatrrr pip._internal.utils.loggingr pip._internal.utils.miscr r r rrrrrrpip._internal.utils.temp_dirrrpip._internal.utils.typingrtypingrrrrrrrrrZpip._vendor.pkg_resourcesr getLoggerrrr-r8rFrUrnr{objectr|rrr+r+r+r,s:    ,  ,   (3o