
!dVF                 @   s  d  Z  d d l Z d d l Z d d l Z d d l Z d d l Z d d l Z d d l Z d d l	 Z	 y e j
 Z Wn e k
 r e j Z Yn Xd d l m Z d d l m Z m Z m Z m Z m Z m Z d d l m Z d d l m Z d d l m Z d d	 l m Z d d
 l m Z d d f Z  e j! d e j"  j# Z$ d d   a% Gd d   d e&  Z' Gd d   d e(  Z) Gd d   d e j*  Z+ d S)zD
Operations on existing wheel files, including basic installation. 
    N)reify)urlsafe_b64encode	from_jsonurlsafe_b64decodenativebinaryHashingFile)
signatures)read_pkg_info_bytes)open_for_csv   )get_supported)get_install_pathsz^(?P<namever>(?P<name>.+?)(-(?P<ver>\d.+?))?)
    ((-(?P<build>\d.*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?)
    \.whl|\.dist-info)$c             C   sC   y d d l  m a Wn" t k
 r8 d d l m a Yn Xt |   S)z?Use parse_version from pkg_resources or distutils as available.r   )parse_version)LooseVersion)pkg_resourcesr   ImportErrordistutils.versionr   )version r   ./tmp/pip-build-0jahl3lb/wheel/wheel/install.pyr   *   s
    r   c               @   s   e  Z d  Z d S)BadWheelFileN)__name__
