
    @dR                         d dl Z d dlZd dlZd dlmZmZmZ d dlmZm	Z	m
Z
  ej        dej                  Z ej        dej                  Z e j        d          Z G d d          Zd d	lmZ d d
lmZmZ dS )    N)existsjoinsplit)INTERPRETER_DIR_TPLSPUBLIC_DIR_REOLD_SITE_DIRSz
    (?:\#!\s*){0,1}  # shebang prefix
    (?P<path>
        .*?/bin/.*?)?
    (?P<name>
        python|pypy)
    (?P<version>
        \d[\.\d]*)?
    (?P<debug>
        -dbg)?
    (?P<options>.*)
    an  
    (?P<name>.*?)
    (?:\.
        (?P<stableabi>abi\d+)
     |(?:\.
        (?P<soabi>
            (?P<impl>cpython|pypy)
            -
            (?P<ver>\d{2,})
            (?P<flags>[a-z]*)
        )?
        (?:
            (?:(?<!\.)-)?  # minus sign only if soabi is defined
            (?P<multiarch>[^/]*?)
        )?
    ))?
    (?P<debug>_d)?
    \.so$dhpythonc                   `   e Zd ZdZdZdZdZdZdZdZ	i Z
	 	 d$dZd	 Zd
 Zd Zd%dZd&dZed             Zed             Zed             Zed             Zd'dZd'dZd Zd Zd&dZd&dZd&dZd&dZd&dZ d&dZ!ed             Z"ed             Z#ed             Z$d&dZ%d  Z&d&d!Z'd(d#Z(dS ))Interpretera  
    :attr path: /usr/bin/ in most cases
    :attr name: pypy or python (even for python3 and python-dbg) or empty string
    :attr version: interpreter's version
    :attr debug: -dbg version of the interpreter
    :attr impl: implementation (cpytho2, cpython3 or pypy)
    :attr options: options parsed from shebang
    :type path: str
    :type name: str
    :type version: Version or None
    :type debug: bool
    :type impl: str
    :type options: tuple
    z	/usr/bin/pythonNF  c                 :   t                      }|d= |d= t          |t                    r3|                                D ]}	||	         t	          ||	          ||	<   ny|rw|                    dd                                          r|st          |          |d<   n:|                     |          	                                D ]\  }	}
||	         |
||	<   |	                                D ]0\  }	}
|
t          | |	|
           |	dk    rt          | |	|
           1d S )Nselfvalue.r   version)locals
isinstancer   keysgetattrreplaceisdigitVersionparseitemssetattr)r   r   pathnamer   debugimploptionsparamskeyvals              ,/usr/share/dh-python/dhpython/interpreter.py__init__zInterpreter.__init__S   sI   6N7Oe[)) 	*{{}} 6 6#;&")%"5"5F3K6  		*}}S"%%--// * *$+ENNy!! !%

5 1 1 7 7 9 9 * *HCc{*&)s 	( 	(HCc3''''	!!c3'''		( 	(    c                    |dk    rZ|dvrt          d|z            |dk    r-| j        r%| j        j        dk    rd| j        d<   n_d| j        d<   nT|d	k    r
d	| j        d<   nC|d
k    r=|;t	          |          }| j        s%| j        dk    r|j        dk    rd| _        nd| _        |dv r|d S |dk    rt          |          | j        |<   d S || j        |<   d S )Nr   )r   pypyr   zinterpreter not supported: %sr      cpython3r!   cpython2r*   r   )r   r   r!   r"   r    )
ValueErrorr   major__dict__r   r!   r   bool)r   r   r   s      r&   __setattr__zInterpreter.__setattr__n   s   6>>222 !@5!HIII  < ;|)Q..0:f--0:f-&(.f%Y5#4ENNE9 +h!6!6;!## *DII *DI6665=DW__"&u++DM$"'DM$r(   c                     | j         }|                    d          s|dz  }||                     | j                  z  }| j        r |dd                    | j                  z   z  }|S )N/ )r   endswith_vstrr   r"   r   r   results     r&   __repr__zInterpreter.__repr__   sj    s## 	cMF$**T\***< 	3cCHHT\2222Fr(   c                 6    |                      | j                  S N)r7   r   r   s    r&   __str__zInterpreter.__str__   s    zz$,'''r(   c                     | j         dk    r| j        S |p| j        pd}|r|r|| j        k    r| j         dk    rdnd}| j        rd                    |          S | j        t          |          z   S )Nr*   r   r,   32zpython{}-dbg)r!   r   r   default_versionr    formatstr)r   r   consider_default_vers      r&   r7   zInterpreter._vstr   s    99/T\/R 	> 	>Gt?S4S4S!Y*44cc#G: 	2!((111y3w<<''r(   c                 ^    d                     | j        |                     |                    S )N{}{}rC   r   r7   r   r   s     r&   binaryzInterpreter.binary   s$    }}TY

7(;(;<<<r(   c                 `    d                     | j        |                     d                    S )zLike binary(), but returns path to default intepreter symlink
        if version matches default one for given implementation.
        rG   T)rE   rH   r=   s    r&   	binary_dvzInterpreter.binary_dv   s(    
 }}TY


