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	Z	ddl
Z
ddlmZ ddlm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ddlZddlmZmZ ddlmZmZmZ dZdZdd	 Z d
d Z!e e!dZ"G dd de#Z$G dd de%Z&dZ'da(dd Z)da*da+dd Z,e,  e-dej.Z/e/j0Z1e2edrne	j3dkrndd Z4ndZ4e2edre	j3dkrdd Z5ndZ5dd Z6d d!d"d#d$gZ7g a8d%d& Z9d'd( Z:ej;;e:dZ<d)d* Z=ej;;e:e=Z>d+d, Z?ej;;e?dZ@d-d. ZAej;j;eAddd/ZBdaCd0d1 ZDG d2d3 d3ZEeE ZFe	j3d4kZGejHId5ejHJd5krjeGsjd6d7 ZKnd8d7 ZKG d9d: d:ZLd;d< ZMd=d> ZNeLd?eMeNZOeOgZPd@dA ZQdBdC ZRG dDdE dEejSjTZUG dFdG dGejVjVZWeWjXeWjYeWjZeWj[eWj\eWj]eWj^dHZ_G dIdJ dJeWZ`e`ZaG dKdL dLZbG dMdN dNebZcG dOdP dPejVjdZeG dQdR dRejVjfZge-dSZhdTdU ZiG dVdW dWeWZjG dXdY dYejZkG dZd[ d[ejVjdZlG d\d] d]ejVjfZmG d^d_ d_eWZndaod`da ZpG dbdc dcZqeq jrZrddde ZsdS )fa/  File system nodes.

These Nodes represent the canonical external objects that people think
of when they think of building software: files and directories.

This holds a "default_fs" variable that should be initialized with an FS
that can be used by scripts or modules looking for the canonical default.
    N)chain)Optional)logInstanceCreationTrace)hash_signaturehash_file_signaturehash_collectFc             C   s   t d S )N)NotImplementedError)node r   ,lib/python3.7/site-packages/SCons/Node/FS.pysconsign_none>   s    r   c             C   s"   | j sddl}|j| | _ | j S )zVReturn the .sconsign file info for this directory,
    creating it first if necessary.r   N)	_sconsignSCons.SConsignSConsignZForDirectory)r
   SConsr   r   r   sconsign_dirA   s    r   )r      c               @   s   e Zd ZdS )#FileBuildInfoFileToCsigMappingErrorN)__name__
__module____qualname__r   r   r   r   r   L   s   r   c                   s(   e Zd ZdZ fddZdd Z  ZS )EntryProxyAttributeErrorz
    An AttributeError subclass for recording and displaying the name
    of the underlying Entry involved in an AttributeError exception.
    c                s   t    || _|| _d S )N)super__init__entry_proxy	attribute)selfr   r   )	__class__r   r   r   T   s    
z!EntryProxyAttributeError.__init__c             C   s,   | j  }d}||jjt|jt| jf S )Nz"%s instance %s has no attribute %s)r   getr   r   reprnamer   )r   entryfmtr   r   r   __str__X   s
    
z EntryProxyAttributeError.__str__)r   r   r   __doc__r   r$   __classcell__r   r   )r   r   r   O   s   r   i  c             C   s   | a d S )N)Save_Strings)valr   r   r   save_stringsw   s    r)   c              C   sp   t jd\} }tt jdp.t jdd dka|   p:tatrJdd }ndd }|at jatt a	td	ka
d S )
NzX:/fooZsplituncz\\split\drive\testr   z\\split\drivec             S   sP   | dd dkr(| d d | dd  fS | dd dkrHd| dd  fS d| fS )Nr      :r   z// r   )pr   r   r   
splitdrive   s
    z,initialize_do_splitdrive.<locals>.splitdrivec             S   s0   | dd dkr(| d d | dd  fS d| fS )Nr   r*   r+   r,   r   )r-   r   r   r   r.      s    /)ospathr.   hasattrhas_uncdo_splitdrive_my_splitdrivesepOS_SEP
UNC_PREFIXos_sep_is_slash)driver1   r.   r   r   r   initialize_do_splitdrive   s    
	r;   a   
      # We need to renormalize the path if it contains any consecutive
      # '/' characters.
      .*// |

      # We need to renormalize the path if it contains a '..' directory.
      # Note that we check for all the following cases:
      #
      #    a) The path is a single '..'
      #    b) The path starts with '..'. E.g. '../' or '../moredirs'
      #       but we not match '..abc/'.
      #    c) The path ends with '..'. E.g. '/..' or 'dirs/..'
      #    d) The path contains a '..' in the middle.
      #       E.g. dirs/../moredirs

      (.*/)?\.\.(?:/|$) |

      # We need to renormalize the path if it contains a '.'
      # directory, but NOT if it is a single '.'  '/' characters. We
      # do not want to match a single '.' because this case is checked
      # for explicitly since this is common enough case.
      #
      # Note that we check for all the following cases:
      #
      #    a) We don't match a single '.'
      #    b) We match if the path starts with '.'. E.g. './' or
      #       './moredirs' but we not match '.abc/'.
      #    c) We match if the path ends with '.'. E.g. '/.' or
      #    'dirs/.'
      #    d) We match if the path contains a '.' in the middle.
      #       E.g. dirs/./moredirs

      \./|.*/\.(?:/|$)

    linkwin32c             C   sR   x@|  |r@| |}tj|s(|}qtjtj||}qW | || d S )N)islinkreadlinkr0   r1   isabsjoindirnamer<   )fssrcdstr<   r   r   r   _hardlink_func   s    
rF   symlinkc             C   s   |  || d S )N)rG   )rC   rD   rE   r   r   r   _softlink_func   s    rH   c             C   s4   t || | |}| |t|jtjB  d S )N)shutilcopy2statchmodS_IMODEst_modeS_IWRITE)rC   rD   deststr   r   r   
_copy_func   s    
rR   zhard-soft-copyzsoft-hard-copyz	hard-copyz	soft-copycopyc             C   sR   t ttd}| tkr tjdg ax(| dD ]}|| r0t	||  q0W d S )N)ZhardZsoftrS   z;The argument of set_duplicate should be in Valid_Duplicates-)
rF   rH   rR   Valid_Duplicatesr   ErrorsZInternalError
Link_Funcssplitappend)	duplicateZ	link_dictfuncr   r   r   set_duplicate
  s    	r\   c       	   
   C   s   |d   }| d   }tj|\}}|rF| d j|sFt| tsRtd |d j}xFtD ]>}y|||| P W qb t	t
fk
r   |td kr Y qbX qbW dS )a.  
    Relative paths cause problems with symbolic links, so
    we use absolute paths, which may be a problem for people
    who want to move their soft-linked src-trees around. Those
    people should use the 'hard-copy' mode, softlinks cannot be
    used for that; at least I have no idea how ...
    r   zhard-soft-copy)get_abspathr0   r1   rX   rC   isdirmakedirsrW   r\   IOErrorOSError)	targetsourceenvrD   rP   dirfilerC   r[   r   r   r   LinkFunc!  s     


rh   c             C   s   d| d |d f S )NzLocal copy of %s from %sr   r   )rc   rd   re   r   r   r   LocalStringD  s    ri   c             C   s   | d }|j |  dS )Nr   )rC   unlinkr^   )rc   rd   re   tr   r   r   
UnlinkFuncI  s    rl   c             C   s4   | d }|  s0tj | s0|j|  dS )Nr   )existsr0   r1   r^   rC   mkdir)rc   rd   re   rk   r   r   r   	MkdirFuncP  s    ro   )Zpresubc              C   s8   t d kr4dd l} dd l} | jjtd d d | jjdda t S )Nr   MkdirBuilder)actionre   ZexplainZis_explicitZtarget_scannerr!   )rp   ZSCons.BuilderSCons.DefaultsZBuilderMkdirDefaultsDirEntryScanner)r   r   r   r   get_MkdirBuilder_  s    rv   c               @   s   e Zd ZdS )_NullN)r   r   r   r   r   r   r   rw   n  s   rw   cygwinZTeStc             C   s   | S )Nr   )xr   r   r   _my_normcasev  s    rz   c             C   s   |   S )N)upper)ry   r   r   r   rz   y  s    c               @   s$   e Zd Zdd Zdd Zdd ZdS )DiskCheckerc             C   s   || _ || _|| _|| _d S )N)typedoignorer[   )r   r}   r~   r   r   r   r   r     s    zDiskChecker.__init__c             O   s   | j ||S )N)r[   )r   argskwr   r   r   __call__  s    zDiskChecker.__call__c             C   s    | j |kr| j| _n| j| _d S )N)r}   r~   r[   r   )r   listr   r   r   set  s    

zDiskChecker.setN)r   r   r   r   r   r   r   r   r   r   r|   ~  s   r|   c          	   C   sR   | }y| j d d kr| j d= W n ttfk
r8   Y nX |rNt||   d S )NrK   )_memoAttributeErrorKeyError	TypeErrorr^   )r
   	predicateerrorfmtresultr   r   r   do_diskcheck_match  s    r   c             C   s   d S )Nr   )r
   r   r   r   r   r   ignore_diskcheck_match  s    r   matchc             C   s   xt D ]}||  qW d S )N)diskcheckersr   )r   dcr   r   r   set_diskcheck  s    
r   c               C   s   dd t D S )Nc             S   s   g | ]
}|j qS r   )r}   ).0r   r   r   r   
<listcomp>  s    z#diskcheck_types.<locals>.<listcomp>)r   r   r   r   r   diskcheck_types  s    r   c               @   s   e Zd ZejdZejdZdd Zdd Z	dd Z
d	d
 Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zeeeeeeeee	e
eeeedZdd Zd S )!
EntryProxyr$   __hash__c             C   s    |   }tj| |jd S )N_abspath)r   r   SubstSpecialAttrWrapperr^   r!   )r   r"   r   r   r   Z__get_abspath  s    zEntryProxy.__get_abspathc             C   s    |   }tj| |jd S )NZ_relpath)r   r   r   r   get_relpathr!   )r   r"   r   r   r   Z__get_relpath  s    zEntryProxy.__get_relpathc             C   s(   |   j}tjtj|d |d S )Nr   Z	_filebase)r   r!   r   r   r   Utilsplitext)r   r!   r   r   r   Z__get_filebase  s    
zEntryProxy.__get_filebasec             C   s(   |   j}tjtj|d |d S )Nr   Z_suffix)r   r!   r   r   r   r   r   )r   r!   r   r   r   Z__get_suffix  s    
zEntryProxy.__get_suffixc             C   s   |   j}tj||d S )NZ_file)r   r!   r   r   r   )r   r!   r   r   r   Z
__get_file  s    
zEntryProxy.__get_filec             C   s,   |   }tjtj| d |jd S )zLReturn the file's directory and file name, with the
        suffix stripped.r   Z_base)r   r   r   r   r   r   get_pathr!   )r   r"   r   r   r   Z__get_base_path  s    zEntryProxy.__get_base_pathc             C   s8   t r| S |  }| td}tj||jd S dS )zMReturn the path with / as the path separator,
        regardless of platform.r/   Z_posixN)	r9   r   r   replacer7   r   r   r   r!   )r   r"   rr   r   r   Z__get_posix_path  s
    zEntryProxy.__get_posix_pathc             C   s<   t dkr| S |  }| t d}tj||jd S dS )zMReturn the path with \ as the path separator,
        regardless of platform.\Z_windowsN)r7   r   r   r   r   r   r   r!   )r   r"   r   r   r   r   Z__get_windows_path  s
    zEntryProxy.__get_windows_pathc             C   s   t |   S )N)r   r   srcnode)r   r   r   r   Z__get_srcnode  s    zEntryProxy.__get_srcnodec             C   s   t |   jS )zReturns the directory containing the source node linked to this
        node via VariantDir(), or the directory of this node if not linked.)r   r   r   rf   )r   r   r   r   Z__get_srcdir  s    zEntryProxy.__get_srcdirc             C   s   t |    S )N)r   r   r   rfile)r   r   r   r   Z__get_rsrcnode  s    zEntryProxy.__get_rsrcnodec             C   s   t |    jS )zReturns the directory containing the source node linked to this
        node via VariantDir(), or the directory of this node if not linked.)r   r   r   r   rf   )r   r   r   r   Z__get_rsrcdir  s    zEntryProxy.__get_rsrcdirc             C   s   t |  jS )N)r   r   rf   )r   r   r   r   Z	__get_dir  s    zEntryProxy.__get_dir)baseposixZwindowsr=   Zsrcpathsrcdirrf   abspathrelpathZfilebasesuffixrg   ZrsrcpathZrsrcdirc             C   sd   y| j | }W nH tk