__module____qualname__r   r   r   r   r   3   s   r   c               @   s  e  Z d  Z d Z d Z d Z d d e d d  Z d d	   Z e	 d
 d    Z
 e	 d d    Z e	 d d    Z e	 d d    Z e	 d d    Z e Z e	 d d    Z e	 d d    Z e	 d d    Z d d   Z d d   Z e	 d d    Z d  d!   Z d" d#   Z d$ d%   Z d& d'   Z d( d)   Z d* d+   Z e d, d-    Z e d. d/    Z d0 d1   Z e d2 d3    Z  d i  d4 d5  Z! d d6 d7  Z" d S)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.WHEELRECORDNFc             C   s{   | |  _  | |  _ | |  _ | |  _ t j j |  } t |  |  _ | j	 d  sd |  j d k rw t
 d |   n  d S)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.whlNzBad filename '%s')filenamefpappendcontextospathbasenameWHEEL_INFO_REparsed_filenameendswithr   )selfr   r   r    r!   r$   r   r   r   __init__A   s    				zWheelFile.__init__c             C   s   |  j  S)N)r   )r(   r   r   r   __repr__U   s    zWheelFile.__repr__c             C   s   d |  j  j d  S)Nz%s.dist-infonamever)r&   group)r(   r   r   r   distinfo_nameX   s    zWheelFile.distinfo_namec             C   s   d |  j  j d  S)Nz%s.datar+   )r&   r,   )r(   r   r   r   datadir_name\   s    zWheelFile.datadir_namec             C   s   d |  j  |  j f S)Nz%s/%s)r-   r   )r(   r   r   r   record_name`   s    zWheelFile.record_namec             C   s   d |  j  |  j f S)Nz%s/%s)r-   
WHEEL_INFO)r(   r   r   r   wheelinfo_named   s    zWheelFile.wheelinfo_namec             c   s{   |  j  j   } xe | d j d  D]P } xG | d j d  D]2 } x) | d j d  D] } | | | f VqW Wq= Wq# Wd S)a  A 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.abiplatN)r&   	groupdictsplit)r(   tagsr2   r4   r5   r   r   r   r8   h   s
    
zWheelFile.tagsc             C   s   t  t |  j   S)z4The number of compatibility tags the wheel declares.)lenlistcompatibility_tags)r(   r   r   r   arityz   s    zWheelFile.arityc             C   s   |  j  |  j    S)zo
        Lowest index of any of this wheel's tags in self.context(), and the
        arity e.g. (0, 1)
        )compatibility_rankr!   )r(   r   r   r   rank   s    zWheelFile.rankc             C   s   |  j  d t k S)Nr   )r>   _big_number)r(   r   r   r   
compatible   s    zWheelFile.compatiblec             C   sr   g  } x@ |  j  D]5 } y | j | j |   Wq t k
 rD Yq Xq Wt |  rh t |  |  j f St d f S)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;   r    index
ValueErrorr9   minr<   r?   )r(   	supportedZpreferencestagr   r   r   r=      s    	zWheelFile.compatibility_rankc             C   s"   |  j  | k s t d   |  j S)Nzcontext mismatch)r!   AssertionErrorr@   )r(   xr   r   r   supports_current_python   s    z!WheelFile.supports_current_pythonc             C   sG   |  j  j d  t |  j  j d   t d d   |  j D  |  j f S)Nnameverc             s   s   |  ] } | Vq d  S)Nr   ).0rG   r   r   r   	<genexpr>   s    z&WheelFile._sort_key.<locals>.<genexpr>)r&   r,   r   tupler>   r   )r(   r   r   r   	_sort_key   s    zWheelFile._sort_keyc             C   s   |  j  | j  k S)N)r   )r(   otherr   r   r   __eq__   s    zWheelFile.__eq__c             C   s   |  j  | j  k S)N)r   )r(   rO   r   r   r   __ne__   s    zWheelFile.__ne__c             C   sV  |  j  | j  k r- t d j |  |    n  |  j | j k  S|  j j d  } | j j d  } | | k rw | | k  St |  j j d   } t | j j d   } | | k r | | k  S|  j  | j  k r t d j |  |    n  |  j } | j } | d  k r*| d  k r*| | k r*| | k S| d  k rF| d  k rFd S|  j | j k  S)Nz{0}.context != {1}.contextrI   rJ   F)	r!   	TypeErrorformatrN   r&   r,   r   r>   r   )r(   rO   ZsnonsvovZscocr   r   r   __lt__   s(    

		$
zWheelFile.__lt__c             C   s
   | |  k  S)Nr   )r(   rO   r   r   r   __gt__   s    zWheelFile.__gt__c             C   s   |  | k p |  | k  S)Nr   )r(   rO   r   r   r   __le__   s    zWheelFile.__le__c             C   s   |  | k p | |  k  S)Nr   )r(   rO   r   r   r   __ge__   s    zWheelFile.__ge__c             C   sY   d } |  j  r d } n  t |  j r- |  j n |  j |  } |  j  sU |  j |  n  | S)Nra)r    VerifyingZipFiler   r   verify)r(   modeZvzfr   r   r   zipfile   s    		$	zWheelFile.zipfilec             C   s   t  |  j j |  j   S)z+Parse wheel metadata (the .data/WHEEL file))r
   ra   readr1   )r(   r   r   r   parsed_wheel_info   s    zWheelFile.parsed_wheel_infoc             C   sD   |  j  d } t t t | j d    t k r@ t d   n  d  S)NzWheel-Versionr3   zWheel version is too high)rc   rM   mapintr7   VERSION_TOO_HIGHrB   )r(   r   r   r   r   check_version   s    $zWheelFile.check_versionc             C   s   |  j  j d  } 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? 
        rI   )r&   r,   r   )r(   rI   r   r   r   install_paths   s    
zWheelFile.install_pathsc                s     f d d   }  j  d d k r7 | d  } n | d  } i  } x j j   D]} | j } | j d  r} qY n  | j d  r | d	 d
  } n  | j d  \ } }	 }
 |	 r|  j k r|
 j d  \ } }	 }
 |	 st d j	 |    n  | |  } n d } | } | }
 t
 j j t
 j j | |
   } | | |
 | f | | <qY W| sxe | j   D]T \ } } | j } | \ } } }
 } t
 j j |  rqt d j	 | |    qqqqWn  t j j t j    } g  }  j d } x| j   D]w\ } \ } } }
 } | j }  j j |  } | | k rIqn  t
 j j |  } t
 j j |  s}t
 j |  n  t t | d   } | d k r| j   } | j d  rd | t t
 j  } n  | j |  n  t j | |  t
 j j  | |  } | j! t
 j" d  | j# | | j$   | j% f  | j&   | j&   | j' d ?} | rt
 j( | | j' d ? qqWt
 j j |  j)  } t* j+ t, | d   } x3 t- |  D]% \ } } } | j. | | | f  qW| j.  j) d d f  d
 S)z7
        Install the wheel into site-packages.
        c                s     j  |   p  j |  S)N)getrh   )key)	overridesr(   r   r   get_path  s    z#WheelFile.install.<locals>.get_pathzRoot-Is-Purelibtruepurelibplatlib/z./   NzInvalid filename in wheel: {0} zAWheel file {0} would overwrite {1}. Use force if this is intendedz/RECORDwbscriptss   #!pythons   #!   zw+)/rc   ra   infolistr   r'   
startswith	partitionr.   rB   rS   r"   r#   normpathjoinitemsexistssys
executableencodegetfilesystemencodingr-   opendirnameisdirmakedirsr   readliner   linesepwriteshutilcopyfileobjrelpathreplacesepr    digestlengthcloseexternal_attrchmodr/   csvwriterr   sortedwriterow)r(   forcerk   rl   rootZ
name_transinforI   basedirr   r   rj   targetdestvkexenameZrecord_datar/   sourceddirZdestinationZhashbangZreldestattrsr   r   r   r   )rk   r(   r   install  sv    	!	"%	

zWheelFile.installc             C   s0  d } | d k r |  j  } n  d | _ d j |  j d f  } d j |  j d f  } d j |  j d f  } | j | d  | j | d  | j | d  | j |  } t t j |  j	    } y t
 t | j |    } Wn t k
 r Yn X| r`t j |  \ } }	 |	 d d t |  k r`d	 }
 t |
 j |	 d t |     q`n  t j d
 d   | j   D  } x | D] } | d } | d } | s| | | f k rt j j d |  qqn  | d j d d  \ } } | d k st d   | j | t t |    qWd S)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).NTrp   r   z
