B
    b                @   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m	Z	m
Z
mZmZ ddlmZ ddlmZ ddlmZmZ ddlmZmZ eedZd	Zded
ddZejZedkrejdkrdZerdd Zndd Ze d
ddZ!e d
ddZ"e d
ddZ#e$d
ddZ%e&d
ddZ'G dd de
Z(e)dZ*ee& d
dd Z+G d!d" d"Z,ddgdfd#d$Z-e d
d%d&Z.e/d'Z0e/d(Z1e/d)Z2e/d*Z3e/d+Z4e/d,Z5e/d-Z6e/d.Z7dd/dgdd/d/fd0d1Z8ee	fZ9e:e
fZ;e:e$e
efZ<e&efZ=e&Z>e?e9fe d
d2d3Z@e?e;fe d
d4d5ZAe?e<fe d
d6d7ZBe?e$fe d
d8d9ZCe?e=fe d
d:d;ZDe?e=e<fe d
d<d=ZEe?e=e<fd>d?ZFe?e=e<eFfe:d
d@dAZGe?e=e<eFfe:d
dBdCZHe?e&ee>fe&d
dDdEZIe?e&e>e<efe&d
dFdGZJeJeKfe&d
dHdIZLded
dJdKZMe:d
dLdMZNe$d
dNdOZOeeMe:eNe$eOiZPdPdQ ZQG dRdS dSZRG dTdU dUZSG dVdW dWZTd/ZUyddlVZVdXZUeVZWW n* eXk
r   G dYdZ dZeYZZeZZ[Y nX eUreWj\Z\eWj]Z]eWj^Z^eWj_Z_eVj`ZaeVjbZceVjdZeeVjfZgeVjhZ[d[d\ Zin dZ\dZ]dZ^dZ_d]d\ Zid^d_ Zaejdkr6dee& d
d`daZjn6ejkdbkrXdee& d
dcdaZjndee& d
dddaZjdeej_ ejldXdfee:e&f d
dfdgZmejldXdfee:e&f d
dhdiZnejlfdjdkZoejdlkrddlpZpe&d
dmdnZqne&d
dodnZqdpeq_ e, Zre:d
dqdrZsG dsdt dte
ZtG dudv dveZuejdlkrHe d
dwdxZvne d
dydxZvde&d
dzd{Zwd|d} Zxdd~dZydd Zzdj{fddZ|G dd dZ}G dd de
Z~G dd dZe&d
ddZdddZdddgZg adadaefddZefddZee dd ZeefddZeefddZed dd ZeefddZdddZdddZdddZd/add Zdd ZdddZdd Zdd ZG dd dZG dd deZed
ddZe&d
ddZe d
ddZde d
ddZde d
ddZdd Zdd ZdS )z Various SCons utility functions.    N)UserDictUserList
UserStringOrderedDict)MappingView)suppress)
MethodTypeFunctionType)OptionalUnionZpypy_translation_infoZSCONS_MAGIC_MISSING_FILE_STRING)returnc             C   s    |d kri }| t| | |S )N)updatezip)keysvaluesresult r   )lib/python3.7/site-packages/SCons/Util.pydictify5   s    r   win32/c             C   s   t | || tS )N)maxrfind_ALTSEP)pathsepr   r   r   rightmost_separator@   s    r   c             C   s
   |  |S )N)r   )r   r   r   r   r   r   C   s    c                s   t  fdd|D S )z<Check whether string `s` contains ANY of the items in `pat`.c             3   s   | ]}| kV  qd S )Nr   ).0c)sr   r   	<genexpr>J   s    zcontainsAny.<locals>.<genexpr>)any)r   patr   )r   r   containsAnyH   s    r#   c                s   t  fdd|D S )z<Check whether string `s` contains ALL of the items in `pat`.c             3   s   | ]}| kV  qd S )Nr   )r   r   )r   r   r   r    N   s    zcontainsAll.<locals>.<genexpr>)all)r   r"   r   )r   r   containsAllL   s    r%   c             C   s   x| D ]}||krdS qW dS )z6Check whether string `s` contains ONLY items in `pat`.FTr   )r   r"   r   r   r   r   containsOnlyP   s    
r&   c             C   sR   t | tj}| d}||krJ| |d d  sJ| d| | |d fS | dfS )z[Split `path` into a (root, ext) pair.

    Same as :mod:`os.path.splitext` but faster.
    .   N )r   osr   r   isdigit)r   r   dotr   r   r   splitextY   s
    
r-   c             C   s$   t j| \}}|r | | } | S )zMake the drive letter (if any) upper case.

    This is useful because Windows is inconsistent on the case
    of the drive letter, which can cause inconsistencies when
    calculating command signatures.
    )r*   r   
splitdriveupper)r   Zdriverestr   r   r   updrivef   s    r1   c               @   sL   e Zd ZdZdd Zdd Zdd Zd dd	d
Zd dddZdd Z	dS )NodeLista?  A list of Nodes with special attribute retrieval.

    Unlike an ordinary list, access to a member's attribute returns a
    `NodeList` containing the same attribute for each member.  Although
    this can hold any object, it is intended for use when processing
    Nodes, where fetching an attribute of each member is very commone,
    for example getting the content signature of each node.  The term
    "attribute" here includes the string representation.

    Example:

    >>> someList = NodeList(['  foo  ', '  bar  '])
    >>> someList.strip()
    ['foo', 'bar']
    c             C   s
   t | jS )N)booldata)selfr   r   r   __bool__   s    zNodeList.__bool__c             C   s   d tt| jS )N )joinmapstrr4   )r5   r   r   r   __str__   s    zNodeList.__str__c             C   s
   t | jS )N)iterr4   )r5   r   r   r   __iter__   s    zNodeList.__iter__)r   c                s     fdd| j D }| |S )Nc                s   g | ]}| qS r   r   )r   x)argskwargsr   r   
<listcomp>   s    z%NodeList.__call__.<locals>.<listcomp>)r4   	__class__)r5   r?   r@   r   r   )r?   r@   r   __call__   s    zNodeList.__call__c                s    fdd| j D }| |S )z.Returns a NodeList of `name` from each member.c                s   g | ]}t | qS r   )getattr)r   r>   )namer   r   rA      s    z(NodeList.__getattr__.<locals>.<listcomp>)r4   rB   )r5   rE   r   r   )rE   r   __getattr__   s    zNodeList.__getattr__c             C   s$   t |tr| | j| S | j| S )z<Returns one item, forces a `NodeList` if `index` is a slice.)
isinstanceslicerB   r4   )r5   indexr   r   r   __getitem__   s    
zNodeList.__getitem__N)
__name__
__module____qualname____doc__r6   r;   r=   rC   rF   rJ   r   r   r   r   r2   r   s   r2   z!^\$([_a-zA-Z]\w*|{[_a-zA-Z]\w*})$c             C   s<   t t| }|r8|d}|d dkr4|dd S |S dS )a  Return undecorated construction variable string.

    Determine if `varstr` looks like a reference
    to a single environment variable, like `"$FOO"` or `"${FOO}"`.
    If so, return that variable with no decorations, like `"FOO"`.
    If not, return `None`.
    r(   r   {N)_get_env_varmatch	to_Stringgroup)ZvarstrZmovarr   r   r   get_environment_var   s    	