rV   ytjj| |}W n tk
rP   t| |Y nX |S X || S d S )N)dictSpecialAttrsr   r   r   Proxy__getattr__r   r   )r   r!   Zattr_functionattrr   r   r   r     s    zEntryProxy.__getattr__N)r   r   r   r   r   ZDelegater$   r   Z_EntryProxy__get_abspathZ_EntryProxy__get_relpathZ_EntryProxy__get_filebaseZ_EntryProxy__get_suffixZ_EntryProxy__get_fileZ_EntryProxy__get_base_pathZ_EntryProxy__get_posix_pathZ_EntryProxy__get_windows_pathZ_EntryProxy__get_srcnodeZ_EntryProxy__get_srcdirZ_EntryProxy__get_rsrcnodeZ_EntryProxy__get_rsrcdirZ_EntryProxy__get_dirr   r   r   r   r   r   r     s<   

r   c                   s  e Zd ZdZdddddddd	d
dddddg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d d! Zejjd"d# Zd$d% ZeZejjd&d' Zejjd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 Zd4d5 Zeed6rd7d8 Znd9d8 Zd:d; Zd<d= Z d>d? Z!dedAdBZ"dCdD Z#dEdF Z$dGdH Z%dIdJ Z&dKdL Z'dMdN Z(dOdP Z)dQdR Z*dSdT Z+dUdV Z,ej-j.fdWdXZ/dYdZ Z0ej1e0d[d\ Z2d]d^ Z3ejjd_d` Z4dfdcddZ5  Z6S )gBasea*  A generic class for file system entries.  This class is for
    when we don't know yet whether the entry being looked up is a file
    or a directory.  Instances of this class can morph into either
    Dir or File objects by a later, more precise lookup.

    Note: this class does not define __cmp__ and __hash__ for
    efficiency reasons.  SCons does a lot of comparing of
    Node.FS.{Base,Entry,File,Dir} objects, so those operations must be
    as fast as possible, which means we want to use Python's built-in
    object identity comparisons.
    r!   rC   r   	_labspath_path_tpath_path_elementsrf   cwdrZ   _localsbuilder_proxy_func_sconsignc                s   t jjrt| d t   t j|| _|| _	|s<t
dd| _d| _d| _d| _d| _|| _d| _|j| _d| _d| _d| _d| _d| _d| _d| _dS )zInitialize a generic Node.FS.Base object.

        Call the superclass initialization, take care of setting up
        our relative and absolute paths, identify our parent
        directory, and indicate that this node should use
        signatures.zNode.FS.BasezA directory must be providedNr*   r   r   )r   Debugtrack_instancesr   r   r   r   silent_internr!   rC   AssertionErrorr   r   r   r   r   rf   r   rZ   changed_since_last_buildr   _func_exists_func_rexists_func_get_contents_func_target_from_source
store_info)r   r!   	directoryrC   )r   r   r   r   =  s*     

zBase.__init__c             C   s   d|    d S )N")r$   )r   r   r   r   str_for_displaya  s    zBase.str_for_displayc             C   s6   t | |s|tkrdS td| jj|  |jf dS )z
        This node, which already existed, is being looked up as the
        specified klass.  Raise an exception if it isn't.
        Nz Tried to lookup %s '%s' as a %s.)
isinstanceEntryr   r   r   get_internal_path)r   klassr   r   r   must_be_samed  s    zBase.must_be_samec             C   s   | j S )N)rf   )r   r   r   r   get_dirn  s    zBase.get_dirc             C   s   t j| jd S )Nr   )r   r   r   r!   )r   r   r   r   
get_suffixq  s    zBase.get_suffixc             C   s   | S )Nr   )r   r   r   r   r   t  s    z
Base.rfilec             C   s*   |t krt | | S td| j|f dS )af   Together with the node_bwcomp dict defined below,
            this method provides a simple backward compatibility
            layer for the Node attributes 'abspath', 'labspath',
            'path', 'tpath', 'suffix' and 'path_elements'. These Node
            attributes used to be directly available in v2.3 and earlier, but
            have been replaced by getter methods that initialize the
            single variables lazily when required, in order to save memory.
            The redirection to the getters lets older Tools and
            SConstruct continue to work without any additional changes,
            fully transparent to the user.
            Note, that __getattr__ is only called as fallback when the
            requested attribute can't be found, so there should be no
            speed performance penalty involved for standard builds.
        z%r object has no attribute %rN)node_bwcompr   r   )r   r   r   r   r   r   w  s    zBase.__getattr__c             C   s   t r|  S |  S )zGA Node.FS.Base object's string representation is its path
        name.)r'   	_save_str_get_str)r   r   r   r   r$     s    zBase.__str__c             C   s   t | t |k S )z* less than operator used by sorting on py3)str)r   otherr   r   r   __lt__  s    zBase.__lt__c             C   s>   y
| j d S  tk
r   Y nX tj|  }|| j d< |S )Nr   )r   r   r   r   r   r   )r   r   r   r   r   r     s    

zBase._save_strc             C   s   | j s|  r|  S |  }| d kr@|  d k	r@|  }n| }tsy| jd= W n tk
rl   Y nX | |k	ry|jd= W n tk
r   Y nX |S )NrK   )rZ   
is_derivedr   r   rK   r'   r   r   )r   r   r   r   r   r   r     s"    
	    zBase._get_strc             C   s^   y
| j d S  tk
r   Y nX y| j|  }W n tjk
rN   d }Y nX || j d< |S )NrK   )r   r   rC   rK   r^   r0   error)r   r   r   r   r   rK     s    


z	Base.statc             C   s^   y
| j d S  tk
r   Y nX y| j|  }W n tjk
rN   d }Y nX || j d< |S )Nlstat)r   r   rC   r   r^   r0   r   )r   r   r   r   r   r     s    


z
Base.lstatc             C   s   t jj| j | S )N)r   Node_exists_mapr   )r   r   r   r   rm     s    zBase.existsc             C   s   t jj| j | S )N)r   r   Z_rexists_mapr   )r   r   r   r   rexists  s    zBase.rexistsc             C   s   |   }|r|t j S d S d S )N)rK   ST_MTIME)r   rQ   r   r   r   getmtime  s    
zBase.getmtimec             C   s   |   }|r|jS d S d S )N)rK   st_size)r   rQ   r   r   r   getsize  s    zBase.getsizec             C   s   |   }|d k	ot |jS )N)rK   S_ISDIRrN   )r   rQ   r   r   r   r_     s    z
Base.isdirc             C   s   |   }|d k	ot |jS )N)rK   S_ISREGrN   )r   rQ   r   r   r   isfile  s    zBase.isfilerG   c             C   s   |   }|d k	ot|jS )N)r   rK   S_ISLNKrN   )r   rQ   r   r   r   r>     s    zBase.islinkc             C   s   dS )NFr   )r   r   r   r   r>     s    c             C   s   | |krdS | j |S d S )Nr   )rf   is_under)r   rf   r   r   r   r     s    zBase.is_underc             C   s
   d| _ d S )Nr   )r   )r   r   r   r   	set_local  s    zBase.set_localc             C   s2   | j  }|r.|d | j}|| j |S | S )zIf this node is in a build path, return the node
        corresponding to its source file.  Otherwise, return
        ourself.
        r   )rf   srcdir_listr   r!   r   r   )r   r   r   r   r   r   r     s    
zBase.srcnodeNc             C   s   |s| j  }| |krdS |  }d}y||}W n4 tk
rh   x|dd D ]}||j7 }qRW Y n&X x"||d d D ]}||j7 }q|W ||d j S )zfReturn path relative to the current working directory of the
        Node.FS.Base object that owns us..r,   Nr]   r   )rC   getcwdget_path_elementsindex
ValueErrorrB   r!   )r   rf   
path_elemspathnameir-   r   r   r   r     s    
 zBase.get_pathc             C   s   || _ |  s| | dS )z*Set the source code builder for this node.N)r   has_builderbuilder_set)r   builderr   r   r   set_src_builder&  s    zBase.set_src_builderc             C   s4   y
| j }W n$ tk
r.   | j }|| _ Y nX |S )a  Fetch the source code builder for this node.

        If there isn't one, we cache the source code builder specified
        for the directory (which in turn will cache the value from its
        parent directory, and so on up to the file system root).
        )r   r   rf   src_builder)r   scbr   r   r   r   ,  s    

zBase.src_builderc             C   s   | j | jS )z"Get the absolute path of the file.)rf   entry_abspathr!   )r   r   r   r   r^   :  s    zBase.get_abspathc             C   s   | j | jS )z"Get the absolute path of the file.)rf   entry_labspathr!   )r   r   r   r   get_labspath>  s    zBase.get_labspathc             C   s    t j| j| j| jj S )zJGet the path of the file relative to the root SConstruct file's directory.)	r0   r1   r   rf   r   r!   rC   SConstruct_dirr^   )r   r   r   r   r   B  s    zBase.get_relpathc             C   s$   | j jdkr| jS | j | jS d S )Nr   )rf   r   r!   
entry_path)r   r   r   r   r   F  s    zBase.get_internal_pathc             C   s$   | j jdkr| jS | j | jS d S )Nr   )rf   r   r!   entry_tpath)r   r   r   r   	get_tpathL  s    zBase.get_tpathc             C   s   | j j| g S )N)rf   r   )r   r   r   r   r   R  s    zBase.get_path_elementsc             C   s   | j S )N)r!   )r   r   r   r   for_signatureU  s    zBase.for_signaturec             C   s.   y| j S  tk
r(   t| }|| _ |S X d S )N)r   r   r   )r   Zretr   r   r   get_subst_proxy[  s    zBase.get_subst_proxyc             C   s   t jj| j | |||S )a1  

        Generates a target entry that corresponds to this entry (usually
        a source file) with the specified prefix and suffix.

        Note that this method can be overridden dynamically for generated
        files that need different behavior.  See Tool/swig.py for
        an example.
        )r   r   Z_target_from_source_mapr   )r   prefixr   r   r   r   r   target_from_sourcec  s    
zBase.target_from_sourcec             C   s   |S )Nr   )r   pathlistr   r   r   _Rfindalldirs_keyo  s    zBase._Rfindalldirs_keyc             C   s   y| j d }W n" tk
r0   i }|| j d< Y n X y|| S  tk
rN   Y nX | j}g }x<|D ]4}t|tjjr~|| q`||}||  q`W |||< |S )aS  
        Return all of the directories for a given path list, including
        corresponding "backing" directories in any repositories.

        The Node lookups are relative to this Node (typically a
        directory), so memoizing result saves cycles from looking
        up the same path for each target in a given directory.
        Rfindalldirs)	r   r   Dirr   r   r   rY   extendget_all_rdirs)r   r   	memo_dictZcreate_dir_relative_to_selfr   r1   rf   r   r   r   r   r  s$    

zBase.Rfindalldirsc             C   s   | j p| jj}||S )z8Search for a list of directories in the Repository list.)r   rC   _cwdr   )r   r   r   r   r   r   RDirs  s    z
Base.RDirsc          	   C   s   y
| j d S  tk
r   Y nX | }|  st| j}xP| j D ]B}y|j| }W qB tk
r   || jr~|	| j}P Y qBX qBW || j d< |S )Nrentry)
r   r   rm   rz   r!   rf   r   entriesentry_exists_on_diskr   )r   r   	norm_namerf   r
   r   r   r   r    s     