(M(MNNNr(   c                 <    | j         rt          | j                   S d S r<   )r!   defaultr=   s    r&   rB   zInterpreter.default_version   s&    9 	&49%%%	& 	&r(   c                     t                               |           }|si S |                                }d|v r*t          |d                                                   |d<   |d         dk    r|d         d|d<   |S )a^  Return dict with parsed shebang

        >>> sorted(Interpreter.parse('/usr/bin/python3.2-dbg').items())
        [('debug', '-dbg'), ('name', 'python'), ('options', ()), ('path', '/usr/bin/'), ('version', '3.2')]
        >>> sorted(Interpreter.parse('#! /usr/bin/python3.2').items())
        [('debug', None), ('name', 'python'), ('options', ()), ('path', '/usr/bin/'), ('version', '3.2')]
        >>> sorted(Interpreter.parse('/usr/bin/python3.2-dbg --foo --bar').items())
        [('debug', '-dbg'), ('name', 'python'), ('options', ('--foo', '--bar')), ('path', '/usr/bin/'), ('version', '3.2')]
        r"   r   r   r   NrA   )
SHEBANG_REsearch	groupdicttupler   )shebangr9   s     r&   r   zInterpreter.parse   s     ""7++ 	I!!## %fY&7&=&=&?&? @ @F9&>X%%&*;*C #F9r(   c                    t                      }t          |d          5 }|                    d          }d|v rt          d          	 ddd           n# 1 swxY w Y   t	          |d                              d          d         }|                    d	          st          d
|z            |                     |          }|st          d
|z            |                                D ]\  }}t          |||           |S )z!Read file's shebang and parse it.rb`       zcannot parse binary fileNzutf-8
r   z#!zdoesn't look like a shebang: %s)
r   openreadr.   rD   r   
startswithr   r   r   )clsfpathinterpreterfpdataparsedr$   r%   s           r&   	from_filezInterpreter.from_file   sJ    "mm% 	="772;;D}} !;<<< 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=
 4!!''--a0t$$ 	G>EFFF4 	G>EFFF 	+ 	+HCKc****s   )AAAc                    	 t          |p| j                  }n$# t          $ r}t          d|z            d}~ww xY w| j        dk    rd}n2|t          d          z  rd|z  }n|t          d          z  rd|z  }nd	}|rd
|z  }|rd||}|S )a  Return path to site-packages directory.

        Note that returned path is not the final location of .py files

        >>> i = Interpreter('python')
        >>> i.sitedir(version='3.1')
        '/usr/lib/python3/dist-packages/'
        >>> i.sitedir(version='2.5')
        '/usr/lib/python2.5/site-packages/'
        >>> i.sitedir(version=Version('2.7'))
        '/usr/lib/python2.7/dist-packages/'
        >>> i.sitedir(version='3.1', gdb=True, package='python3-foo')
        'debian/python3-foo/usr/lib/debug/usr/lib/python3/dist-packages/'
        >>> i.sitedir(version=Version('3.2'))
        '/usr/lib/python3/dist-packages/'
        cannot find valid version: %sNr*   z/usr/lib/pypy/dist-packages/2.6z /usr/lib/python%s/site-packages/z3.0z /usr/lib/python%s/dist-packages/z/usr/lib/python3/dist-packages/z/usr/lib/debug%szdebian/)r   r   	Exceptionr.   r!   )r   packager   gdberrr   s         r&   sitedirzInterpreter.sitedir   s    "	Dg566GG 	D 	D 	D<sBCCC	D91DD& 	55?DD& 	55?DD4D 	-%,D 	3 	3$+GTT2Ds    
:5:c                 >   	 t          |p| j                  }n$# t          $ r}t          d|z            d}~ww xY wg }t	          j        | j        g           D ]b}t          |t                    r)|	                    |
                    |                     @ ||          }||	                    |           c|rNd |D             }| j                            d          r(|	                    d
                    |                     rfd|D             }|S )z5Return deprecated paths to site-packages directories.re   Nc                 8    g | ]}d                      |          S )z/usr/lib/debug{}rC   .0is     r&   