rV   c               @   s&   e Zd ZdZdZd	ddZdd ZdS )
DisplayEnginez0A callable class used to display SCons messages.Tr(   c             C   sD   | j s
d S |r|d }ytjt| W n tk
r>   Y nX d S )N
)print_itsysstdoutwriter:   IOError)r5   textZappend_newliner   r   r   rC      s    zDisplayEngine.__call__c             C   s
   || _ d S )N)rY   )r5   moder   r   r   set_mode   s    zDisplayEngine.set_modeN)r(   )rK   rL   rM   rN   rY   rC   r`   r   r   r   r   rW      s   
rW   c             C   s   t | }|dkri }|| }d}x*|dd D ]}|r@|d }q.|d }q.W ||krd|d | d S |d | d	 }|st|}d
||< xFt|D ]:\}	}
||	t|d k  |t|
|||| }|  qW |S )a  Render a tree of nodes into an ASCII tree view.

    Args:
        root: the root node of the tree
        child_func: the function called to get the children of a node
        prune: don't visit the same node twice
        margin: the format of the left margin to use for children of `root`.
          1 results in a pipe, and 0 results in no pipe.
        visited: a dictionary of visited nodes in the current branch if
          `prune` is 0, or in the whole tree if `prune` is 1.
    Nr)   rP   z| z  z+-[z]
z+-rX   Tr(   )r:   copy	enumerateappendlenrender_treepop)root
child_funcprunemarginvisitedrnamechildrenZretvalpipeiZchildr   r   r   re      s(    

re   c             C   s   t | S )zzGenerate in index into strings from the tree legends.

    These are always a choice between two, so bool works fine.
    )r3   )nr   r   r   IDX   s    rq   i %  i%  i%  i%  i%  i%  i%  i,%  Fc                sF  t | }|dkri }|r|dkr0d}	tj|	 ddt|   dt|  oT|    ddd	gt|   ddgt|     d
t| j	 dt| j
 dt| j dt|   dt| j dt| j dg}
ng }
 fdd}tt||dd }|| }d} rPtt }|r"tt }|rP|rH||krH|rH|t7 }n|t7 }|r||kr|rtjd|
| |d|dg d  dS tjd|
| ||g d  d	||< |rB|d	 t|}d}x@|dd D ]0}|d	 }t||||||t|| dk  qW d|d< t|d |||||d  |  dS )a  Print a tree of nodes.

    This is like func:`render_tree`, except it prints lines directly instead
    of creating a string representation in memory, so that huge trees can
    be handled.

    Args:
        root: the root node of the tree
        child_func: the function called to get the children of a node
        prune: don't visit the same node twice
        showtags: print status information to the left of each node line
        margin: the format of the left margin to use for children of `root`.
          1 results in a pipe, and 0 results in no pipe.
        visited: a dictionary of visited nodes in the current branch if
          prune` is 0, or in the whole tree if `prune` is 1.
        singleLineDraw: use line-drawing characters rather than ASCII.
    N   a   E         = exists
  R        = exists in repository only
   b       = implicit builder
   B       = explicit builder
    S      = side effect
     P     = precious
      A    = always build
       C   = current
        N  = no clean
         H = no cache

[z Ez Rz BbBr   r(   z Sz Pz Az Cz Nz H]c                s     rdt d g|  S ddg|  S )Nz  r7   z| )BOX_VERT)m)singleLineDrawr   r   MMMR  s    zprint_tree.<locals>.MMMrP   z+-r)   rX   T)r:   rZ   r[   r\   rq   existsZrexistsZhas_explicit_builderZhas_builderZside_effectZpreciousZalways_buildZis_up_to_dateZnocleanZnocachelistr9   BOX_VERT_RIGHT	BOX_HORIZBOX_UP_RIGHTBOX_HORIZ_DOWNr8   rc   
print_treerd   rf   )rg   rh   ri   Zshowtagsrj   rk   Z	lastChildrw   rl   ZlegendZtagsrx   Zmarginsrm   ZcrossidxZ_childCr   )rw   r   r     sp    

&"
r   c             C   s
   || |S )Nr   )objrG   	DictTypesr   r   r   is_Dict  s    r   c             C   s
   || |S )Nr   )r   rG   	ListTypesr   r   r   is_List  s    r   c             C   s
   || |S )Nr   )r   rG   SequenceTypesr   r   r   is_Sequence  s    r   c             C   s
   || |S )Nr   )r   rG   tupler   r   r   is_Tuple  s    r   c             C   s
   || |S )Nr   )r   rG   StringTypesr   r   r   	is_String  s    r   c             C   s   || |p|| | S )Nr   )r   rG   r   r   r   r   r   	is_Scalar  s    
r   c             C   s<   x6| D ].}|||s|||s*| | qt|| qW d S )N)rc   
do_flatten)sequencer   rG   r   r   itemr   r   r   r     s    
r   c             C   sZ   || |s|| |s| gS g }x6| D ].}|||s<|||sH| | q$||| q$W |S )zFlatten a sequence to a non-nested list.

    Converts either a single scalar or a nested sequence to a non-nested list.
    Note that :func:`flatten` considers strings
    to be scalars instead of sequences like pure Python would.
    )rc   )r   rG   r   r   r   r   r   r   r   r   flatten  s    
r   c             C   s@   g }x6| D ].}|||s"|||s.| | q
||| q
W |S )zFlatten a sequence to a non-nested list.

    Same as :func:`flatten`, but it does not handle the single scalar case.
    This is slightly more efficient when one knows that the sequence
    to flatten can not be a scalar.
    )rc   )r   rG   r   r   r   r   r   r   r   r   flatten_sequence  s    
r   c             C   s&   || |r| S || |r| j S || S )zReturn a string version of obj.)r4   )r   rG   r:   r   BaseStringTypesr   r   r   rS     s
    	