zBase.rentryTFc             C   s   g S )Nr   )r   patternondiskrd   stringsr   r   r   _glob1  s    zBase._glob1)N)TFF)7r   r   r   r%   	__slots__r   r   r   r   r   r   r   r$   r   r   MemoizeCountMethodCallr   r   rstrrK   r   rm   r   r   r   r_   r   r2   r0   r>   r   r   r   r   r   r   r^   r   r   r   r   r   r   r   r   r   r   r   CountDictCallr   r  r  r  r&   r   r   )r   r   r   !  st   $




"r   )r   Zlabspathr   r1   ZtpathZpath_elementsr   c                   s   e Zd ZdZdddddddd	d
dddddgZ fddZdd Zd-ddZdd Zdd Z	dd Z
dd Zdd  Zd!d" Zd#d$ Zd%d& Zd.d)d*Zd+d, Z  ZS )/r   aU  This is the class for generic Node.FS entries--that is, things
    that could be a File or a Dir, but we're just not sure yet.
    Consequently, the methods in this class really exist just to
    transform their associated object into the right class when the
    time comes, and then call the same-named method in the transformed
    class.scanner_pathscachedir_csigcachesigrepositoriesr   r  searchedr   variant_dirsrootrB   on_disk_entriesreleased_target_info
contentsigc                s    t  ||| d| _d| _d S )N   r   )r   r   r   r   )r   r!   r   rC   )r   r   r   r     s    zEntry.__init__c             C   s   d S )Nr   )r   r   r   r   diskcheck_match  s    zEntry.diskcheck_matchNc             C   s   |   r t| _|   |   n|  r8t| _|   np| j }|| jkrt|	| j
rt|   rtt| _|   n4|rd|   }tj|nt| _|   |   | S )z	
        zNo such file or directory: '%s')r   Filer   _morphclearr_   r   rf   r   r  r!   r^   r   rV   	UserError)r   
must_existr   msgr   r   r   disambiguate  s(    




zEntry.disambiguatec             C   s    t | _|   |   t | S )znWe're a generic Entry, but the caller is actually looking for
        a File at this point, so morph into one.)r  r   r  r  r   )r   r   r   r   r     s    zEntry.rfilec             C   s   |   S )N)r   )r   r   r   r   scanner_key  s    zEntry.scanner_keyc             C   s   t jj| j | S )zXFetch the contents of the entry.  Returns the exact binary
        contents of the file.)r   r   _get_contents_mapr   )r   r   r   r   get_contents  s    zEntry.get_contentsc             C   s6   y| j dd} W n tjjk
r(   dS X |  S dS )zFetch the decoded text contents of a Unicode encoded Entry.

        Since this should return the text contents from the file
        system, we check to see into what sort of subclass we should
        morph this Entry.r   )r!  r,   N)r#  r   rV   r   get_text_contents)r   r   r   r   r'    s
    zEntry.get_text_contentsc             C   s$   | j |k	r || _ |   |   dS )zZCalled to make sure a Node is a Dir.  Since we're an
        Entry, we can morph into one.N)r   r  r  )r   r   r   r   r   r     s    
zEntry.must_be_samec             C   s   t jj| j | S )N)r   r   r   r   )r   r   r   r   rm   2  s    zEntry.existsc             C   s$   |   }|jtkrtd||S )Nz*rel_path() could not disambiguate File/Dir)r#  r   r   	Exceptionrel_path)r   r   dr   r   r   r)  5  s    
zEntry.rel_pathc             C   s   |    S )N)r#  	new_ninfo)r   r   r   r   r+  ;  s    zEntry.new_ninfoTFc             C   s   |   ||||S )N)r#  r  )r   r  r	  rd   r
  r   r   r   r  >  s    zEntry._glob1c             C   s   |    S )N)r#  r   )r   r   r   r   r   A  s    zEntry.get_subst_proxy)N)TFF)r   r   r   r%   r  r   r  r#  r   r$  r&  r'  r   rm   r)  r+  r  r   r&   r   r   )r   r   r     s8   
#
r   c               @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zd3ddZd4ddZd d! Zd"d# Zd$d% Zd&d' Zd(d) Zeed*rd+d, Znd-d, Zeed.rd/d0 Znd1d0 Zd2S )5LocalFSa   
    This class implements an abstraction layer for operations involving
    a local file system.  Essentially, this wraps any function in
    the os, os.path or shutil modules that we use to actually go do
    anything with or to the local file system.

    Note that there's a very good chance we'll refactor this part of
    the architecture in some way as we really implement the interface(s)
    for remote file system Nodes.  For example, the right architecture
    might be to have this be a subclass instead of a base class.
    Nevertheless, we're using this as a first step in that direction.

    We're not using chdir() yet because the calling subclass method
    needs to use os.chdir() directly to avoid recursion.  Will we
    really need this one?
    c             C   s   t ||S )N)r0   rL   )r   r1   moder   r   r   rL   [  s    zLocalFS.chmodc             C   s   t ||S )N)rI   rS   )r   rD   rE   r   r   r   rS   ^  s    zLocalFS.copyc             C   s   t ||S )N)rI   rJ   )r   rD   rE   r   r   r   rJ   a  s    zLocalFS.copy2c             C   s   t j|S )N)r0   r1   rm   )r   r1   r   r   r   rm   d  s    zLocalFS.existsc             C   s   t j|S )N)r0   r1   r   )r   r1   r   r   r   r   g  s    zLocalFS.getmtimec             C   s   t j|S )N)r0   r1   r   )r   r1   r   r   r   r   j  s    zLocalFS.getsizec             C   s   t j|S )N)r0   r1   r_   )r   r1   r   r   r   r_   m  s    zLocalFS.isdirc             C   s   t j|S )N)r0   r1   r   )r   r1   r   r   r   r   p  s    zLocalFS.isfilec             C   s   t ||S )N)r0   r<   )r   rD   rE   r   r   r   r<   s  s    zLocalFS.linkc             C   s
   t |S )N)r0   r   )r   r1   r   r   r   r   v  s    zLocalFS.lstatc             C   s
   t |S )N)r0   listdir)r   r1   r   r   r   r.  y  s    zLocalFS.listdirc             C   s
   t |S )N)r0   scandir)r   r1   r   r   r   r/  |  s    zLocalFS.scandir  Fc             C   s   t j|||dS )N)r-  exist_ok)r0   r`   )r   r1   r-  r1  r   r   r   r`     s    zLocalFS.makedirsc             C   s   t j||dS )N)r-  )r0   rn   )r   r1   r-  r   r   r   rn     s    zLocalFS.mkdirc             C   s   t ||S )N)r0   rename)r   oldnewr   r   r   r2    s    zLocalFS.renamec             C   s
   t |S )N)r0   rK   )r   r1   r   r   r   rK     s    zLocalFS.statc             C   s   t ||S )N)r0   rG   )r   rD   rE   r   r   r   rG     s    zLocalFS.symlinkc             C   s   t |S )N)open)r   r1   r   r   r   r5    s    zLocalFS.openc             C   s
   t |S )N)r0   rj   )r   r1   r   r   r   rj     s    zLocalFS.unlinkrG   c             C   s   t j|S )N)r0   r1   r>   )r   r1   r   r   r   r>     s    zLocalFS.islinkc             C   s   dS )NFr   )r   r1   r   r   r   r>     s    r?   c             C   s
   t |S )N)r0   r?   )r   rg   r   r   r   r?     s    zLocalFS.readlinkc             C   s   dS )Nr,   r   )r   rg   r   r   r   r?     s    N)r0  F)r0  )r   r   r   r%   rL   rS   rJ   rm   r   r   r_   r   r<   r   r.  r/  r`   rn   r2  rK   rG   r5  rj   r2   r0   r>   r?   r   r   r   r   r,  I  s4   





r,  c               @   s   e Zd Zd&ddZdd Zdd Zdd	 Zd
d Zd'ddZdd Z	d(ddZ
d)ddZd*ddZd+ddZd,ddZdd Zdd  Zd!d" Zd-d$d%ZdS ).FSNc             C   s   t jjrt| d i | _i | _d| _t| _d| _	|dkrDt
 | _n|| _tt| jd | _| | j| _	d| j	_d| j	_| j	| _| t_| t_dS )a  Initialize the Node.FS subsystem.

        The supplied path is the top of the source tree, where we
        expect to find the top-level build file.  If no path is
        supplied, the current directory is the default.

        The path argument must be a valid absolute path.
        zNode.FSNr   r   )r   r   r   r   r   Rootr   default_max_drift	max_driftTopr0   r   ZpathToprz   r5   defaultDriver   r   r   r  DirNodeInforC   FileNodeInfo)r   r1   r   r   r   r     s"    	 
zFS.__init__c             C   s
   || _ d S )N)r   )r   rf   r   r   r   set_SConstruct_dir  s    zFS.set_SConstruct_dirc             C   s   | j S )N)r9  )r   r   r   r   get_max_drift  s    zFS.get_max_driftc             C   s
   || _ d S )N)r9  )r   r9  r   r   r   set_max_drift  s    zFS.set_max_driftc             C   s   t | dr| jS dS d S )Nr  z<no cwd>)r2   r  )r   r   r   r   r     s    
z	FS.getcwdr   c             C   sL   | j }y$|dk	r(|| _ |r(t|  W n tk
rF   || _  Y nX dS )zChange the current working directory for lookups.
        If change_os_dir is true, we will also change the "real" cwd
        to match.
        N)r  r0   chdirr^   rb   )r   rf   Zchange_os_dirZcurrr   r   r   rA    s    zFS.chdirc             C   sf   t |}y
| j| S  tk
r`   t|| }|| j|< |sH|| j| j< n|| jkr\|| jd< |S X dS )zg
        Returns the root directory for the specified drive, creating
        it if necessary.
        r,   N)rz   r7  r   RootDirr;  )r   r:   r  r   r   r   get_root  s    




