YF @sdZddlZddlZddlZddlZddlZddlZddlZddl Z y ej Z Wne k rej Z YnXddlmZddlmZmZmZmZmZmZddlmZddlmZddlmZdd lmZdd lmZddfZ ej!d ej"j#Z$d d a%Gddde&Z'Gddde(Z)Gdddej*Z+dS)zD Operations on existing wheel files, including basic installation. N)reify)urlsafe_b64encode from_jsonurlsafe_b64decodenativebinary HashingFile) signatures)read_pkg_info_bytes) open_for_csv) get_supported)get_install_pathsz^(?P(?P.+?)(-(?P\d.+?))?) ((-(?P\d.*?))?-(?P.+?)-(?P.+?)-(?P.+?) \.whl|\.dist-info)$c CsCyddlmaWn"tk r8ddlmaYnXt|S)z?Use parse_version from pkg_resources or distutils as available.r) parse_version) LooseVersion) pkg_resourcesr ImportErrorZdistutils.versionr)versionr./tmp/pip-build-3puug3g5/wheel/wheel/install.pyr*s  rc@seZdZdS) BadWheelFileN)__name__ __module__ __qualname__rrrrr3s rc@seZdZdZdZdZddeddZdd Ze d d Z e d d Z e ddZ e ddZ e ddZeZe ddZe ddZe ddZddZddZe ddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zed,d-Zed.d/Zd0d1Zed2d3Z did4d5Z!dd6d7Z"dS)8 WheelFilezParse wheel-specific attributes from a wheel (.whl) file and offer basic installation and verification support. WheelFile can be used to simply parse a wheel filename by avoiding the methods that require the actual file contents.WHEELRECORDNFcCsx||_||_||_||_tjj|}t||_|j d sd|jdkrtt d|dS)a :param fp: A seekable file-like object or None to open(filename). :param append: Open archive in append mode. :param context: Function returning list of supported tags. Wheels must have the same context to be sortable. z.whlNzBad filename '%s') filenamefpappendcontextospathbasename WHEEL_INFO_REparsed_filenameendswithr)selfrrrr r#rrr__init__As    zWheelFile.__init__cCs|jS)N)r)r'rrr__repr__UszWheelFile.__repr__cCsd|jjdS)Nz %s.dist-infonamever)r%group)r'rrr distinfo_nameXszWheelFile.distinfo_namecCsd|jjdS)Nz%s.datar*)r%r+)r'rrr datadir_name\szWheelFile.datadir_namecCsd|j|jfS)Nz%s/%s)r,r)r'rrr record_name`szWheelFile.record_namecCsd|j|jfS)Nz%s/%s)r, WHEEL_INFO)r'rrrwheelinfo_namedszWheelFile.wheelinfo_nameccs{|jj}xe|djdD]P}xG|djdD]2}x)|djdD]}|||fVqWWq=Wq#WdS)aA wheel file is compatible with the Cartesian product of the period-delimited tags in its filename. To choose a wheel file among several candidates having the same distribution version 'ver', an installer ranks each triple of (pyver, abi, plat) that its Python installation can run, sorting the wheels by the best-ranked tag it supports and then by their arity which is just len(list(compatibility_tags)). pyver.abiplatN)r% groupdictsplit)r'tagsr1r3r4rrrr7hs zWheelFile.tagscCstt|jS)z4The number of compatibility tags the wheel declares.)lenlistcompatibility_tags)r'rrrarityzszWheelFile.aritycCs|j|jS)zo Lowest index of any of this wheel's tags in self.context(), and the arity e.g. (0, 1) )compatibility_rankr )r'rrrrankszWheelFile.rankcCs|jdtkS)Nr)r= _big_number)r'rrr compatibleszWheelFile.compatiblec Csrg}x@|jD]5}y|j|j|Wqtk rDYqXqWt|rht||jfStdfS)zRank the wheel against the supported tags. Smaller ranks are more compatible! :param supported: A list of compatibility tags that the current Python implemenation can run. r)r:rindex ValueErrorr8minr;r>)r' supportedZ preferencestagrrrr<s   zWheelFile.compatibility_rankcCs"|j|kstd|jS)Nzcontext mismatch)r AssertionErrorr?)r'xrrrsupports_current_pythonsz!WheelFile.supports_current_pythoncCsG|jjdt|jjdtdd|jD|jfS)Nnamevercss|] }| VqdS)Nr).0rFrrr sz&WheelFile._sort_key..)r%r+rtupler=r)r'rrr _sort_keyszWheelFile._sort_keycCs|j|jkS)N)r)r'otherrrr__eq__szWheelFile.__eq__cCs|j|jkS)N)r)r'rNrrr__ne__szWheelFile.__ne__cCsP|j|jkr*tdj|||j|jkS|jjd}|jjd}||krt||kSt|jjd}t|jjd}||kr||kS|j|jkrtdj|||j}|j}|dkr$|dkr$||kr$||kS|dkr@|dkr@dS|j|jkS)Nz{0}.context != {1}.contextrHrIF) r TypeErrorformatrMr%r+rr=r)r'rNZsnonsvovZscocrrr__lt__s(      $ zWheelFile.__lt__cCs ||kS)Nr)r'rNrrr__gt__szWheelFile.__gt__cCs||kp||kS)Nr)r'rNrrr__le__szWheelFile.__le__cCs||kp||kS)Nr)r'rNrrr__ge__szWheelFile.__ge__cCsSd}|jrd}t|jr*|jn|j|}|jsO|j||S)Nra)rVerifyingZipFilerrverify)r'modeZvzfrrrzipfiles $  zWheelFile.zipfilecCst|jj|jS)z+Parse wheel metadata (the .data/WHEEL file))r r`readr0)r'rrrparsed_wheel_infoszWheelFile.parsed_wheel_infocCsA|jd}ttt|jdtkr=tddS)Nz Wheel-Versionr2zWheel version is too high)rbrLmapintr6VERSION_TOO_HIGHrA)r'rrrr check_versions $zWheelFile.check_versioncCs|jjd}t|S)al Consult distutils to get the install paths for our dist. A dict with ('purelib', 'platlib', 'headers', 'scripts', 'data'). We use the name from our filename as the dist name, which means headers could be installed in the wrong place if the filesystem-escaped name is different than the Name. Who cares? rH)r%r+r)r'rHrrr install_pathss zWheelFile.install_pathscsfdd}jddkr7|d}n |d}i}x jjD]}|j}|jdrzqY|jdr|d d }|jd\}} } | r|jkr| jd\} } } | std j ||| } nd } |} |} t j j t j j | | } | | | | f||.get_pathzRoot-Is-Purelibtruepurelibplatlib/z./NzInvalid filename in wheel: {0}zAWheel file {0} would overwrite {1}. Use force if this is intendedz/RECORDwbscriptss#!pythons#!zw+)/rbr`infolistrr& startswith partitionr-rArRr!r"normpathjoinitemsexistssys executableencodegetfilesystemencodingr,opendirnameisdirmakedirsrreadlinerlinesepwriteshutil copyfileobjrelpathreplaceseprdigestlengthclose external_attrchmodr.csvwriterr sortedwriterow)r'forcerjrkrootZ name_transinforHbasedirrrritargetdestvkexenameZ record_datar.sourceddirZ destinationZhashbangZreldestattrsrrrr)rjr'rinstallsv  !   %         zWheelFile.installcCs!d}|dkr|j}d|_dj|jdf}dj|jdf}dj|jdf}|j|d|j|d|j|d|j|}ttj|j }yt t |j|}Wnt k rYnX|rWt j|\}} | ddt |krWd } t| j| dt |tjd d |jD} x| D]} | d } | d }|s| ||fkrtjjd| q| d jdd \}}|dkstd|j| tt|qWdS)a Configure the VerifyingZipFile `zipfile` by verifying its signature and setting expected hashes for every hash in RECORD. Caller must complete the verification process by completely reading every file in the archive (e.g. with extractall).NTrorz RECORD.jwsz RECORD.p7shashzsha256=z8RECORD.sig claimed RECORD hash {0} != computed hash {1}.css|]}t|VqdS)N)r)rJr[rrrrKsz#WheelFile.verify..rr z%s has no hash! =sha256zUnsupported hash algorithm)r`strictryr,set_expected_hashrarhashlibrrrrKeyErrorr r^rrRrreader splitlinesr|stderrrr6rErr)r'r`sigr.Zsig_nameZsmime_sig_namerecordZ record_digestheaderspayloadmsgrrowrralgodatarrrr^psB    "   zWheelFile.verify)#rrr__doc__r/rr r(r)propertyr,r-r.r0r7r:r;r=r?r<rGrMrOrPrWrXrYrZrr`rbrfrgrr^rrrrr7s>             nrc@sXeZdZdZdejdddZddZddd d Zd d Z dS) r]zZipFile that can assert that each of its extracted contents matches an expected sha256 hash. Note that each file must be completly read in order for its hash to be checked.r[FcCs>tjj|||||d|_i|_tj|_dS)NF)r`ZipFiler(r_expected_hashesrr_hash_algorithm)r'filer_ compression allowZip64rrrr(s  zVerifyingZipFile.__init__cCs||j|= 2.7)_eofcsI|j|jrEjkrEtdjdS)NzBad hash for file %r)updaterrrrH)r)_update_crc_origef expected_hash running_hashrr _update_crcs  z*VerifyingZipFile.open.._update_crccsL|d|j||rHjkrHtdjdS)NeofzBad hash for file %r)rrrrH)rr)rrrrrrrs zNo expected hash for file %r)r`rr isinstanceZipInforrrAttributeErrorwarningswarnrhasattrrrrH)r'Z name_or_infor_pwdrHrr)rrrrrrs(        zVerifyingZipFile.opencCsg|jstd|jj}|j|j=|jj|jtj |jj d|_ dS)zTruncate the last file off this zipfile. Assumes infolist() is in the same order as the files (true for ordinary zip files created by Python)z7Attempt to pop from ZIP archive that was already closedTN) r RuntimeErrorrupop NameToInforseek header_offsetr!SEEK_SETtruncate _didModify)r'lastrrrrs    zVerifyingZipFile.pop) rrrrr` ZIP_STOREDr(rrrrrrrr]s  #r]),rr|ros.pathr!rer`rrrmaxsizer> NameErrorZmaxintZwheel.decoratorrZ wheel.utilrrrrrrwheelr Z wheel.pkginfor r pep425tagsr pathsrrecompileVERBOSEmatchr$rrArobjectrrr]rrrrs8          .  g