rS   c             C   sD   || |r| S || |r,d dd | D S || |r<| jS || S )z/Return a string version of obj for subst usage.r7   c             S   s   g | ]}t |qS r   )to_String_for_subst)r   er   r   r   rA   6  s    z'to_String_for_subst.<locals>.<listcomp>)r8   r4   )r   rG   r:   r   r   r   r   r   r   r   '  s    


r   c             C   sF   y
| j }W n0 |k
r:   t| tr2tj| ddS || S X | S dS )zReturn a string version of obj for signature usage.

    Like :func:`to_String_for_subst` but has special handling for
    scons objects that have a :meth:`for_signature` method, and for dicts.
    i@B )widthN)Zfor_signaturerG   dictpprintZpformat)r   r   AttributeErrorfr   r   r   to_String_for_signature>  s    	


r   c                s"    d krg   fdd|   D S )Nc                s"   i | ]\}}| krt ||qS r   )semi_deepcopy)r   kv)excluder   r   
<dictcomp>e  s    z&semi_deepcopy_dict.<locals>.<dictcomp>)items)r   r   r   )r   r   semi_deepcopy_dictb  s    r   c             C   s   dd | D S )Nc             S   s   g | ]}t |qS r   )r   )r   r   r   r   r   rA   h  s    z'_semi_deepcopy_list.<locals>.<listcomp>r   )r   r   r   r   _semi_deepcopy_listg  s    r   c             C   s   t tt| S )N)r   r9   r   )r   r   r   r   _semi_deepcopy_tuplej  s    r   c             C   sj   t t| }|r|| S t| dr6t| jr6|  S t| trN| t	| S t| t
rf| t| S | S )N__semi_deepcopy__)_semi_deepcopy_dispatchgettypehasattrcallabler   rG   r   rB   r   r   r   )r   Zcopierr   r   r   r   s  s    