zFS.get_rootr   c          	   C   s   t |tr|| |S t|}ts0|td}|dd dkr|dd }| j}trzt	|\}}|rr| 
|}q|j}n|j}|d}t|}|dkr| }n| d | }ntrt	|\}}|r|sd}nd}|dkr|d}t|}|dd dkr| 
|}n`|r.t |ts4| |}n| j}|dkrH| }n| d | }|rj| 
|}n|j}|dk	r|ddd }g }	xR|D ]J}
|
dkry|	  W n tk
r   Y nX n|
dkr|	|
 qW dd|	 }||||S )	a  
        The generic entry point for Node lookup with user-supplied data.

        This translates arbitrary input into a canonical Node.FS object
        of the specified fsclass.  The general approach for strings is
        to turn it into a fully normalized absolute path and then call
        the root directory's lookup_abs() method for the heavy lifting.

        If the path name begins with '#', it is unconditionally
        interpreted relative to the top-level directory of this FS.  '#'
        is treated as a synonym for the top-level SConstruct directory,
        much like '~' is treated as a synonym for the user's home
        directory in a UNIX shell.  So both '#foo' and '#/foo' refer
        to the 'foo' subdirectory underneath the top-level SConstruct
        directory.

        If the path name is relative, then the path is looked up relative
        to the specified directory, or the current directory (self._cwd,
        typically the SConscript directory) if the specified directory
        is None.
        r/   r   r   #N)r,   r   r,   z..)r   r   r   r   r9   r   r7   r:  r4   r5   rC  r  stripneeds_normpath_matchr   rstripr   r  rX   pop
IndexErrorrY   rA   _lookup_abs)r   r-   r   Zfsclasscreater:   r  Zneeds_normpathZinsZoutsr*  r   r   r   _lookup  sj    











z
FS._lookupc             C   s   |  ||t|S )aQ  Look up or create a generic Entry node with the specified name.
        If the name is a relative path (begins with ./, ../, or a file
        name), then it is looked up relative to the supplied directory
        node, or to the top level directory of the FS (supplied at
        construction time) if no directory is supplied.
        )rL  r   )r   r!   r   rK  r   r   r   r     s    zFS.Entryc             C   s   |  ||t|S )a  Look up or create a File node with the specified name.  If
        the name is a relative path (begins with ./, ../, or a file name),
        then it is looked up relative to the supplied directory node,
        or to the top level directory of the FS (supplied at construction
        time) if no directory is supplied.

        This method will raise TypeError if a directory is found at the
        specified path.
        )rL  r  )r   r!   r   rK  r   r   r   r    s    
zFS.FileTc             C   s   |  ||t|S )a  Look up or create a Dir node with the specified name.  If
        the name is a relative path (begins with ./, ../, or a file name),
        then it is looked up relative to the supplied directory node,
        or to the top level directory of the FS (supplied at construction
        time) if no directory is supplied.

        This method will raise TypeError if a normal file is found at the
        specified path.
        )rL  r   )r   r!   r   rK  r   r   r   r     s    
zFS.Dirc             C   s   t |tjjs| |}t |tjjs0| |}||rFtjd|jrp|j|krZdS tjd||jf ||| dS )zcLink the supplied variant directory to the source directory
        for purposes of building files.z3Source directory cannot be under variant directory.Nz*'%s' already has a source directory: '%s'.)	r   r   r   r   r   rV   r   r   r<   )r   Zvariant_dirZsrc_dirrZ   r   r   r   
VariantDir  s    



zFS.VariantDirc             G   s6   x0|D ](}t |tjjs"| |}| j| qW dS )z)Specify Repository directories to search.N)r   r   r   r   r:  addRepository)r   dirsr*  r   r   r   
Repository  s    

zFS.Repositoryc             C   s.   d}t j|}tj|j}| |dtdS )a  Locate the directory of a given python module name

        For example scons might resolve to
        Windows: C:\Python27\Lib\site-packages\scons-2.5.1
        Linux: /usr/lib/scons

        This can be useful when we want to determine a toolpath based on a python module namer,   NT)		importlibutil	find_specr0   r1   rB   originrL  r   )r   Z
modulenamedirpathZmodspecr   r   r   PyPackageDir  s    	zFS.PyPackageDirc       
      C   s   g }d}d}|}xl|r|xN|j D ]D}||r>|g|t| fS tjj|jf| }	|| |	 qW |j	g| }|
 }qW |r|dtt| }||fS )aa  Create targets in corresponding variant directories

        Climb the directory tree, and look up path names
        relative to any linked variant directories we find.

        Even though this loops and walks up the tree, we don't memoize
        the return value because this is really only used to process
        the command-line targets.
        Nz*building associated VariantDir targets: %s )r  r   r   r0   r1   rA   r   rY   r   r!   upmap)
r   Zorigrf   tailtargetsmessager#   Z	start_dirZbdr-   r   r   r   variant_dir_target_climb  s    

zFS.variant_dir_target_climbFc             C   s"   |dkr|   }||||||S )z<
        Globs

        This is mainly a shim layer
        N)r   glob)r   r   r	  rd   r
  excluder   r   r   r   Glob  s    zFS.Glob)N)r   )r   )Nr   )Nr   )NT)r   )TTFNN)r   r   r   r   r>  r?  r@  r   rA  rC  rL  r   r  r   rM  rP  rV  r]  r`  r   r   r   r   r6    s"   
 

 	
	


r6  c               @   s    e Zd ZdZdZdZdd ZdS )r<  r   r*   Nc             C   sV   | j j}|j}tr.t|\}}|r.| j |}tj|sJ|	 d | }|
|tS )Nr/   )rC   r:  r  r4   r5   rC  r0   r1   r@   r   rJ  r   )r   stopr  r:   r   r   r   str_to_node  s    zDirNodeInfo.str_to_node)r   r   r   r  current_version_idrC   rc  r   r   r   r   r<    s   r<  c               @   s   e Zd ZdZdZdS )DirBuildInfor   r*   N)r   r   r   r  rd  r   r   r   r   re    s   re  z[*?[]c             C   s   t | d k	S )N)glob_magic_checksearch)ra  r   r   r   has_glob_magic  s    rh  c                   s.  e Zd ZdZdddddddd	d
dddddgZeZeZ fddZ	dd Z
dd Zd~ddZdd Zdd ZdddZd d! Zd"d# Zd$d% Zejjd&d' Zd(d) Zd*d+ Zd,d- Zejed.d/ Zi fd0d1Zd2d3 Zd4d5 Zd6d7 Zd8d9 Z d:d; Z!d<d= Z"d>d? Z#d@dA Z$dBdC Z%dDdE Z&dFdG Z'dHdI Z(dJdK Z)dLdM Z*dNdO Z+dPdQ Z,e-dRdSdTZ.e/dRdUdVZ0e/dRdWdXZ1dYdZ Z2d[d\ Z3d]d^ Z4d_d` Z5dadb Z6dcdd Z7dedf Z8dgdh Z9didj Z:ejjdkdl Z;dmdn Z<dodp Z=eje=dqdr Z>dsdt Z?dudv Z@dwdx ZAddzd{ZBdd|d}ZC  ZDS )r   z.A class for directories in a file system.
    r  r  r  r  r   r  r  r   r  r  rB   r  r  r  c                s.   t jjrt| d t ||| |   d S )NzNode.FS.Dir)r   r   r   r   r   r   r  )r   r!   r   rC   )r   r   r   r   !  s     
zDir.__init__c             C   sd  g | _ d| _| | jd| _| | _d| _d| _g | _| jj| _d| _	d| _
d| _d| _tj| j| j| _tj| j| j| _| jjdkrtj| j| _ntj| j| j| _| jjdkrtj| j| _ntj| j| j| _| jj| g | _| jt | _t| ds4t | _|   | jj! n,|  j"}t j!}|#d| |   | dS )	aW  Turn a file system Node (either a freshly initialized directory
        object or a separate Entry object) into a proper directory object.

        Set up this directory's entries and hook it into the file
        system tree.  Specify that directories (this Node) don't use
        signatures for calculating whether they're current.
        N)r   z..r   r  r   r*   r   executor)$r  r   rf   r  r   r  r   r  r  r   r   r   r   r   r   r   r   r!   r   r   r   r   r   r   r   r   r7   rB   r2   rv   r   get_executorset_action_listrq   action_listinsert)r   lar   r   r   r  &  s:    	


z
Dir._morphc             C   s   t | | jd d S )Nz'File %s found where directory expected.)r  r   )r   r   r   r   r  f  s    zDir.diskcheck_matchNc          	   C   st   xn| j  D ]`}|| jkr|| kr8t|tr8|| q|  y|`W n tk
r\   Y nX |dk	r||_	qW dS )zCalled when we change the repository(ies) for a directory.
        This clears any cached information that is invalidated by changing
        the repository.N)
r  valuesrf   r   r   _Dir__clearRepositoryCacher  Z_srcrepsr   rZ   )r   rZ   r
   r   r   r   Z__clearRepositoryCachej  s    
zDir.__clearRepositoryCachec             C   s   || kr|  j|_d S )N)r   rZ   )r   r
   r   r   r   Z__resetDuplicate|  s    zDir.__resetDuplicatec             C   s   | j || S )zd
        Looks up or creates an entry node named 'name' relative to
        this directory.
        )rC   r   )r   r!   r   r   r   r     s    z	Dir.EntryTc             C   s   | j || |S )zg
        Looks up or creates a directory node named 'name' relative to
        this directory.
        )rC   r   )r   r!   rK  r   r   r   r     s    zDir.Dirc             C   s   | j || S )zb
        Looks up or creates a file node named 'name' relative to
        this directory.
        )rC   r  )r   r!   r   r   r   r    s    zDir.Filec             C   s&   || _ || _| | |j|  dS )zVSet this directory as the variant directory for the
        supplied source directory.N)r   rZ   rq  r  rY   )r   r   rZ   r   r   r   r<     s    
zDir.linkc             C   s"   | j r| js| j  | j S | jS )z;Returns a list of repositories for this directory.
        )r   rZ   r   r  )r   r   r   r   getRepositories  s    zDir.getRepositoriesc             C   s   yt | jd S  tk
r"   Y nX | g}d}| }xP|rx | D ]}||| qBW |dkrj|j}n|jt | }| }q4W t || jd< |S )Nr   r   )	r   r   r   rr  rY   r   r!   r7   rX  )r   r   fnamerf   Zrepr   r   r   r     s     zDir.get_all_rdirsc             C   s0   || kr,|| j kr,| j | d|_|   d S )Nr   )r  rY   r   rq  )r   rf   r   r   r   rN    s    zDir.addRepositoryc             C   s   | j S )N)rf   )r   r   r   r   rX    s    zDir.upc             C   s   t |S )N)r   )r   r   r   r   r   _rel_path_key  s    zDir._rel_path_keyc             C   s  y| j d }W n" tk
r0   i }|| j d< Y n X y|| S  tk
rN   Y nX | |kr^d}n|| jkry| }W n tk
r   t|}Y n:X |dkr|j}n(| |}|dkr|j}n|t |j }nF| j	|d }dgt
| j|  dd |j|d D  }t|}|||< |S )z=Return a path to "other" relative to this directory.
        r)  r   Nr   z..c             S   s   g | ]
}|j qS r   )r!   )r   nr   r   r   r     s    z Dir.rel_path.<locals>.<listcomp>)r   r   r   r   r   r   r!   r)  r7   r   lenrA   )r   r   r  r   Z	other_dirZdir_rel_pathr   r   r   r   r   r)    s8    


zDir.rel_pathc             C   s   dd l }|jjS )Nr   )rr   rt   ru   )r   re   r   r   r   r   r   get_env_scanner  s    zDir.get_env_scannerc             C   s   dd l }|jjS )Nr   )rr   rt   ru   )r   r   r   r   r   get_target_scanner  s    zDir.get_target_scannerc             C   s   |sg S |    || ||S )a7  Return this directory's implicit dependencies.

        We don't bother caching the results because the scan typically
        shouldn't be requested more than once (as opposed to scanning
        .h file contents, which can be requested as many times as the
        files is #included by other files).
        )r  )r   re   scannerr1   r   r   r   get_found_includes  s    	zDir.get_found_includesc             C   s   d S )Nr   )r   r   r   r   prepare  s    zDir.preparec             K   s    | j tk	rtjjj| f| dS )z!A null "builder" for directories.N)r   rp   r   r   build)r   r   r   r   r   r|  "  s    
z	Dir.buildc          	   C   s   g }| }x>|rF|  rP || | }|dkr@tj|j|}q
W |  xH|D ]@}y&tjj	| |
   |  W qV tk
r   Y qVX qVW dS )zmCreate this directory, silently and without worrying about
        whether the builder is the default or not.N)rm   rY   rX  r   rV   	StopErrorr   reverser   r|  rj  Znullifyr  rb   )r   ZlistDirsparentr-   Zdirnoder   r   r   _create,  s$    