<listcomp>z,Interpreter.old_sitedirs.<locals>.<listcomp>  s'    CCCq(//22CCCr(   cpythonz(/usr/lib/debug/usr/lib/pyshared/python{}c                 <    g | ]}d                      |          S )zdebian/{}{}rn   )rp   rq   rh   s     r&   rr   z,Interpreter.old_sitedirs.<locals>.<listcomp>  s)    GGG1m**7A66GGGr(   )r   r   rg   r.   r   getr!   r   rD   appendrC   r\   )r   rh   r   ri   rj   r9   itemress    `      r&   old_sitedirszInterpreter.old_sitedirs   sO   	Dg566GG 	D 	D 	D<sBCCC	D!%di44 	' 	'D$$$ 'dkk'223333d7mm?MM#&&& 	ZCCFCCCFy##I.. ZHOOPWXXYYY 	HGGGGGGGFs    
;6;c                     t           | j                                     |          }|r0|                    d          }|r|d         rt	          |          S dS dS )z]Return version assigned to site-packages path
        or True is it's unversioned public dir.r   TN)r   r!   matchgroupsr   )r   r   r{   verss       r&   parse_public_dirzInterpreter.parse_public_dir  sc     di(..t44 	<<??D %Q %t}}$4		 	r(   c                 b    d                      j                  }| j        j        vr` fdt	          j                    D             }t          j        d                    d |D                                 }| j        j        |<   n j        j        |         }|	                    |          S )zBReturn True if path is used by another interpreter implementation.zshould_ignore_{}c                 0    g | ]\  }}|j         k    |S r   )r!   )rp   kvr   s      r&   rr   z-Interpreter.should_ignore.<locals>.<listcomp>$  s$    QQQ$!Q!ty..A...r(   |c              3   @   K   | ]}d                      |          V  dS )z({})Nrn   ro   s     r&   	<genexpr>z,Interpreter.should_ignore.<locals>.<genexpr>%  s.      (H(Haq)9)9(H(H(H(H(H(Hr(   )