r   c               @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )Proxya  A simple generic Proxy class, forwarding all calls to subject.

    This means you can take an object, let's call it `'obj_a`,
    and wrap it in this Proxy class, with a statement like this::

        proxy_obj = Proxy(obj_a)

    Then, if in the future, you do something like this::

        x = proxy_obj.var1

    since the :class:`Proxy` class does not have a :attr:`var1` attribute
    (but presumably `objA` does), the request actually is equivalent to saying::

        x = obj_a.var1

    Inherit from this class to create a Proxy.

    With Python 3.5+ this does *not* work transparently
    for :class:`Proxy` subclasses that use special .__*__() method names,
    because those names are now bound to the class, not the individual
    instances.  You now need to know in advance which special method names you
    want to pass on to the underlying Proxy object, and specifically delegate
    their calls like this::

        class Foo(Proxy):
            __str__ = Delegate('__str__')
    c             C   s
   || _ dS )z Wrap an object as a Proxy objectN)_subject)r5   Zsubjectr   r   r   __init__  s    zProxy.__init__c             C   s   t | j|S )zRetrieve an attribute from the wrapped object.

        Raises:
           AttributeError: if attribute `name` doesn't exist.
        )rD   r   )r5   rE   r   r   r   rF     s    zProxy.__getattr__c             C   s   | j S )z"Retrieve the entire wrapped object)r   )r5   r   r   r   r     s    z	Proxy.getc             C   s&   t |j| jjr| j|kS | j|jkS )N)
issubclassrB   r   __dict__)r5   otherr   r   r   __eq__  s    
zProxy.__eq__N)rK   rL   rM   rN   r   rF   r   r   r   r   r   r   r     s
   r   c               @   s    e Zd ZdZdd Zdd ZdS )DelegatezA Python Descriptor class that delegates attribute fetches
    to an underlying wrapped subject of a Proxy.  Typical use::

        class Foo(Proxy):
            __str__ = Delegate('__str__')
    c             C   s
   || _ d S )N)	attribute)r5   r   r   r   r   r     s    zDelegate.__init__c             C   s   t ||rt|j| jS | S )N)rG   rD   r   r   )r5   r   clsr   r   r   __get__  s    
zDelegate.__get__N)rK   rL   rM   rN   r   r   r   r   r   r   r     s   r   c               @   s*   e Zd ZdZd	ddZdd Zdd ZdS )
MethodWrappera  A generic Wrapper class that associates a method with an object.

    As part of creating this MethodWrapper object an attribute with the
    specified name (by default, the name of the supplied method) is added
    to the underlying object.  When that new "method" is called, our
    :meth:`__call__` method adds the object as the first argument, simulating
    the Python behavior of supplying "self" on method calls.

    We hang on to the name by which the method was added to the underlying
    base class so that we can provide a method to "clone" ourselves onto
    a new underlying object being copied (without which we wouldn't need
    to save that info).
    Nc             C   s2   |d kr|j }|| _|| _|| _t| j||  d S )N)rK   objectmethodrE   setattr)r5   r   r   rE   r   r   r   r     s    zMethodWrapper.__init__c             O   s   | j f| }| j||S )N)r   r   )r5   r?   r@   nargsr   r   r   rC     s    zMethodWrapper.__call__c             C   s   |  || j| jS )zn
        Returns an object that re-binds the underlying "method" to
        the specified new object.
        )rB   r   rE   )r5   Z
new_objectr   r   r   clone  s    zMethodWrapper.clone)N)rK   rL   rM   rN   r   rC   r   r   r   r   r   r     s   
r   Tc               @   s   e Zd ZdS )_NoErrorN)rK   rL   rM   r   r   r   r   r     s   r   c             C   s>   | dd }|d|d  }||d }t| |}t||S )a  Returns a registry value without having to open the key first.

        Only available on Windows platforms with a version of Python that
        can read the registry.

        Returns the same thing as :func:`RegQueryValueEx`, except you just
        specify the entire path to the value, and don't have to bother
        opening the key first.  So, instead of::

          k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
                r'SOFTWARE\Microsoft\Windows\CurrentVersion')
          out = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')

        You can write::

          out = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
                r'SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir')
        \r(   N)r   RegOpenKeyExRegQueryValueEx)rg   keypZkeypvalr   r   r   r   RegGetValue  s
    
r   c             C   s   t d S )N)OSError)rg   r   r   r   r   r   &  s    c             C   s   t d S )N)r   )rg   r   r   r   r   r   )  s    r   c          
   C   sL  |d kr,yt jd }W n tk
r*   d S X t|r@|t j}|d krpyt jd }W n tk
rn   d}Y nX t|r|t j}x2|D ]*}| | t| d   krdg}P qW |d krg }t|st	|s|g}xl|D ]d}t j
|| }xP|D ]H}|| }t j
|ry|| W q tk
r<   t j
|S X qqW qW d S )NPATHZPATHEXTz.COM;.EXE;.BAT;.CMDr)   )r*   environKeyErrorr   splitpathseplowerrd   r   r   r   r8   isfilerI   
ValueErrornormpath)filer   pathextrejectextr   r   fextr   r   r   WhereIs/  sB    




r   Zos2c          
   C   s  |d kr,yt jd }W n tk
r*   d S X t|r@|t j}|d krPddg}x2|D ]*}| | t| d   krVdg}P qVW |d krg }t|st	|s|g}xl|D ]d}t j
|| }xP|D ]H}|| }t j
|ry|| W q tk
r   t j
|S X qqW qW d S )Nr   z.exez.cmdr)   )r*   r   r   r   r   r   r   rd   r   r   r   r8   r   rI   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   T  s8    



c          	   C   s   dd l }|d kr4ytjd }W n tk
r2   d S X t|rH|tj}|d krTg }t|sjt|sj|g}x|D ]}tj	
|| }tj	|rpyt |}W n tk
r   wpY nX |||j d@ rpy|| W qp tk
r   tj	|S X qpqpW d S )Nr   r   I   )statr*   r   r   r   r   r   r   r   r   r8   r   r   S_IMODEST_MODErI   r   r   )r   r   r   r   r   r   r   str   r   r   r   t  s4    
a  Return the path to an executable that matches `file`.

Searches the given `path` for `file`, respecting any filename
extensions `pathext` (on the Windows platform only), and
returns the full path to the matching command.  If no
command is found, return ``None``.

If `path` is not specified, :attr:`os.environ[PATH]` is used.
If `pathext` is not specified, :attr:`os.environ[PATHEXT]`
is used. Will not select any path name or names in the optional
`reject` list.
c             C   s~  | }d}|}t |s*t|s*||}d}t|r>||}nt |sVt|sV|g}n|}|rltt||}|sg }	g }
xB|D ]:}|sqtjtj	|}||
kr|	
| |

| qW |  xD|D ]<}|sqtjtj	|}||
kr|	d| |

| qW |	}nX|| }g }
g }xF|D ]>}tjtj	|}|r(||
kr(|
| |

| q(W |rt|S ||S )a  Prepends `newpath` path elements to `oldpath`.

    Will only add any particular path once (leaving the first one it
    encounters and ignoring the rest, to preserve path order), and will
    :mod:`os.path.normpath` and :mod:`os.path.normcase` all paths to help
    assure this.  This can also handle the case where `oldpath`
    is a list instead of a string, in which case a list will be returned
    instead of a string. For example:

    >>> p = PrependPath("/foo/bar:/foo", "/biz/boom:/foo")
    >>> print(p)
    /biz/boom:/foo:/foo/bar

    If `delete_existing` is ``False``, then adding a path that exists will
    not move it to the beginning; it will stay where it is in the list.

    >>> p = PrependPath("/foo/bar:/foo", "/biz/boom:/foo", delete_existing=False)
    >>> print(p)
    /biz/boom:/foo/bar:/foo

    If `canonicalize` is not ``None``, it is applied to each element of
    `newpath` before use.
    TFr   )r   r   r   r   rz   r9   r*   r   r   normcaserc   reverseinsertr8   )oldpathnewpathr   delete_existingcanonicalizeorigis_listpathsnewpathsr   	normpathsr   r   r   r   r   PrependPath  sV    





r   c             C   sv  | }d}|}t |s*t|s*||}d}t|r>||}nt |sVt|sV|g}n|}|rltt||}|sg }	g }
x6|D ].}|sq~|	| |
tj	tj
| q~W xB|D ]:}|sqtj	tj
|}||
kr|	| |
| qW |	}nh|| }|  g }
g }xF|D ]>}tj	tj
|}|r||
kr|| |
| qW |  |rl|S ||S )a  Appends `newpath` path elements to `oldpath`.

    Will only add any particular path once (leaving the last one it
    encounters and ignoring the rest, to preserve path order), and will
    :mod:`os.path.normpath` and :mod:`os.path.normcase` all paths to help
    assure this.  This can also handle the case where `oldpath`
    is a list instead of a string, in which case a list will be returned
    instead of a string. For example:

    >>> p = AppendPath("/foo/bar:/foo", "/biz/boom:/foo")
    >>> print(p)
    /foo/bar:/biz/boom:/foo

    If `delete_existing` is ``False``, then adding a path that exists
    will not move it to the end; it will stay where it is in the list.

    >>> p = AppendPath("/foo/bar:/foo", "/biz/boom:/foo", delete_existing=False)
    >>> print(p)
    /foo/bar:/foo:/biz/boom

    If `canonicalize` is not ``None``, it is applied to each element of
    `newpath` before use.
    TF)r   r   r   r   rz   r9   rc   r*   r   r   r   r   r8   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   
AppendPath  sT    






r   c             C   s   ynd}| | }t | | s(||}d}tj|tttjj|krP|g| }|r^|| |< n||| |< W n tk
r   || |< Y nX dS )a  Add a path element to a construction variable.

    `key` is looked up in `env_dict`, and `path` is added to it if it
    is not already present. `env_dict[key]` is assumed to be in the
    format of a PATH variable: a list of paths separated by `sep` tokens.
    Example:

    >>> env = {'PATH': '/bin:/usr/bin:/usr/local/bin'}
    >>> AddPathIfNotExists(env, 'PATH', '/opt/bin')
    >>> print(env['PATH'])
    /opt/bin:/bin:/usr/bin:/usr/local/bin
    TFN)	r   r   r*   r   r   rz   r9   r8   r   )Zenv_dictr   r   r   r   r   r   r   r   AddPathIfNotExistsO  s    


r   cygwinc             C   s*   t jdd| fdt jd}|j ddS )NZcygpathz-wF)Zcheckr[   rX   r)   )
subprocessrunPIPEr[   decodereplace)r   Zcpr   r   r   get_native_patho  s    r   c             C   s   | S )Nr   )r   r   r   r   r   s  s    zTransform an absolute path into a native path for the system.

In Cygwin, this converts from a Cygwin path to a Windows path,
without regard to whether `path` refers to an existing file
system object.  For other platforms, `path` is unchanged.
c             C   s*   t | st| r| S t| r$|  S | gS )a  Returns a list of file names or other objects.

    If `arg` is a string, it will be split on strings of white-space
    characters within the string.  If `arg` is already a list, the list
    will be returned untouched. If `arg` is any other type of object,
    it will be returned as a list containing just the object.

    >>> print(Split(" this  is  a  string  "))
    ['this', 'is', 'a', 'string']
    >>> print(Split(["stringlist", " preserving ", " spaces "]))
    ['stringlist', ' preserving ', ' spaces ']
    )r   r   r   r   )argr   r   r   Split  s
    r   c                   sN   e Zd ZdZd fdd	Z fddZ fddZ fd	d
Zdd Z  Z	S )CLVara  A container for command-line construction variables.

    Forces the use of a list of strings intended as command-line
    arguments.  Like :class:`collections.UserList`, but the argument
    passed to the initializter will be processed by the :func:`Split`
    function, which includes special handling for string types: they
    will be split into a list of words, not coereced directly to a list.
    The same happens if a string is added to a :class:`CLVar`,
    which allows doing the right thing with both
    :func:`Append`/:func:`Prepend` methods,
    as well as with pure Python addition, regardless of whether adding
    a list or a string to a construction variable.

    Side effect: spaces will be stripped from individual string
    arguments. If you need spaces preserved, pass strings containing
    spaces inside a list argument.

    >>> u = UserList("--some --opts and args")
    >>> print(len(u), repr(u))
    22 ['-', '-', 's', 'o', 'm', 'e', ' ', '-', '-', 'o', 'p', 't', 's', ' ', 'a', 'n', 'd', ' ', 'a', 'r', 'g', 's']
    >>> c = CLVar("--some --opts and args")
    >>> print(len(c), repr(c))
    4 ['--some', '--opts', 'and', 'args']
    >>> c += "    strips spaces    "
    >>> print(len(c), repr(c))
    6 ['--some', '--opts', 'and', 'args', 'strips', 'spaces']
    Nc                s    t  t|d k	r|ng  d S )N)superr   r   )r5   initlist)rB   r   r   r     s    zCLVar.__init__c                s   t  t|S )N)r   __add__r   )r5   r   )rB   r   r   r     s    zCLVar.__add__c                s   t  t|S )N)r   __radd__r   )r5   r   )rB   r   r   r     s    zCLVar.__radd__c                s   t  t|S )N)r   __iadd__r   )r5   r   )rB   r   r   r     s    zCLVar.__iadd__c             C   s   d dd | jD S )Nr7   c             S   s   g | ]}t |qS r   )r:   )r   dr   r   r   rA     s    z!CLVar.__str__.<locals>.<listcomp>)r8   r4   )r5   r   r   r   r;     s    zCLVar.__str__)N)
rK   rL   rM   rN   r   r   r   r   r;   __classcell__r   r   )rB   r   r     s   r   c               @   s   e Zd ZdZdddZdS )SelectorzA callable ordered dictionary that maps file suffixes to
    dictionary values.  We preserve the order in which items are added
    so that :func:`get_suffix` calls always return the first suffix added.
    Nc             C   s   |d kr2y|d   }W n tk
r0   d}Y nX y| | S  tk
r   i }xN|  D ]B\}}|d k	rX||}||krt|| d ||||f||< qXW y|| d S  tk
r   y| d  S  tk
r   d S X Y nX Y nX d S )Nr   r)   r(   )Z
get_suffix
IndexErrorr   r   Zsubst)r5   envsourcer   Zs_dictr   r   Zs_kr   r   r   rC     s,    

zSelector.__call__)N)rK   rL   rM   rN   rC   r   r   r   r   r     s   r   c             C   s   dS )NFr   )s1s2r   r   r   case_sensitive_suffixes  s    r   c             C   s   t j| t j|kS )N)r*   r   r   )r   r   r   r   r   r     s    c             C   sj   |r@t jt j| \}}||r.||kr@t j||| } |rf| |sf|s^t| d sf| | } | S )zAdjust filename prefixes and suffixes as needed.

    Add `prefix` to `fname` if specified.
    Add `suffix` to `fname` if specified and if `ensure_suffix` is ``True``
    r(   )r*   r   r   r   
startswithr8   endswithr-   )fnameZpreZsufZensure_suffixr   fnr   r   r   
adjustixes  s    r  c          	   C   s   | sg S t t tt| S Q R X t| }yt| }W n tk
rN   Y nXX |d }d }}x8||k r|| |kr||  ||< }|d }|d }qbW |d| S g }x| D ]}||kr|| qW |S )aR  Return a list of the elements in seq without duplicates, ignoring order.

    >>> mylist = unique([1, 2, 3, 1, 2, 3])
    >>> print(sorted(mylist))
    [1, 2, 3]
    >>> mylist = unique("abcabc")
    >>> print(sorted(mylist))
    ['a', 'b', 'c']
    >>> mylist = unique(([1, 2], [2, 3], [1, 2]))
    >>> print(sorted(mylist))
    [[1, 2], [2, 3]]

    For best speed, all sequence elements should be hashable.  Then
    unique() will usually work in linear time.

    If not possible, the sequence elements should enjoy a total
    ordering, and if list(s).sort() doesn't raise TypeError it's
    assumed that they do enjoy a total ordering.  Then unique() will
    usually work in O(N*log2(N)) time.

    If that's not possible either, the sequence elements must support
    equality-testing.  Then unique() will usually work in quadratic time.
    Nr   r(   )r   	TypeErrorrz   r   fromkeysrd   sortedrc   )seqrp   tZlastZlastiro   ur>   r   r   r   unique  s,    
	

r  c             C   sR   dd }|s|}i }g }|j }x.| D ]&}||}||kr:q$d||< || q$W |S )Nc             S   s   | S )Nr   )r>   r   r   r   default_idfun_  s    zuniquer.<locals>.default_idfunr(   )rc   )r  Zidfunr  seenr   result_appendr   Zmarkerr   r   r   uniquer^  s    
r  c             C   s8   i }g }|j }x$| D ]}||krd||< || qW |S )Nr(   )rc   )r  r  r   r  r   r   r   r   uniquer_hashablesr  s    
r  r)   c             c   sb   g }xJ| D ]B}|  }|dr4||d d  q
|| ||V  g }q
W |r^||V  d S )Nr   rP   )rstripr  rc   )Zphysical_linesZjoinerZlogical_linelinestrippedr   r   r   logical_lines  s    



r  c               @   s    e Zd ZdZdd Zdd ZdS )LogicalLinesz~ Wrapper class for the logical_lines method.

    Allows us to read all "logical" lines at once from a given file object.
    c             C   s
   || _ d S )N)fileobj)r5   r  r   r   r   r     s    zLogicalLines.__init__c             C   s   t t| jS )N)rz   r  r  )r5   r   r   r   	readlines  s    zLogicalLines.readlinesN)rK   rL   rM   rN   r   r  r   r   r   r   r    s   r  c                   s>  e Zd ZdZd5 fdd	Zdd Z fddZ fd	d
Z fddZ fddZ	 fddZ
 fddZ fddZ fddZ fddZ fddZ fddZ fddZ fdd Z fd!d"Z fd#d$Z fd%d&Z fd'd(Z fd)d*Z fd+d,Z fd-d.Z fd/d0Z fd1d2Z fd3d4Z  ZS )6
UniqueLista  A list which maintains uniqueness.

    Uniquing is lazy: rather than being assured on list changes, it is fixed
    up on access by those methods which need to act on a uniqe list to be
    correct. That means things like "in" don't have to eat the uniquing time.
    Nc                s   t  | d| _d S )NT)r   r   r  )r5   r   )rB   r   r   r     s    zUniqueList.__init__c             C   s   | j st| j| _d| _ d S )NT)r  r  r4   )r5   r   r   r   Z__make_unique  s    zUniqueList.__make_uniquec                s   |    t  S )N)_UniqueList__make_uniquer   __repr__)r5   )rB   r   r   r    s    zUniqueList.__repr__c                s   |    t |S )N)r  r   __lt__)r5   r   )rB   r   r   r    s    zUniqueList.__lt__c                s   |    t |S )N)r  r   __le__)r5   r   )rB   r   r   r    s    zUniqueList.__le__c                s   |    t |S )N)r  r   r   )r5   r   )rB   r   r   r     s    zUniqueList.__eq__c                s   |    t |S )N)r  r   __ne__)r5   r   )rB   r   r   r    s    zUniqueList.__ne__c                s   |    t |S )N)r  r   __gt__)r5   r   )rB   r   r   r    s    zUniqueList.__gt__c                s   |    t |S )N)r  r   __ge__)r5   r   )rB   r   r   r    s    zUniqueList.__ge__c                s   |    t  S )N)r  r   __len__)r5   )rB   r   r   r     s    zUniqueList.__len__c                s   |    t |S )N)r  r   rJ   )r5   ro   )rB   r   r   rJ     s    zUniqueList.__getitem__c                s   t  || d| _d S )NF)r   __setitem__r  )r5   ro   r   )rB   r   r   r!    s    zUniqueList.__setitem__c                s   t  |}d|_|S )NF)r   r   r  )r5   r   r   )rB   r   r   r     s    zUniqueList.__add__c                s   t  |}d|_|S )NF)r   r   r  )r5   r   r   )rB   r   r   r     s    zUniqueList.__radd__c                s   t  |}d|_|S )NF)r   r   r  )r5   r   r   )rB   r   r   r     s    zUniqueList.__iadd__c                s   t  |}d|_|S )NF)r   __mul__r  )r5   r   r   )rB   r   r   r"    s    zUniqueList.__mul__c                s   t  |}d|_|S )NF)r   __rmul__r  )r5   r   r   )rB   r   r   r#    s    zUniqueList.__rmul__c                s   t  |}d|_|S )NF)r   __imul__r  )r5   r   r   )rB   r   r   r$    s    zUniqueList.__imul__c                s   t  | d| _d S )NF)r   rc   r  )r5   r   )rB   r   r   rc     s    zUniqueList.appendc                s   t  || d| _d S )NF)r   r   r  )r5   ro   r   )rB   r   r   r     s    zUniqueList.insertc                s   |    t |S )N)r  r   count)r5   r   )rB   r   r   r%    s    zUniqueList.countc                s   |    t j|f| S )N)r  r   rI   )r5   r   r?   )rB   r   r   rI     s    zUniqueList.indexc                s   |    t   d S )N)r  r   r   )r5   )rB   r   r   r     s    zUniqueList.reversec                s   |    t j||S )N)r  r   sort)r5   r?   kwds)rB   r   r   r&    s    zUniqueList.sortc                s   t  | d| _d S )NF)r   extendr  )r5   r   )rB   r   r   r(    s    zUniqueList.extend)N)rK   rL   rM   rN   r   r  r  r  r  r   r  r  r  r   rJ   r!  r   r   r   r"  r#  r$  rc   r   r%  rI   r   r&  r(  r   r   r   )rB   r   r    s4   r  c               @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )
UnbufferedzyA proxy  that wraps a file object, flushing after every write.

    Delegates everything else to the wrapped object.
    c             C   s
   || _ d S )N)r   )r5   r   r   r   r   r     s    zUnbuffered.__init__c          	   C   s.   t t | j| | j  W d Q R X d S )N)r   r]   r   r\   flush)r5   r   r   r   r   r\     s    
zUnbuffered.writec          	   C   s.   t t | j| | j  W d Q R X d S )N)r   r]   r   
writelinesr*  )r5   r   r   r   r   r+  )  s    
zUnbuffered.writelinesc             C   s   t | j|S )N)rD   r   )r5   attrr   r   r   rF   .  s    zUnbuffered.__getattr__N)rK   rL   rM   rN   r   r\   r+  rF   r   r   r   r   r)    s
   r)  c             C   sZ   t j| rBt j| \}} |s6td| d } n| dd } t j| rVt| | S )z6Converts an absolute path name to a relative pathname.z/*(.*)r   r(   N)r*   r   isabsr.   recompilefindallAssertionError)r   Zdrive_sr   r   r   make_path_relative1  s    r2  c             C   s|   |dkr|j }nt|j|j||j}t| drh| jtk	rht| dr\t| ||}| j	
| qlt|| }n|}t| || dS )av  Adds a method to an object.

    Adds `function` to `obj` if `obj` is a class object.
    Adds `function` as a bound method if `obj` is an instance object.
    If `obj` looks like an environment instance, use `MethodWrapper`
    to add it.  If `name` is supplied it is used as the name of `function`.

    Although this works for any class object, the intent as a public
    API is to be used on Environment, to be able to add a method to all
    construction environments; it is preferred to use env.AddMethod
    to add to an individual environment.

    >>> class A:
    ...    ...

    >>> a = A()

    >>> def f(self, x, y):
    ...    self.z = x + y

    >>> AddMethod(A, f, "add")
    >>> a.add(2, 4)
    >>> print(a.z)
    6
    >>> a.data = ['a', 'b', 'c', 'd', 'e', 'f']
    >>> AddMethod(a, lambda self, i: self.data[i], "listIndex")
    >>> print(a.listIndex(3))
    d

    NrB   added_methods)rK   r	   __code____globals____defaults__r   rB   r   r   r3  rc   r   r   )r   ZfunctionrE   r   r   r   r   	AddMethodO  s    
r7  Zmd5Zsha1Zsha256c             C   s@   | dkrdS |j jdks0|j jdkr:|j jdkr:| ddS |  S )a  Python 3.9 and onwards lets us initialize the hash function object with the
    key "usedforsecurity"=false. This lets us continue to use algorithms that have
    been deprecated either by FIPS or by Python itself, as the MD5 algorithm SCons
    prefers is not being used for security purposes as much as a short, 32 char
    hash that is resistant to accidental collisions.

    In prior versions of python, hashlib returns a native function wrapper, which
    errors out when it's queried for the optional parameter, so this function
    wraps that call.

    It can still throw a ValueError if the initialization fails due to FIPS
    compliance issues, but that is assumed to be the responsibility of the caller.
    N   	   F)Zusedforsecurity)version_infomajorminor)Zhash_function_objectsys_usedr   r   r   '_attempt_init_of_python_3_9_hash_object  s
    $
r>  c             C   s   d}g a xbtD ]Z}t| |d}|dk	ryt|| t | W q tk
rf } z
|}wW dd}~X Y qX qW tt dkrddlm} |d|dS )a  Checks if SCons has ability to call the default algorithms normally supported.

    This util class is sometimes called prior to setting the user-selected hash algorithm,
    meaning that on FIPS-compliant systems the library would default-initialize MD5
    and throw an exception in set_hash_format. A common case is using the SConf options,
    which can run prior to main, and thus ignore the options.hash_format variable.

    This function checks the DEFAULT_HASH_FORMATS and sets the ALLOWED_HASH_FORMATS
    to only the ones that can be called. In Python >= 3.9 this will always default to
    MD5 as in Python 3.9 there is an optional attribute "usedforsecurity" set for the method.

    Throws if no allowed hash formats are detected.
    Nr   )SConsEnvironmentErrorzQNo usable hash algorithms found.Most recent error from hashlib attached in trace.)	ALLOWED_HASH_FORMATSDEFAULT_HASH_FORMATSrD   r>  rc   r   rd   SCons.Errorsr?  )hashlib_usedr=  Z_last_errorZtest_algorithmZ
_test_hashr   r?  r   r   r   "_set_allowed_viable_default_hashes  s"    

rD  c               C   s   t S )a  Retrieves the hash format or ``None`` if not overridden.

    A return value of ``None``
    does not guarantee that MD5 is being used; instead, it means that the
    default precedence order documented in :func:`SCons.Util.set_hash_format`
    is respected.
    )_HASH_FORMATr   r   r   r   get_hash_format  s    rF  c             C   s@   y&t || d}|dkrdS t|| | S  tk
r:   dS X dS )zWrapper used to try to initialize a hash function given.

    If successful, returns the name of the hash function back to the user.

    Otherwise returns None.
    N)rD   r>  r   )Z	hash_namerC  r=  Z_fetch_hashr   r   r   _attempt_get_hash_function  s    
rG  c             C   s   | a | r|  }|tkrddlm} |tkrD|d|dtf n>ttkrd|d|dtf n|d|dtdtf t|||atdkrddlm} |d| n8x6tD ]}t|||atdk	rP qW ddlm} |d	dS )
a  Sets the default hash format used by SCons.

    If `hash_format` is ``None`` or
    an empty string, the default is determined by this function.

    Currently the default behavior is to use the first available format of
    the following options: MD5, SHA1, SHA256.
    r   )	UserErrorzWhile hash format "%s" is supported by SCons, the local system indicates only the following hash formats are supported by the hashlib library: %sz, z]Hash format "%s" is not supported by SCons. Only the following hash formats are supported: %szHash format "%s" is not supported by SCons. SCons supports more hash formats than your local system is reporting; SCons supports: %s. Your local system only supports: %sNzHash format "%s" is not available in your Python interpreter. Expected to be supported algorithm by set_allowed_viable_default_hashes, Assertion error in SCons.zYour Python interpreter does not have MD5, SHA1, or SHA256. SCons requires at least one. Expected to support one or more during set_allowed_viable_default_hashes.)	rE  r   r@  rB  rH  rA  r8   rG  _HASH_FUNCTION)hash_formatrC  r=  Zhash_format_lowerrH  Zchoicer   r   r   set_hash_format  s<    

rK  c               C   s   t S )a  Returns the current hash algorithm name used.

    Where the python version >= 3.9, this is expected to return md5.
    If python's version is <= 3.8, this returns md5 on non-FIPS-mode platforms, and
    sha1 or sha256 on FIPS-mode Linux platforms.

    This function is primarily useful for testing, where one expects a value to be
    one of N distinct hashes, and therefore the test needs to know which hash to select.
    )rI  r   r   r   r   get_current_hash_algorithm_usedL  s    
rL  c             C   sh   | dkr6t dkr$ddlm} |dtt|t d|S tt| sXddlm} |d|  ttt| |S )zAllocates a hash object using the requested hash format.

    Args:
        hash_format: Hash format to use.

    Returns:
        hashlib object.
    Nr   )rH  z`There is no default hash function. Did you call a hashing function before SCons was initialized?z=Hash format "%s" is not available in your Python interpreter.)rI  rB  rH  r>  rD   r   hashlib)rJ  rC  r=  rH  r   r   r   _get_hash_objectX  s    	