zDir._createc             C   s   | j tk	o|  S )N)r   rp   r   )r   r   r   r    multiple_side_effect_has_builderL  s    z$Dir.multiple_side_effect_has_builderc             C   s   | j | | g S )zAReturn any corresponding targets in a variant directory.
        )rC   r]  )r   r   r   r   alter_targetsP  s    zDir.alter_targetsc             C   s   dS )z!A directory does not get scanned.Nr   )r   r   r   r   r$  U  s    zDir.scanner_keyc             C   s   |   S )zJWe already emit things in text, so just return the binary
        version.)r&  )r   r   r   r   r'  Y  s    zDir.get_text_contentsc             C   s   t jj| j | S )zyReturn content signatures and names of all our children
        separated by new-lines. Ensure that the nodes are sorted.)r   r   r%  r   )r   r   r   r   r&  ^  s    zDir.get_contentsc             C   s   |   }t|S )a7  Compute the content signature for Directory nodes. In
        general, this is not needed and the content signature is not
        stored in the DirNodeInfo. However, if get_contents on a Dir
        node is called which has a child directory, the child
        directory should return the hash of its contents.)r&  r   )r   contentsr   r   r   get_csigc  s    zDir.get_csigc             C   s   d S )Nr   )r   rD   r   r   r   do_duplicatel  s    zDir.do_duplicatec             C   sD   | j tk	r|  sdS tjj}x |  D ]}| |kr(dS q(W dS )zJIf any child is not up-to-date, then this directory isn't,
        either.r   r   )r   rp   rm   r   r   
up_to_datechildren	get_state)r   r  kidr   r   r   is_up_to_dateo  s    zDir.is_up_to_datec          	   C   s~   |   szt| j}xf| j D ]X}y|j| }W n  tk
rP   || j}Y nX |r|  rt|t	srt|t
r|S qW | S )N)rm   rz   r!   rf   r   r  r   dir_on_diskr   r   r   )r   r  rf   r
   r   r   r   rdirz  s    
  zDir.rdirc             C   s   t | j | S )z3Return the .sconsign file info for this directory. )_sconsign_mapr   )r   r   r   r   sconsign  s    zDir.sconsignc             C   s   | j r| j S t| S )zmDir has a special need for srcnode()...if we
        have a srcdir attribute set, then that *is* our srcnode.)r   r   r   )r   r   r   r   r     s    zDir.srcnode)returnc             C   s.   d}x$|   D ]}| |kr| }qW |S )z3Return the latest timestamp from among our childrenr   )r  get_timestamp)r   Zstampr  r   r   r   r    s
    zDir.get_timestampc             C   s   | j S )z"Get the absolute path of the file.)r   )r   r   r   r   r^     s    zDir.get_abspathc             C   s   | j S )z"Get the absolute path of the file.)r   )r   r   r   r   r     s    zDir.get_labspathc             C   s   | j S )N)r   )r   r   r   r   r     s    zDir.get_internal_pathc             C   s   | j S )N)r   )r   r   r   r   r     s    zDir.get_tpathc             C   s   | j S )N)r   )r   r   r   r   r     s    zDir.get_path_elementsc             C   s   | j t | S )N)r   r7   )r   r!   r   r   r   r     s    zDir.entry_abspathc             C   s   | j d | S )Nr/   )r   )r   r!   r   r   r   r     s    zDir.entry_labspathc             C   s   | j t | S )N)r   r7   )r   r!   r   r   r   r     s    zDir.entry_pathc             C   s   | j t | S )N)r   r7   )r   r!   r   r   r   r     s    zDir.entry_tpathc             C   s   y
| j }W n` tk
rj   i }yt| j}W n tk
rB   Y nX xtt|D ]}d||< qPW || _ Y nX tj	dkstj	dkrt|}|
|}|dkrtj| jt | }|||< |S ||kS dS )z Searches through the file/dir entries of the current
            directory, and returns True if a physical entry with the given
            name could be found.

            @see rentry_exists_on_disk
        Tr=   rx   N)r  r   r0   r.  r   rb   rY  rz   sysplatformr   r1   rm   r7   )r   r!   r*  r  r"   r   r   r   r   r    s&    

zDir.entry_exists_on_diskc          	   C   sj   |  |}|sft|}xN|  D ]B}y|j| }|r:d}P W q  tk
r`   | |r\d}P Y q X q W |S )a   Searches through the file/dir entries of the current
            *and* all its remote directories (repos), and returns
            True if a physical entry with the given name could be found.
            The local directory (self) gets searched first, so
            repositories take a lower precedence regarding the
            searching order.

            @see entry_exists_on_disk
        T)r  rz   r   r  r   )r   r!   Zrentry_existsr  r  r
   r   r   r   rentry_exists_on_disk  s    


zDir.rentry_exists_on_diskc             C   sr   y
| j d S  tk
r   Y nX g }d}| }x6|rb|jrJ||j| |jt | }| }q.W || j d< |S )Nr   r   )r   r   r   rY   r   r!   r7   rX  )r   r   rB   rf   r   r   r   r     s    

zDir.srcdir_listc             C   s`   xZ|   D ]N}| |rP ||r
|| }| jrT| | }|| |S |S q
W d S )N)r   r   r  r   r#  rZ   r  )r   r!   rf   r   r
   r   r   r   srcdir_duplicate  s    


zDir.srcdir_duplicatec             C   s   |S )Nr   )r   filenamer   r   r   _srcdir_find_file_key  s    zDir._srcdir_find_file_keyc       	   
   C   sN  y| j d }W n" tk
r0   i }|| j d< Y n X y|| S  tk
rN   Y nX dd }t|}x^|  D ]R}y|j| }W n tk
r   ||}Y n
X ||}|rj|| f}|||< |S qjW x||  D ]p}xj| D ]^}y|j| }W n  tk
r
   ||}Y n
X ||}|rt|| | j|f}|||< |S qW qW d}|||< |S )Nsrcdir_find_filec             S   s,   t | tst | tr(|  s$|  r(| S d S )N)r   r  r   r   rm   )r
   r   r   r   r[   %  s    z"Dir.srcdir_find_file.<locals>.func)NN)	r   r   rz   r   r  file_on_diskr   r  rC   )	r   r  r  r[   r  r  r
   r   r   r   r   r   r    sF        zDir.srcdir_find_filec             C   sF   |  |r*y
| |S  tk
r(   Y nX | |}t|trBd S |S )N)r  r   r   r  r   r  )r   r!   r
   r   r   r   r  D  s    
 
 

zDir.dir_on_diskc             C   sF   |  |r*y
| |S  tk
r(   Y nX | |}t|trBd S |S )N)r  r  r   r  r   r   )r   r!   r
   r   r   r   r  M  s    
 
 

zDir.file_on_diskc                sb   | j  t  }|d |d ||| | x* fdd|D D ]} | || qFW dS )a  
        Walk this directory tree by calling the specified function
        for each directory in the tree.

        This behaves like the os.path.walk() function, but for in-memory
        Node.FS.Dir objects.  The function takes the same arguments as
        the functions passed to os.path.walk():

                func(arg, dirname, fnames)

        Except that "dirname" will actually be the directory *Node*,
        not the string.  The '.' and '..' entries are excluded from
        fnames.  The fnames list may be modified in-place to filter the
        subdirectories visited or otherwise impose a specific order.
        The "arg" argument is always passed to func() and may be used
        in any way (or ignored, passing None is common).
        r   z..c                s   g | ]}t  | tr|qS r   )r   r   )r   ru  )r  r   r   r   m  s    zDir.walk.<locals>.<listcomp>N)r  r   keysremovewalk)r   r[   argnamesrB   r   )r  r   r  V  s    

zDir.walkFc                s   t j|\}}|s&| ||||}nnt|rB| |||d|}	n| j|ddg}	g }x<|	D ]4  ||||}
|r fdd|
D }
||
 q\W |rg tj	
|}x&|D ]}| ||||}
|
 qW fdd|D }t|dd d	S )
a  
        Returns a list of Nodes (or strings) matching a specified
        pathname pattern.

        Pathname patterns follow UNIX shell semantics:  * matches
        any-length strings of any characters, ? matches any character,
        and [] can enclose lists or ranges of characters.  Matches do
        not span directory separators.

        The matches take into account Repositories, returning local
        Nodes if a corresponding entry exists in a Repository (either
        an in-memory Node or something on disk).

        By defafult, the glob() function matches entries that exist
        on-disk, in addition to in-memory Nodes.  Setting the "ondisk"
        argument to False (or some other non-true value) causes the glob()
        function to only match in-memory Nodes.  The default behavior is
        to return both the on-disk and in-memory Nodes.

        The "source" argument, when true, specifies that corresponding
        source Nodes must be returned if you're globbing in a build
        directory (initialized with VariantDir()).  The default behavior
        is to return Nodes local to the VariantDir().

        The "strings" argument, when true, returns the matches as strings,
        not Nodes.  The strings are path names relative to this directory.

        The "exclude" argument, if not None, must be a pattern or a list
        of patterns following the same UNIX shell semantics.
        Elements matching a least one pattern of this list will be excluded
        from the result.

        The underlying algorithm is adapted from the glob.glob() function
        in the Python library (but heavily modified), and uses fnmatch()
        under the covers.
        FT)rK  c                s   g | ]}t jt |qS r   )r0   r1   rA   r   )r   ry   )rf   r   r   r     s    zDir.glob.<locals>.<listcomp>c                s.   g | ]& t  fd dtjD s qS )c             3   s"   | ]}t  t t|V  qd S )N)fnmatchr   )r   e)ry   r   r   	<genexpr>  s    z&Dir.glob.<locals>.<listcomp>.<genexpr>)anyr   r   flatten)r   )excludes)ry   r   r     s    c             S   s   t | S )N)r   )ro  r   r   r   <lambda>      zDir.glob.<locals>.<lambda>)key)r0   r1   rX   r  rh  r^  r   r   r   r   r  sorted)r   r   r	  rd   r
  r_  rB   basenamer   r   r   ZexcludeListry   r   )rf   r  r   r^  p  s(    %

zDir.globc          	      sr     }x  D ]}||   qW  j}g }x|D ]}	dd |	j D }
||
 |stx|
D ]}|| qdW |r8yt|	j}W n tj	k
r   w8Y nX || |s8|d dkrdd |D }t
||}|	j}xD|D ]<}d| }|| }||}|j|jkr|j|_|  qW q8W t|}|d dkrJdd |D }t
||}|r`|S  fdd|D S )	aj  
        Globs for and returns a list of entry names matching a single
        pattern in this directory.

        This searches any repositories and source directories for
        corresponding entries and returns a Node (or string) relative
        to the current directory if an entry is found anywhere.

        TODO: handle pattern with no wildcard
        c             S   s   g | ]\}}|d kr|j qS ))r   z..)r!   )r   kvr   r   r   r     s    zDir._glob1.<locals>.<listcomp>r   r   c             S   s   g | ]}|d  dkr|qS )r   r   r   )r   ry   r   r   r   r     s    z./c             S   s   g | ]}|d  dkr|qS )r   r   r   )r   ry   r   r   r   r     s    c                s   g | ]} j t| qS r   )r  rz   )r   ru  )r   r   r   r     s    )r   r   r   r   r  itemsr0   r.  r   r   r  filterr#  r   r  r   )r   r  r	  rd   r
  Zsearch_dir_listr   Z	selfEntryr  rf   Z
node_namesr!   Z
disk_namesZdirEntryr
   ru  r   )r   r   r    sH    


 
	
z
Dir._glob1)N)T)TFFN)TFF)Er   r   r   r%   r  r<  NodeInfore  	BuildInfor   r  r  rq  Z_Dir__resetDuplicater   r   r  r<   rr  r   r  r  r   rN  rX  rt  r  r)  rw  rx  rz  r{  r|  r  r  r  r$  r'  r&  r  r  r  r  r  r   intr  r   r^   r   r   r   r   r   r   r   r   r  r  r   r  r  r  r  r  r  r^  r  r&   r   r   )r   r   r     s   @

7
 	,		
<r   c               @   s~   e Zd ZdZdZdd Zdd Zdd Zdd
dZdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd ZdS ) rB  a  A class for the root directory of a file system.

    This is the same as a Dir class, except that the path separator
    ('/' or '\') is actually part of the name, so we don't need to
    add a separator when creating the path names of entries within
    this directory.
    )_lookupDictr   r1   c             C   s   t jjrt| d t jj|  |dkr2t}t}n|dkrDt}t}n|}|t }t j	|| _