RECORD.jwsz
RECORD.p7shashzsha256=z8RECORD.sig claimed RECORD hash {0} != computed hash {1}.c             s   s   |  ] } t  |  Vq d  S)N)r   )rK   r\   r   r   r   rL     s    z#WheelFile.verify.<locals>.<genexpr>r   r   z%s has no hash!
=sha256zUnsupported hash algorithm)ra   strictrz   r-   set_expected_hashrb   r   hashlibr   r   r   r   KeyErrorr	   r_   r   rS   r   reader
splitlinesr}   stderrr   r7   rF   r   r   )r(   ra   sigr/   Zsig_nameZsmime_sig_namerecordZrecord_digestheaderspayloadmsgr   rowr   r   algodatar   r   r   r_   p  sB    	"

zWheelFile.verify)#r   r   r   __doc__r0   r   r   r)   r*   propertyr-   r.   r/   r1   r8   r;   r<   r>   r@   r=   rH   rN   rP   rQ   rX   rY   rZ   r[   r   ra   rc   rg   rh   r   r_   r   r   r   r   r   7   s>   
nr   c               @   sX   e  Z d  Z d Z d e j d d d  Z d d   Z d d d	 d
  Z d d   Z	 d S)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\   Fc             C   s>   t  j j |  | | | |  d |  _ i  |  _ t j |  _ d  S)NF)ra   ZipFiler)   r   _expected_hashesr   r   _hash_algorithm)r(   filer`   compression
allowZip64r   r   r   r)     s    		zVerifyingZipFile.__init__c             C   s   | |  j  | <d S)zn
        :param name: name of zip entry
        :param hash: bytes of hash (or None for "don't care")
        N)r   )r(   rI   r   r   r   r   r     s    z"VerifyingZipFile.set_expected_hashNc                s6  t  j j |  | | |   t | t  j  r9 | j } n | } | |  j k r|  j | d k r|  j |  y  j   Wn# t k
 r t	 j
 d   SYn X|  j    t  d  r      f d d   } n d      f d d  } |  _ n. |  j r2| |  j k r2t d  j   n   S)z#Return file-like object for 'name'.NzRNeed ZipExtFile._update_crc to implement file hash verification (in Python >= 2.7)_eofc                sL     |    j  |    j rH  j    k rH t d  j   n  d  S)NzBad hash for file %r)updater   r   r   rI   )r   )_update_crc_origefexpected_hashrunning_hashr   r   _update_crc  s    
z*VerifyingZipFile.open.<locals>._update_crcc                sO     |  d |  j  |   | rK  j    k rK t d  j   n  d  S)NeofzBad hash for file %r)r   r   r   rI   )r   r   )r   r   r   r   r   r   r     s    zNo expected hash for file %r)ra   r   r   
isinstanceZipInfor   r   r   AttributeErrorwarningswarnr   hasattrr   r   rI   )r(   Zname_or_infor`   pwdrI   r   r   )r   r   r   r   r   r     s(    	zVerifyingZipFile.openc             C   sj   |  j  s t d   n  |  j   j   } |  j | j =|  j  j | j t j	  |  j  j
   d |  _ d S)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   RuntimeErrorrv   pop
NameToInfor   seekheader_offsetr"   SEEK_SETtruncate
_didModify)r(   lastr   r   r   r     s    	zVerifyingZipFile.pop)
r   r   r   r   ra   
ZIP_STOREDr)   r   r   r   r   r   r   r   r^     s   #r^   ),r   r}   r   os.pathr"   rera   r   r   r   maxsizer?   	NameErrorZmaxintZwheel.decoratorr   Z
wheel.utilr   r   r   r   r   r   wheelr	   Zwheel.pkginfor
   r   
pep425tagsr   pathsr   rf   compileVERBOSEmatchr%   r   rB   r   objectr   r   r^   r   r   r   r   <module>   s8   .	 g