rN  c             C   sJ   t |}y|t|  W n& tk
r@   |tt|  Y nX | S )z
    Generate hash signature of a string

    Args:
        s: either string or bytes. Normally should be bytes
        hash_format: Specify to override default hash format

    Returns:
        String of hex digits representing the signature
    )rN  r   to_bytesr  r:   	hexdigest)r   rJ  rv   r   r   r   hash_signatures  s    rQ     c          	   C   sJ   t |}t| d*}x"||}|s&P |t| qW W dQ R X | S )z
    Generate the md5 signature of a file

    Args:
        fname: file to hash
        chunksize: chunk size to read
        hash_format: Specify to override default hash format

    Returns:
        String of Hex digits representing the signature
    rbN)rN  openreadr   rO  rP  )r  	chunksizerJ  rv   r   Zblckr   r   r   hash_file_signature  s    
rW  c             C   s$   t | dkr| d S td| |S )z
    Collects a list of signatures into an aggregate signature.

    Args:
        signatures: a list of signatures
        hash_format: Specify to override default hash format

    Returns:
        the aggregate signature
    r(   r   z, )rd   rQ  r8   )
signaturesrJ  r   r   r   hash_collect  s    rY  c             C   s*   t s&ddl}|j|jjd|   da dS )z6Shows a deprecation warning for various MD5 functions.r   NzFunction %s is deprecatedT)_MD5_WARNING_SHOWNZSCons.WarningsZWarningswarnZDeprecatedWarning)Zfunction_nameZSConsr   r   r   _show_md5_warning  s
    