|| _| g| _| | _d| _d| _d| _|| _d| _|| _|| _|| _| j| _| j| _|   d| _| | d| _| | _ts| | jd< d S )NzNode.FS.RootDirr,   z//r*   r   r   )r,   r/   )r   r   r   r   r   r   r7   r8   r   r   r!   rC   r   rf   r   r   r   r   r   r   r   rB   r   r1   r  rZ   r  r  r3   )r   r:   rC   r!   rB   r   r   r   r     s>     
zRootDir.__init__c             C   s   g | _ d| _| | jd| _| | _d| _d| _g | _d| _d| _	d| _
d| _t| dspt | _|  | jj n,|  j}t j}|d| |  | dS )aW  Turn a file system Node (either a freshly initialized directory
        object or a separate Entry object) into a proper directory object.

        Set up this directory's entries and hook it into the file
        system tree.  Specify that directories (this Node) don't use
        signatures for calculating whether they're current.
        N)r   z..r   r  r   r*   ri  )r  r   rf   r  r   r  r   r  r   r   r   r   r2   rv   r   rj  rk  rq   rl  rm  )r   rn  ro  r   r   r   r  4	  s$    	


zRootDir._morphc             C   s   |t krd S t| | d S )N)r   r   r   )r   r   r   r   r   r   ]	  s    zRootDir.must_be_samer   c       
      C   s   t |}y| j| }W n tk
r   |sFd|t| f }tj||dd\}}| |t	}	|||	| j
}|  || j|< ||	jt |< d|	_Y nX || |S )a  
        Fast (?) lookup of a *normalized* absolute path.

        This method is intended for use by internal lookups with
        already-normalized path data.  For general-purpose lookups,
        use the FS.Entry(), FS.Dir() or FS.File() methods.

        The caller is responsible for making sure we're passed a
        normalized absolute path; we merely let Python's dictionary look
        up and return the One True Node.FS object for the path.

        If a Node for the specified "p" doesn't already exist, and
        "create" is specified, the Node may be created after recursive
        invocation to find or create the parent directory or directories.
        z=No such file or directory: '%s' in '%s' (and create is False)r/   r   N)rz   r  r   r   r   rV   r   rsplitrJ  r   rC   r  r  Zimplicitr   )
r   r-   r   rK  r  r   r"  Zdir_name	file_nameZdir_noder   r   r   rJ  b	  s     

zRootDir._lookup_absc             C   s   | j S )N)r   )r   r   r   r   r$   	  s    zRootDir.__str__c             C   s
   | j | S )N)r   )r   r!   r   r   r   r   	  s    zRootDir.entry_abspathc             C   s   d| S )Nr/   r   )r   r!   r   r   r   r   	  s    zRootDir.entry_labspathc             C   s
   | j | S )N)r   )r   r!   r   r   r   r   	  s    zRootDir.entry_pathc             C   s
   | j | S )N)r   )r   r!   r   r   r   r   	  s    zRootDir.entry_tpathc             C   s   | |krdS dS d S )Nr   r   r   )r   rf   r   r   r   r   	  s    zRootDir.is_underc             C   s   d S )Nr   )r   r   r   r   rX  	  s    z
RootDir.upc             C   s   d S )Nr   )r   r   r   r   r   	  s    zRootDir.get_dirc             C   s   t S )N)_null)r   r   r   r   r   	  s    zRootDir.src_builderN)r   )r   r   r   r%   r  r   r  r   rJ  r$   r   r   r   r   r   rX  r   r   r   r   r   r   rB    s   :)
*rB  c               @   sJ   e Zd ZdZdZdddgZdZdd Zd	d
 Zdd Z	dd Z
dd ZdS )r=  )csig	timestampsizer*   r  r  r  Nc             C   sV   | j j}|j}tr.t|\}}|r.| j |}tj|sJ|	 d | }|
|tS )Nr/   )rC   r:  r  r4   r5   rC  r0   r1   r@   r   rJ  r   )r   ra  rb  r  r:   r   r   r   rc  	  s    zFileNodeInfo.str_to_nodec             C   s   t | di  }xBt|  D ]2}x,t |ddD ]}t| |r0t | |||< q0W qW | j|d< y
|d= W n tk
r|   Y nX |S )a0  
        Return all fields that shall be pickled. Walk the slots in the class
        hierarchy and add those to the state dictionary. If a '__dict__' slot is
        available, copy all entries to the dictionary. Also include the version
        id, which is fixed for all instances of a class.
        __dict__r  r   _version_id__weakref__)getattrrS   r}   mror2   rd  r   )r   stateobjr!   r   r   r   __getstate__	  s    


zFileNodeInfo.__getstate__c             C   s4   |d= x(|  D ]\}}|dkrt| || qW dS )z>
        Restore the attributes from a pickled state.
        r  )r  N)r  setattr)r   r  r  valuer   r   r   __setstate__	  s    zFileNodeInfo.__setstate__c             C   s$   | j |j ko"| j|jko"| j|jkS )N)r  r  r  )r   r   r   r   r   __eq__	  s    zFileNodeInfo.__eq__c             C   s   |  | S )N)r  )r   r   r   r   r   __ne__	  s    zFileNodeInfo.__ne__)r   r   r   r  rd  Z
field_listrC   rc  r  r  r  r  r   r   r   r   r=  	  s   

r=  c                   sL   e Zd ZdZdgZdZ fddZdd Zdd	 Zd
d Z	dddZ
  ZS )FileBuildInfoa  
    This is info loaded from sconsign.

    Attributes unique to FileBuildInfo:
        dependency_map : Caches file->csig mapping
            for all dependencies.  Currently this is only used when using
            MD5-timestamp decider.
            It's used to ensure that we copy the correct csig from the
            previous build to be written to .sconsign when current build
            is done. Previously the matching of csig to file was strictly
            by order they appeared in bdepends, bsources, or bimplicit,
            and so a change in order or count of any of these could
            yield writing wrong csig, and then false positive rebuilds
    dependency_mapr*   c                s$   |dkrt | dr| `t ||S )Nr  )r2   r  r   __setattr__)r   r  r  )r   r   r   r  	  s    zFileBuildInfo.__setattr__c          	   C   s^   t r
t}ndd }xFdD ]>}yt| |}W n tk
r>   Y qX t| |tt|| qW dS )a   
        Converts this FileBuildInfo object for writing to a .sconsign file

        This replaces each Node in our various dependency lists with its
        usual string representation: relative to the top-level SConstruct
        directory, or an absolute path if it's outside.
        c             S   s:   y|   }W n tk
r(   t| }Y nX |td}|S )Nr/   )r   r   r   r   r7   )ru  ra  r   r   r   node_to_str
  s    z6FileBuildInfo.convert_to_sconsign.<locals>.node_to_str)bsourcesbdepends	bimplicitN)r9   r   r  r   r  r   rY  )r   r  r   r(   r   r   r   convert_to_sconsign
  s    
z!FileBuildInfo.convert_to_sconsignc             C   s   dS )z
        Converts a newly-read FileBuildInfo object for in-SCons use

        For normal up-to-date checking, we don't have any conversion to
        perform--but we're leaving this method here to make that clear.
        Nr   )r   rf   r!   r   r   r   convert_from_sconsign
  s    z#FileBuildInfo.convert_from_sconsignc       	   	   C   s   dddg}x|D ]\}}yt | |}t | |}W n tk
rF   wY nX |dks|dkrZqg }x8t||D ]*\}}t|tjjs||}|| qjW t| || qW dS )aP  
        Prepares a FileBuildInfo object for explaining what changed

        The bsources, bdepends and bimplicit lists have all been
        stored on disk as paths relative to the top-level SConstruct
        directory.  Convert the strings to actual Nodes (for use by the
        --debug=explain code and --implicit-cache).
        )r  bsourcesigs)r  bdependsigs)r  bimplicitsigsN)	r  r   zipr   r   r   rc  rY   r  )	r   ZattrsZnattrZsattrr
  Z	nodeinfosZnodesra  Znir   r   r   prepare_dependencies&
  s"    


z"FileBuildInfo.prepare_dependenciesr   c          	   C   s   g }| j | j | j }| j| j | j }x:t||D ],\}}|t|d d	|j
|d  q4W t| dstd| _|d| j| jf  d	|S )Nz: rW  )r  bactZnonez%s [%s]
)r  r  r  r  r  r  r  rY   r   rA   formatr2   r  bactsig)r   r  r   ZbkidsZbkidsigsZbkidZbkidsigr   r   r   r  C
  s    
zFileBuildInfo.format)r   )r   r   r   r%   r  rd  r  r  r  r  r  r&   r   r   )r   r   r  	  s   	r  c                   s~  e Zd ZdZdddddddd	d
dddddgZeZeZdZ	dd Z
 fddZdd ZdddZdd Zdd Zdd Zd d! Zed"d#d$Zed"d%d&Zed"d'd(Zejjed"d)d*Zejjed"d+d,Zd-d.d/d0d1d2gZd3d4d5gZd6d7 Zejjd8d9 Z d:d; Z!d<d= Z"d>d? Z#ej$e#d@dA Z%dBdC Z&dDdE Z'dFdG Z(dHdI Z)dJdK Z*dLdM Z+dNdO Z,dPdQ Z-dRdS Z.dTdU Z/dVdW Z0dXdY Z1dZd[ Z2ejjd\d] Z3e4e d"d^d_Z5ed"d`daZ6dbdc Z7ddde Z8ddhdiZ9ddjdkZ:ddldmZ;i Z<i Z=dndo Z>dpdq Z?drds Z@ddtduZAddvdwZBddxdyZCdzd{ ZDejjd|d} ZEd~d ZFdd ZGdd ZHdd ZIdd ZJ  ZKS )r  z(A class for files in a file system.
    r  r  r  r  r   r  r  r   r  r  rB   r  r  r  i   c             C   s   t | | jd d S )Nz'Directory %s found where file expected.)r  r_   )r   r   r   r   r  i
  s    zFile.diskcheck_matchc                s.   t jjrt| d t ||| |   d S )NzNode.FS.File)r   r   r   r   r   r   r  )r   r!   r   rC   )r   r   r   r   m
  s     
zFile.__init__c             C   s   | j |S )zQCreate an entry node named 'name' relative to
        the directory of this file.)rf   r   )r   r!   r   r   r   r   r
  s    z
File.EntryTc             C   s   | j j||dS )zTCreate a directory node named 'name' relative to
        the directory of this file.)rK  )rf   r   )r   r!   rK  r   r   r   r   w
  s    zFile.Dirc                s    fdd|D S )zWCreate a list of directories relative to the SConscript
        directory of this file.c                s   g | ]}  |qS r   )r   )r   r-   )r   r   r   r   
  s    zFile.Dirs.<locals>.<listcomp>r   )r   r   r   )r   r   Dirs|
  s    z	File.Dirsc             C   s   | j |S )zOCreate a file node named 'name' relative to
        the directory of this file.)rf   r  )r   r!   r   r   r   r  
  s    z	File.Filec             C   sP   i | _ t| dsd| _t| ds&d| _d| _d| _d| _d| _|  rLd| _d	S )
z+Turn a file system node into a File object.r   r   r  Fr      r     N)	r  r2   r   r  r   r   r   r   r   )r   r   r   r   r  
  s    

zFile._morphc             C   s   |   S )N)r   )r   r   r   r   r$  
  s    zFile.scanner_key)r  c             C   s   t jj| j | S )z)Return the contents of the file as bytes.)r   r   r%  r   )r   r   r   r   r&  
  s    zFile.get_contentsc             C   s  |   }|dttj tjkr8|ttjd dS |dttj tjkrh|ttjd dS |dttj tjkr|ttjd dS y
|dS  tk
 r } z<y