rC   r!   	__class___cacher   r   recompiler   rQ   )r   r   	cache_keyexprregexps   `    r&   should_ignorezInterpreter.should_ignore   s    &--di88	DN111QQQQ"6"<">">QQQDZ(H(H4(H(H(H H HIIF/5DN!),,^*95F}}T"""r(   c           	      8   t          |p| j                  }d| j        v rdnd}|t          d          k    r||z   S t          |          \  }}|                    d          s|dz  }t          |d|dd         d	|                     |          d|          S )
a  Given path to a .py file, return path to its .pyc/.pyo file.

        This function is inspired by Python 3.2's imp.cache_from_source.

        :param fpath: path to file name
        :param version: Python version

        >>> i = Interpreter('python')
        >>> i.cache_file('foo.py', Version('3.1'))
        'foo.pyc'
        >>> i.cache_file('bar/foo.py', '3.8')          # doctest: +SKIP
        'bar/__pycache__/foo.cpython-38.pyc'
        z-Ooc3.1z.py__pycache__Nr   )r   r   r"   r   r6   r   	magic_tag)r   r^   r   	last_charfdirfnames         r&   
cache_filezInterpreter.cache_file+  s     '1T\224<//CCS	genn$$9$$Elle~~e$$ 	UNED-3B3ZZZ!8!8!8!8))*E F F 	Fr(   c                     t          |p| j                  }| j        dk    rdS |                     d|          }t	          |          S )zReturn magic number.r-   r   z"import imp; print(imp.get_magic()))r   r   r!   _executeeval)r   r   r9   s      r&   magic_numberzInterpreter.magic_numberD  sH    '1T\229
""2CWMMF||r(   c                     t          |p| j                  }| j                            d          r|t          d          z  rdS |                     d|          S )zReturn Python magic tag (used in __pycache__ dir to tag files).

        >>> i = Interpreter('python')
        >>> i.magic_tag(version='3.8')                 # doctest: +SKIP
        'cpython-38'
        rs   3.2r   z import imp; print(imp.get_tag()))r   r   r!   r\   r   rI   s     r&   r   zInterpreter.magic_tagL  s\     '1T\229	** 	w'%../H 	2}}?IIIr(   c                     t          |p| j                  }	 |                     |          dd         \  }}n-# t          $ r  t                              dd           Y dS w xY w|S )zReturn multiarch tag.N   zcannot get multiarchTexc_infor   r   r   _get_configrg   logr    r   r   soabi	multiarchs       r&   r   zInterpreter.multiarchX  s    '1T\22	#//88!<E99 	 	 	II,tI<<<22	     9 &A#"A#c                     t          |p| j                  }| j        dk    r,|t          d          z	  rd                    |j                  S d S d S )Nr,   r   zabi{})r   r   r!   rC   r/   rI   s     r&   	stableabizInterpreter.stableabic  sU    '1T\229
""w'%..'@">>'-000 #"""r(   c                     t          |p| j                  }	 |                     |          dd         \  }}n-# t          $ r  t                              dd           Y dS w xY w|S )z)Return SOABI flag (used to in .so files).Nr   zcannot get soabiTr   r   r   r   s       r&   r   zInterpreter.soabii  s~    '1T\22	#//88!<E99 	 	 	II(4I88822	 r   c                    | j         dk    rdS 	 |                                 d         }|r|S n.# t          $ r! d}t                              dd           Y nw xY wd                    | j                  }| j        }| j        r|d	k    r|d
z  }n.|dz  r|dz  }n#|dz  }n|d	k    rn|dz	  r|dz  }n|dk    r|dz  }|S )zReturn INCLUDE_DIR path.

        >>> Interpreter('python2.7').include_dir       # doctest: +SKIP
        '/usr/include/python2.7'
        >>> Interpreter('python3.8-dbg').include_dir   # doctest: +SKIP
        '/usr/include/python3.8d'
        r*   z/usr/lib/pypy/includer   r   cannot get include pathTr   /usr/include/{}z3.8d3.3_ddmr   mmu)r!   r   rg   r   r    rC   r   r   )r   r9   r   s      r&   include_dirzInterpreter.include_diru  s&    9**	@%%''*F  	@ 	@ 	@FII/$I?????	@ #))$)44,: 	%#E! $$%E! #E!!$s   . (AAc                 \   | j         dv s| j        s| j        dz	  s
| j        dz  rdS 	 |                                 d         }|r!|                    d          r
|dd         S dS nF# t
          $ r9 d                    | j                  }t                              d	d
           Y nw xY w|S )z+Return path to symlinked include directory.)r-   r*   z3.7r   Nr   r   r   r   Tr   )	r!   r    r   r   r6   rg   rC   r   r   r8   s     r&   symlinked_include_dirz!Interpreter.symlinked_include_dir  s     9,,,
,le# -'+|u'< - F
	@%%''*F ??3'' !#2#;& F  	@ 	@ 	@&--di88FII/$I?????	@ s   :A& &A B)(B)c                    | j         dk    rdS |                                 dd         \  }}|                    d          r|                    dd          }|r|rt	          ||          S t          d                    |                     )zReturn libfoo.so file path.r*   r   r+      z.a.sozcannot find library file for {})r!   r   r6   r   r   rg   rC   )r   libpl	ldlibrarys      r&   library_filezInterpreter.library_file  s     92++--ac2yd## 	7!))$66I 	*Y 	*y)))9@@FFGGGr(   c                    |s	| j         sdS t          |p| j                   }d|v r|                    dd          \  }}nd}t                              |          }|sdS |                                }|d         r5|r|j        ,t          |d         d         d|d         d                   }|d         rdS |d	         r| j        d
u rdS |d         r
|d         rdS 	 |                     |          dd         \  }}n-# t          $ r  t                              dd           Y dS w xY w|d         r|r|d         |k    rdS |d         p|}|d         p|}|d         }	|	                    d          r1|	dk    r+| j        dk    r|dz	  s| j        dk    r|dk    r
|	dd         }	|rCd                    |	|          }	|r*| j        dk    r|dz  s||vrd                    |	|          }	n)| j        dk    r|dk    r|rd                    |	|          }	| j        r| j        dk    r|	dz  }	|	dz  }	||	k    rdS t          ||	          S )z2Return extension file name if file can be renamed.Nr4      r   verr   r   r   r    Fr   r   r   zcannot get soabi/multiarchTr   r   moduler,   r   r-   z2.7iz{}.{}r   z{}-{}r   r   )r   r   rsplit
EXTFILE_RErQ   rR   minorr    r   rg   r   r6   r!   rC   r   )
r   r   r   r   infor   r   	tmp_soabitmp_multiarchr9   s
             r&   check_extnamezInterpreter.check_extname  s    	t| 	F'1T\22%<<,,sA..KD%%D  '' 	F~~; 	J 	J7=+@ eQeQHIIG 	F= 	TZ500 F= 	T+. 	F	#//88!<E99 	 	 	II2TIBBBFF	 = 	U 	tG}'='=FM*U	[)6Yf??8$$ 	!8););9
""w%'7"9
""w%'7'7CRC[F 	;^^FI66F ?di:&=&='UBR&=XemrXrXr >>Y*$$E)9)9m)9^^FM::F: 	$)z11dNF%F??FD&!!!s   ! D &D,+D,c                     |                     dd          }| j        dk    rd                    |          S | j        dk    rdnd}d                    ||          }| j        r|d	z  }|S )
aI  Suggest binary package name with for given library name

        >>> Interpreter('python3.1').suggest_pkg_name('foo')
        'python3-foo'
        >>> Interpreter('python3.8').suggest_pkg_name('foo_bar')
        'python3-foo-bar'
        >>> Interpreter('python2.7-dbg').suggest_pkg_name('bar')
        'python-bar-dbg'
        _-r*   zpypy-{}r,   r@   r   zpython{}-{}z-dbg)r   r!   rC   r    )r   r   r   r9   s       r&   suggest_pkg_namezInterpreter.suggest_pkg_name  s{     ||C%%9##D)))j00##b%%gt44: 	fFr(   c                    t          |p| j                  }| j        dk    s/| j                            d          r|dz	  r|dz  s|dz	  s|dk    rd}nd}|dz  }|                     ||                              d	          }|d
         |d         v r(|d                             d|d
         z  d          |d<   	 t          j        d         |d
<   n# t          $ r Y nw xY w|S )Nr*   rs   rf   r@   r   zimport sysconfig as s;z%from distutils import sysconfig as s;zrprint("__SEP__".join(i or "" for i in s.get_config_vars("SOABI", "MULTIARCH", "INCLUDEPY", "LIBPL", "LDLIBRARY")))__SEP__r   r   z-%sr   DEB_HOST_MULTIARCH)
r   r   r!   r\   r   r   r   osenvironKeyError)r   r   cmd	conf_varss       r&   r   zInterpreter._get_config  s    '1T\22 9$)"6"6y"A"A5  %,^ e# '.#~~*CC9C L 	L MM#w//55i@@	Q<9Q<''$Q<//	!0DbIIIaL	:&:;IaLL 	 	 	D	s   =C 
C C Tc                    t          |p| j                  }d                    | j        |                     |                    }d                    ||                    dd                    }|r || j        j        v r| j        j        |         S t          |          st          d|z            t          |          }|d         dk    rIt                              |d                    t          d                    ||d                             |d	                                         }t          |          d
k    r|d         }|r|| j        j        |<   |S )NrG   z
{} -c '{}''z5cannot execute command due to missing interpreter: %s
returncoder   stderrz{} failed with status code {}stdoutr   )r   r   rC   r   r7   r   r   r   r   rg   executer   r    
splitlineslen)r   commandr   cacheexeoutputr9   s          r&   r   zInterpreter._execute%  sU   '1T\22mmDItzz'':':;;%%c7??3+E+EFF 	2W 555>(11c{{ 	5 .034 5 5 5 !!,1$$IIfX&''';BB7FS_L`aabbb!,,..v;;!AYF 	4-3DN!'*r(   )NNNNNNN)NFr<   )NNF)NT))__name__
__module____qualname____doc__r   r   r   r    r!   r"   r   r'   r2   r:   r>   r7   rJ   propertyrL   rB   staticmethodr   classmethodrc   rk   ry   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r(   r&   r   r   <   s         DDGEDGFAE04( ( ( (6( ( (4  ( ( (	( 	( 	( 	(= = = = O O XO & & X&   \,   [&# # # #J   0  	# 	# 	#F F F F2   
J 
J 
J 
J	 	 	 	1 1 1 1
 
 
 
 ! ! X!F   X( 
H 
H X
H>" >" >" >"@  &   .     r(   r   )r   )r   rN   )loggingr   r   os.pathr   r   r   r	   r   r   r   r   VERBOSErP   r   	getLoggerr   r   dhpython.toolsr   dhpython.versionr   rN   r   r(   r&   <module>r      s  *  				 				 ' ' ' ' ' ' ' ' ' ' G G G G G G G G G GRZ  
 
 RZ " j# 
$ g
##@ @ @ @ @ @ @ @F # " " " " " - - - - - - - - - -r(   