r\  c             C   s   t d t| S )z/Deprecated. Use :func:`hash_signature` instead.MD5signature)r\  rQ  )r   r   r   r   r]    s    r]  c             C   s   t d t| |S )z4Deprecated. Use :func:`hash_file_signature` instead.MD5filesignature)r\  rW  )r  rV  r   r   r   r^    s    r^  c             C   s   t d t| S )z-Deprecated. Use :func:`hash_collect` instead.
MD5collect)r\  rY  )rX  r   r   r   r_    s    r_  c             C   s$   y
t | S  tk
r   | S X dS )z
    Perform :mod:`sys.intern` on the passed argument and return the result.
    If the input is ineligible for interning the original argument is
    returned and no exception is thrown.
    N)rZ   internr  )r>   r   r   r   silent_intern  s    
ra  c                   sX   e Zd ZdZ fddZdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Z  ZS )Nullz0 Null objects always and reliably "do nothing." c                s,   dt | kr&tt| j| f||| _| jS )N	_instance)varsr   rb  __new__rc  )r   r?   r@   )rB   r   r   re    s    zNull.__new__c             O   s   d S )Nr   )r5   r?   r@   r   r   r   r     s    zNull.__init__c             O   s   | S )Nr   )r5   r?   r@   r   r   r   rC     s    zNull.__call__c             C   s   dt |  S )NzNull(0x%08X))id)r5   r   r   r   r    s    zNull.__repr__c             C   s   dS )NFr   )r5   r   r   r   r6     s    zNull.__bool__c             C   s   | S )Nr   )r5   rE   r   r   r   rF     s    zNull.__getattr__c             C   s   | S )Nr   )r5   rE   valuer   r   r   __setattr__  s    zNull.__setattr__c             C   s   | S )Nr   )r5   rE   r   r   r   __delattr__  s    zNull.__delattr__)rK   rL   rM   rN   re  r   rC   r  r6   rF   rh  ri  r   r   r   )rB   r   rb    s   rb  c               @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )NullSeqz/ A Null object that can also be iterated over. c             C   s   dS )Nr   r   )r5   r   r   r   r     s    zNullSeq.__len__c             C   s   t dS )Nr   )r<   )r5   r   r   r   r=     s    zNullSeq.__iter__c             C   s   | S )Nr   )r5   ro   r   r   r   rJ     s    zNullSeq.__getitem__c             C   s   | S )Nr   )r5   ro   r   r   r   __delitem__  s    zNullSeq.__delitem__c             C   s   | S )Nr   )r5   ro   r   r   r   r   r!    s    zNullSeq.__setitem__N)	rK   rL   rM   rN   r   r=   rJ   rk  r!  r   r   r   r   rj    s   rj  c             C   s(   | d krdS t | ttfr| S t| dS )Ns   Nonezutf-8)rG   bytes	bytearray)r   r   r   r   rO  	  s
    rO  c             C   s"   | d krdS t | r| S t| dS )NNonezutf-8)r   r:   )r   r   r   r   to_str  s
    ro  c             C   s   | |k| |k  S )z=A cmp function because one is no longer available in python3.r   )abr   r   r   cmp  s    rr  c             C   sp   y| | }W n t k