|dS  tk
r } z|jdddS d}~X Y nX W dd}~X Y nX dS )zReturn the contents of the file in text form.

        This attempts to figure out what the encoding of the text is
        based upon the BOM bytes, and then decodes the contents so that
        it's a valid python string.
        Nzutf-8z	utf-16-lez	utf-16-bezlatin-1backslashreplace)errors)r&  rv  codecsBOM_UTF8decodeBOM_UTF16_LEBOM_UTF16_BEUnicodeDecodeError)r   r  r  r   r   r   r'  
  s    

zFile.get_text_contentsc          
   C   sh   |   sttjjS |   }yt|tj	d}W n0 t
k
rb } z|jsP||_ W dd}~X Y nX |S )z<
        Compute and return the hash for this file.
        )Z	chunksizeN)r   r   r   r   NOFILEr   r^   r   r  hash_chunksizeEnvironmentErrorr  )r   rs  Zcsr  r   r   r   get_content_hash
  s    zFile.get_content_hashc             C   sH   y
| j d S  tk
r   Y nX |  r6|   }nd}|| j d< |S )Nget_sizer]   )r   r   r   r   r   )r   r  r   r   r   r  
  s    

zFile.get_sizec             C   sH   y
| j d S  tk
r   Y nX |  r6|   }nd}|| j d< |S )Nr  r   )r   r   r   r   r   )r   r  r   r   r   r  
  s    

zFile.get_timestampr  r  r  r  r  ninfor  r  r  c       
   	   C   s   dd l }|j }|  |_|j}xJ| jD ]@}yt||}W n tk
rR   w*Y nX t||| t	|| q*W x| j
D ]~}yt||}W n tk
r   wvY nX g }x8|D ]0}|  }	t|dkr||	_n||	_||	 qW t||| t	|| qvW |S )Nr       )r   r   SConsignEntry	new_binfobinfoconvert_copy_attrsr  r   r  delattrconvert_sig_attrsr+  rv  r  r  rY   )
r   Z	old_entryr   Z	new_entryr  r   r  Zsig_listZsigr  r   r   r   convert_old_entry  s4    D


zFile.convert_old_entryc          	   C   s   y
| j d S  tk
r   Y nX y| j | j}W n> ttfk
rt   dd l}|j	 }| 
 |_|  |_Y n<X t|tr| |}yt|jd W n tk
r   Y nX || j d< |S )Nget_stored_infor   Zbsig)r   r   rf   r  Z	get_entryr!   r  r   r   r  r  r  r+  r  r   r  r  r  r   )r   Zsconsign_entryr   r   r   r   r  c  s&    





zFile.get_stored_infoc             C   s2   |   j}|  y|jS  tk
r,   d S X d S )N)r  r  r  r  r   )r   r  r   r   r   get_stored_implicit  s    
  zFile.get_stored_implicitc             C   s   | j |S )N)rf   r)  )r   r   r   r   r   r)    s    zFile.rel_pathc             C   s   t |t ||fS )N)id)r   re   ry  r1   r   r   r   _get_found_includes_key  s    zFile._get_found_includes_keyc             C   s   t |t ||f}y| jd }W n" tk
rB   i }|| jd< Y n X y|| S  tk
r`   Y nX |r~dd || ||D }ng }|||< |S )zReturn the included implicit dependencies in this file.
        Cache results so we only scan the file once per path
        regardless of how many times this information is requested.
        rz  c             S   s   g | ]}|  qS r   )r#  )r   ru  r   r   r   r     s    z+File.get_found_includes.<locals>.<listcomp>)r  r   r   )r   re   ry  r1   memo_keyr  r   r   r   r   rz    s    zFile.get_found_includesc             C   s   | j   d S )N)rf   r  )r   r   r   r   
_createDir  s    zFile._createDirc             C   s0   | j r
dS |   |  r,|   |  dS )z*Try to push the node into a cache
        N)nocacheclear_memoized_valuesrm   get_build_envget_CacheDirpush)r   r   r   r   push_to_cache  s
    
zFile.push_to_cachec             C   s(   | j r
dS |  sdS |   | S )a  Try to retrieve the node's content from a cache

        This method is called from multiple threads in a parallel build,
        so only do thread safe stuff here. Do thread unsafe stuff in
        built().

        Returns true if the node was successfully retrieved.
        N)r  r   r  r  Zretrieve)r   r   r   r   retrieve_from_cache  s
    	zFile.retrieve_from_cachec             C   s   |   r$| jd k	r$|   |  |  }|  }|r>||_|  |_	| 
 |_|  sr|  }|  |j tjj| j |  d S )N)rm   ri  r  r  Zpush_if_forced	get_ninfoget_max_drift_csigr  r  r  r  r  r   r  	get_binfomerger  r   r   store_info_mapr   )r   r  r  r3  r   r   r   visited  s    

zFile.visitedc             C   s   | j stjjrdS t| jds| jdd |   |   d| _	| j
dd d| _t| jsdd| _t| jstd| _t| jsd| _t| jsd| _t| jsd| _d| _ dS )a4  Called just after this node has been marked
         up-to-date or was built completely.

         This is where we try to release as many target node infos
         as possible for clean builds and update runs, in order
         to minimize the overall memory consumption.

         We'd like to remove a lot more attributes like self.sources
         and self.sources_set, but they might get used
         in a next build step. For example, during configuration
         the source files for a built E{*}.o file are used to figure out
         which linker to use for the resulting Program (gcc vs. g++)!
         That's why we check for the 'keep_targetinfo' attribute,
         config Nodes and the Interactive mode just don't allow
         an early release of most variables.

         In the same manner, we can't simply remove the self.attributes
         here. The smart linking relies on the shared flag, and some
         parts of the java Tool use it to transport information
         about nodes...

         @see: built() and Node.release_target_info()
         Nkeep_targetinfoT)
allowcacher   )r  r   r   interactiver2   
attributeschangedget_contents_sigr  ri  r   rH  Zprerequisitesrv  Z
ignore_setZimplicit_setZdepends_setr   Zdepends)r   r   r   r   release_target_info  s(    




zFile.release_target_infoc             C   sd   |   rd S | j }|tkr"d }|d k	r`y
| j}W n tk
rL   d }Y nX |d kr`| | |S )N)r   rf   r   r  r   r   r   )r   r   br   r   r   find_src_builder  s    



zFile.find_src_builderc             C   s6   y
| j }W n" tk
r,   |   }| _ Y nX |dk	S )a  Return whether this Node has a source builder or not.

        If this Node doesn't have an explicit source code builder, this
        is where we figure out, on the fly, if there's a transparent
        source code builder for it.

        Note that if we found a source builder, we also set the
        self.builder attribute, so that all of the methods that actually
        *build* this file don't have to do anything different.
        N)r   r   r
  )r   r   r   r   r   has_src_builder$  s
    
zFile.has_src_builderc             C   s&   |   rg dfS | j| | j| jgS )zAReturn any corresponding targets in a variant directory.
        N)r   rC   r]  rf   r!   )r   r   r   r   r  5  s    zFile.alter_targetsc             C   s@   |    tjjrtd|  t| g d }t|tjj	r<|d S )Nz dup: removing existing target {})
r  r   r   print_duplicateprintr  Unlinkr   rV   
BuildError)r   r  r   r   r   _rmv_existing<  s    zFile._rmv_existingc             C   s   |    |   d S )N)r  r  )r   r   r   r   
make_readyH  s    zFile.make_readyc          
   C   s   t jj|  |  t jjkr|  s.|  rF|  r| js| 	  nHy| 
  W n: t jjk
r } zt jd|| W dd}~X Y nX dS )z$Prepare for this file to be created.zNo drive `{}' for target `{}'.N)r   r   r{  r  r  rm   r>   r   Zpreciousr  r  rV   r}  r  )r   r:   r   r   r   r{  L  s    
zFile.preparec             C   s(   |   s|  r$| j|   dS dS )zRemove this file.r   N)rm   r>   rC   rj   r   )r   r   r   r   r  a  s    zFile.removec             C   sx   |    tjjr td| | t| d d  t| |d }t|tj	j
rftj	d| | jj|jd| _|   d S )Nz%dup: relinking variant '{}' from '{}'z"Cannot duplicate `{}' in `{}': {}.r   )r  r   r   r  r  r  r  Linkr   rV   r  r}  r   rf   r   ZerrstrZlinkedr  )r   rD   r  r   r   r   r  h  s     zFile.do_duplicatec             C   s@   y
| j d S  tk
r   Y nX tjj| j | }|| j d< |S )Nrm   )r   r   r   r   r   r   )r   r   r   r   r   rm   w  s    

zFile.existsc             C   s   |   }|  }| jj}|dkrnt | |kry&|j}|jrT|jrT|j|krT|jS W q tk
rj   Y qX n&|dkry|jjS  tk
r   Y nX dS )z
        Returns the content signature currently stored for this node
        if it's been unmodified longer than the max_drift value, or the
        max_drift value is 0.  Returns None otherwise.
        r   N)	r  r  rC   r9  timer  r  r  r   )r   r3  mtimer9  ru  r   r   r   r    s"    
zFile.get_max_drift_csigc             C   s   |   }y|jS  tk
r"   Y nX |  }|dkry:|  }|dkrPtjj}n|tj	k rd| 
 }n|  }W n tk
r   d}Y nX |stj|}||_|S )z$Generate a node's content signature.Nr]   r,   )r  r  r   r  r  r   r   r  r  r  r&  r  ra   r   )r   r  r  r  r  r   r   r   r    s(    



zFile.get_csigc             C   s   t jj| | d| _d S )Nr  )r   r   r   r   )r   r   r   r   r   r     s    zFile.builder_setc             C   sX   t jj|  t jjsTt| jdsTt jj| j |  d| _d| _	| 
  d| _d| _dS )a  Called just after this File node is successfully built.

         Just like for 'release_target_info' we try to release
         some more target node attributes in order to minimize the
         overall memory consumption.

         @see: release_target_info
        r  FN)r   r   builtr  r2   r  r   r   Z_specific_sourcesr   r   r   r  )r   r   r   r   r    s    
z
File.builtNFc             C   sJ   |dkr(y
| j d S  tk
r&   Y nX tjj| |}|rF|| j d< |S )ah  
        Returns if the node is up-to-date with respect to the BuildInfo
        stored last time it was built.

        For File nodes this is basically a wrapper around Node.changed(),
        but we allow the return value to get cached after the reference
        to the Executor got released in release_target_info().

        @see: Node.changed()
        Nr  )r   r   r   r   r  )r   r
   r  Zhas_changedr   r   r   r    s    

zFile.changedc             C   s,   |   }y
||jkS  tk
r&   dS X d S )Nr   )r  r  r   )r   rc   prev_ni	repo_nodeZcur_csigr   r   r   changed_content  s
    
zFile.changed_contentc             C   s   | j tjjkS )N)r  r   r   r  )r   rc   r  r  r   r   r   changed_state  s    zFile.changed_statec             C   s^   t |jt |j t |j dkr&i S dd tt|j|j|jt|j|j|jD |_	|j	S )z
        Build mapping from file -> signature

        Args:
            self - self
            binfo - buildinfo from node being considered

        Returns:
            dictionary of file->signature mappings
        r   c             S   s   i | ]\}}||qS r   r   )r   child	signaturer   r   r   
<dictcomp>  s    z.File._build_dependency_map.<locals>.<dictcomp>)
rv  r  r  r  r  r   r  r  r  r  )r   r  r   r   r   _build_dependency_map  s    zFile._build_dependency_mapc             C   s8   t tt|}||kr4dd | D }|| |S )z
        In the case comparing node objects isn't sufficient, we'll add the strings for the nodes to the dependency map
        :return:
        c             S   s   i | ]\}}|t |qS r   )r   )r   r  r  r   r   r   r  '  s    z7File._add_strings_to_dependency_map.<locals>.<dictcomp>)r   nextiterr  update)r   dmapZfirst_stringZstring_dictr   r   r   _add_strings_to_dependency_map  s
    