r    |S X ytt|S  tk
rj   t| dkrRdS t| dkrfdS |S X dS )al  Convert a construction variable to bool.

    If the value of `name` in `env` is 'true', 'yes', 'y', 'on' (case
    insensitive) or anything convertible to int that yields non-zero then
    return ``True``; if 'false', 'no', 'n', 'off' (case insensitive)
    or a number that converts to integer zero return ``False``.
    Otherwise, return `default`.

    Args:
        env: construction environment, or any dict-like object
        name: name of the variable
        default: value to return if `name` not in `env` or cannot
          be converted (default: False)

    Returns:
        the "truthiness" of `name`
    )trueZyesyZonT)ZfalseZnorp   ZoffFN)r   r3   intr   r:   r   )r   rE   defaultrU   r   r   r   get_env_bool  s    rw  c             C   s   t tj| |S )zfConvert an environment variable to bool.

    Conversion is the same as for :func:`get_env_bool`.
    )rw  r*   r   )rE   rv  r   r   r   get_os_env_boolA  s    rx  c              C   s   ddl m}  | S )z6Hack to return a value from Main if can't import Main.r   )
print_time)ZSCons.Script.Mainry  )ry  r   r   r   ry  I  s    ry  c             C   s   y6ddl }x(| dd | D kr&P qtd qW W n tk
r   xtjdkrddl}d}|jj	
|d| }|dkr|P q|jj	| td qHyt| d W n tk
r   P Y qHX td qHW Y nX dS )z
    Wait for specified process to die, or alternatively kill it
    NOTE: This function operates best with psutil pypi package
    TODO: Add timeout which raises exception
    r   Nc             S   s   g | ]
}|j qS r   )pid)r   procr   r   r   rA   Z  s    z+wait_for_process_to_die.<locals>.<listcomp>g?r   i   )psutilZprocess_itertimeZsleepImportErrorrZ   platformctypesZwindllZkernel32ZOpenProcessZCloseHandler*   killr   )rz  r|  r  ZPROCESS_QUERY_INFORMATIONZprocessHandler   r   r   wait_for_process_to_dieP  s*    
r  )N)N)NNN)NNN)NNN)F)N)N)N)rR  N)N)rR  )F)F)rN   ra   rM  r*   r   r.  rZ   r}  collectionsr   r   r   r   Zcollections.abcr   
contextlibr   typesr   r	   typingr
   r   r   ZPYPYZNOFILEr   r   altsepr   r  r   r3   r#   r%   r&   r   r-   r:   r1   r2   r/  rQ   rV   rW   re   rq   chrr|   ru   r}   ZBOX_DOWN_RIGHTZBOX_DOWN_LEFTZBOX_UP_LEFTr{   r~   r   r   rz   r   r   r   r   rG   r   r   r   r   r   r   r   r   r   rS   r   r   r   r   r   r   r   r   r   r   r   Zcan_read_regwinregZhkey_modr~  	Exceptionr   ZRegErrorZHKEY_CLASSES_ROOTHKEY_LOCAL_MACHINEHKEY_CURRENT_USERZ
HKEY_USERSZ	OpenKeyExr   ZEnumKeyZ
RegEnumKeyZ	EnumValueZRegEnumValueZQueryValueExr   errorr   r   rE   r   r   r   r   r   r   Zdisplayr   r   r   r   r  r  r  r  r8   r  r  r  r)  r2  r7  rA  r@  rI  rE  r>  rD  rF  rG  rK  rL  rN  rQ  rW  rY  rZ  r\  r]  r^  r_  ra  rb  rj  rl  rO  ro  rr  rw  rx  ry  r  r   r   r   r   <module>   sz  	

	+
* "4#

# -
U
T	/$ I
x
6
,
U



	"