z#File._add_strings_to_dependency_mapc       
   
   C   s  g }t |dkr trtd dS tr4tdt |  trVtdt| t| t| f  || d}|rj|S |  }trtdt|t|t|f  ||d}|r|S t| g}tj	r|
|d tjtj	 x0|D ](}trtd|  ||d}|r|S qW | |}x6|D ].}tr*td	|  ||d}|r|S qW |syB|  }tj	rn|tjtj	}trtd
|  ||d}W n0 tk
r }	 ztd| W dd}	~	X Y nX |S )a  
        Return a list of corresponding csigs from previous
        build in order of the node/files in children.

        Args:
            self - self
            dmap - Dictionary of file -> csig

        Returns:
            List of csigs for provided list of children
        r   zNothing dmap shortcuttingNzlen(dmap):%dz,Checking if self is in  map:%s id:%s type:%sFz3Checking if self.rfile  is in  map:%s id:%s type:%sz$Checking if str(self) is in map  :%sz7Checking if str(self) is in map (now with strings)  :%sz;Checking if self.get_path is in map (now with strings)  :%sz6No mapping from file name to content signature for :%s)rv  MD5_TIMESTAMP_DEBUGr  r   r  r}   r   r   r0   altseprY   r   r6   r"  r   r   r   )
r   r!  prevZdfZrfZrfmZc_strsra  Zc_strr  r   r   r   _get_previous_signatures+  sZ        

 

 
 zFile._get_previous_signaturesc          
   C   s  |dkr| }|  j}d}y
|j}W n0 tk
rT } z| |}d}W dd}~X Y nX t|dkrztrntd |   dS | 	|}| 
||}	tr| 
||}
|
|	krtdt||
|	f  | 	|}|	sy|j|  _W n tk
r   Y nX dS | ||S )a  
        Used when decider for file is Timestamp-MD5

        NOTE: If the timestamp hasn't changed this will skip md5'ing the
              file and just copy the prev_ni provided.  If the prev_ni
              is wrong. It will propagate it.
              See: https://github.com/SCons/scons/issues/2980

        Args:
            self - dependency
            target - target
            prev_ni - The NodeInfo object loaded from previous builds .sconsign
            node - Node instance.  Check this node for file existence/timestamp
                   if specified.

        Returns:
            Boolean - Indicates if node(File) has changed.
        NFTr   zSkipping checks len(dmap)=0z@Mismatch self.changed_timestamp_match(%s, prev_ni) old:%s new:%s)r  r  r  r   r  rv  r#  r  r  r&  changed_timestamp_matchr   r  r  r  )r   rc   r  r
   ZbiZrebuiltr  r  Znew_prev_nir4  r3  r   r   r   changed_timestamp_then_content{  s8    


 

z#File.changed_timestamp_then_contentc             C   s*   y|   |  kS  tk
r$   dS X d S )Nr   )r  r   )r   rc   r  r  r   r   r   changed_timestamp_newer  s    zFile.changed_timestamp_newerc             C   s(   y|   |jkS  tk
r"   dS X dS )z
        Return True if the timestamps don't match or if there is no previous timestamp
        :param target:
        :param prev_ni: Information about the node from the previous build
        :return:
        r   N)r  r  r   )r   rc   r  r  r   r   r   r'    s    zFile.changed_timestamp_matchc             C   s   d}|rt d|   |  s|r(t d |  }|| kr| |s|rRt d|  | jrt| |d}t|tjj	rv|tj
j| j |  |rt d dS |   |rt d dS |  }|rt d	|  | S dS )
zCheck for whether the Node is current
           In all cases self is the target we're checking to see if it's up to date
        r   zis_up_to_date(%s):z not self.exists():z changed(%s):Nz 1
r   z None
z self.exists():  %s
)r   rm   r   r  r   	LocalCopyr   r   rV   r  r   r   r   )r   Tr   r  r   r   r   r    s6      
    zFile.is_up_to_datec          	   C   s   y
| j d S  tk
r   Y nX | }|  st| j}xx| j D ]j}y|j| }W n  tk
rt   || j}Y nX |rB| rBt	|t
st	|ts| sB|}| j|_P qBW || j d< |S )Nr   )r   r   rm   rz   r!   rf   r   r  r  r   r  r   r   r  )r   r   r  repo_dirr
   r   r   r   r     s(    


z
File.rfilec          	   C   s   g }t | j}xt| j D ]f}y|j| }W n  tk
rL   || j}Y nX |r| rt|t	svt|t
sv| s|| qW |S )z
        For this node, find if there exists a corresponding file in one or more repositories
        :return: list of corresponding files in repositories
        )rz   r!   rf   r   r  r   r  rm   r   r  r   r   rY   )r   Zretvalsr  r,  r
   r   r   r   find_repo_file  s    
zFile.find_repo_filec             C   s   t |  S )N)r   r   )r   r   r   r   r  &  s    z	File.rstrc             C   sl   y| j S  tk
r   Y nX |   }|| \}}|  s\|r\tj|r\|| | _ n
| 	 | _ | j S )a  
        Fetch a Node's content signature for purposes of computing
        another Node's cachesig.

        This is a wrapper around the normal get_csig() method that handles
        the somewhat obscure case of using CacheDir with the -n option.
        Any files that don't exist would normally be "built" by fetching
        them from the cache, but the normal get_csig() method will try
        to open up the local file, which doesn't exist because the -n
        option meant we didn't actually pull the file from cachedir.
        But since the file *does* actually exist in the cachedir, we
        can use its contents for the csig.
        )
r  r   r  r  Z	cachepathrm   r0   r1   get_cachedir_csigr  )r   cacheZcachedirZ	cachefiler   r   r   r.  )  s    
zFile.get_cachedir_csigc             C   s:   y| j S  tk
r   Y nX |  }t|  }| _ |S )z
        A helper method for get_cachedir_bsig.

        It computes and returns the signature for this
        node's contents.
        )r  r   rj  r   r&  )r   ri  r   r   r   r   r  D  s    zFile.get_contents_sigc             C   s`   y| j S  tk
r   Y nX |  }dd |D }||   ||   t| }| _ |S )aw  
        Return the signature for a cached file, including
        its children.

        It adds the path of the cached file to the cache signature,
        because multiple targets built by the same action will all
        have the same build signature, and we have to differentiate
        them somehow.

        Signature should normally be string of hex digits.
        c             S   s   g | ]}|  qS r   )r.  )r   ru  r   r   r   r   i  s    z*File.get_cachedir_bsig.<locals>.<listcomp>)r  r   r  rY   r  r   r   )r   r  Zsigsr   r   r   r   get_cachedir_bsigV  s    zFile.get_cachedir_bsig)T)NF)N)N)N)N)N)Lr   r   r   r%   r  r=  r  r  r  r  r  r   r   r   r  r  r  r$  bytesr&  r   r'  r  r   r  r  r  r  r  r  r  r  r  r  r)  r  r  rz  r  r  r  r  r  r
  r  r  r  r  r{  r  r  rm   r   r  r  r   r  r  r  r  Z_File__dmap_cacheZ_File__dmap_sig_cacher  r"  r&  r(  r)  r'  r  r   r-  r  r.  r  r0  r&   r   r   )r   r   r  P
  s   
`4$


P
=

"$r  c               C   s   t s
t a t S )N)
default_fsr6  r   r   r   r   get_default_fsw  s    r3  c               @   sB   e Zd ZdZdd ZdddZdddZej	edd	d
Z
dS )
FileFinderz
    c             C   s
   i | _ d S )N)r   )r   r   r   r   r     s    zFileFinder.__init__Nc       	      C   s   |dkr| j }tj|\}}t|\}}|sN|dd dtfkrN|j|S |rf| ||}|sfdS t	|}y|j
| }W n tk
r   ||S X t|tr|S t|tr|t |S dS )a$  
        A helper method for find_file() that looks up a directory for
        a file we're trying to find.  This only creates the Dir Node if
        it exists on-disk, since if the directory doesn't exist we know
        we won't find any files in it...  :-)

        It would be more compact to just use this as a nested function
        with a default keyword argument (see the commented-out version
        below), but that doesn't work unless you have nested scopes,
        so we define it here just so this work under Python 1.5.2.
        Nr   r/   )default_filedirr0   r1   rX   r5   r7   rC   rC  filedir_lookuprz   r  r   r  r   r   r   r   )	r   r-   fdrf   r!   r:   r*  r  r
   r   r   r   r6    s*    


zFileFinder.filedir_lookupc             C   s   t |trt|n|}||fS )N)r   r   tuple)r   r  pathsverboseZpaths_entryr   r   r   _find_file_key  s    zFileFinder._find_file_keyc                s  |  ||}y| jd }W n" tk
r<   i }|| jd< Y n X y|| S  tk
rZ   Y nX |rt|stj|sxd}d|   fdd}tj	|\}}|r|| _
dd t| j|D }d}xN|D ]F}|r|d||f  ||\}	}
|	r|r|d	||
f  |	}P qW |||< |S )
a  
        Find a node corresponding to either a derived file or a file that exists already.

        Only the first file found is returned, and none is returned if no file is found.

        filename: A filename to find
        paths: A list of directory path *nodes* to search in.  Can be represented as a list, a tuple, or a callable that is called with no arguments and returns the list or tuple.

        returns The node created from the found file.

        	find_filez  %s: c                s   t j |  S )N)r  stdoutwrite)ra  )_verboser   r   r    r  z&FileFinder.find_file.<locals>.<lambda>c             S   s   g | ]}|r|qS r   r   )r   Z_fr   r   r   r     s    z(FileFinder.find_file.<locals>.<listcomp>Nzlooking for '%s' in '%s' ...
z... FOUND '%s' in '%s'
)r;  r   r   callabler   r   Z	is_Stringr0   r1   rX   r5  rY  r6  r  )r   r  r9  r:  r  r  Zfiledirr   rf   r
   r*  r   )r?  r   r<    s>    
zFileFinder.find_file)N)N)N)r   r   r   r%   r   r6  r;  r   r  r  r<  r   r   r   r   r4  }  s   
#

r4  c          	   C   s   ddl m} x4| D ]&}|d dkr|d dd dkrP qW dS tj| sT| g} xF| D ]>}y|  W qZ tk
r   t |}|r|  Y qZX qZW dS )a  
    Invalidate the memoized values of all Nodes (files or directories)
    that are associated with the given entries. Has been added to
    clear the cache of nodes affected by a direct execution of an
    action (e.g.  Delete/Copy/Chmod). Existing Node caches become
    inconsistent if the action is run through Execute().  The argument
    `targets` can be a single Node object or filename, or a sequence
    of Nodes/filenames.
    r   )extract_stackr*   ZExecuteiNzEnvironment.py)		tracebackrA  r   r   Zis_Listr  r   r3  r   )r[  rA  fr"   r
   r   r   r   invalidate_node_memos  s    
 
rD  )tr%   r  r  importlib.utilrQ  r0   rerI   rK   r  r  	itertoolsr   typingr   ZSCons.Actionr   ZSCons.DebugZSCons.ErrorsZSCons.MemoizeZ
SCons.NodeZSCons.Node.AliasZSCons.SubstZ
SCons.UtilZSCons.Warningsr   r   r   r   r   r  r#  r   r   r  r(  r   r   r   r8  r'   r)   r4   r5   r;   compileVERBOSEZneeds_normpath_checkr   rF  r2   r  rF   rH   rR   rU   rW   r\   rh   ZActionr  ri   r*  rl   r  ro   rs   rp   rv   rw   r  Z
_is_cygwinr1   normcasenormpathrz   r|   r   r   r  r   r   r   r   r   r   r   r   r^   r   r   r   r   r   r   r   r   Z_classEntryr,  r6  ZNodeInfoBaser<  ZBuildInfoBasere  rf  rh  r   rB  r=  r  r  r2  r3  r4  r<  rD  r   r   r   r   <module>   s   &#


"
 
q   
 `  I
     i =:k        -c