B
    ›³ëbŒ   ã               @   sè   d Z ddlZddlmZmZ ddlmZ ddlZddl	Zddl
ZejjZejjZejjZejjZejjZejjZejjZdadZG dd„ dƒZg ZdZd	d
„ ZG dd„ deƒZG dd„ deƒZ G dd„ deƒZ!dd„ Z"G dd„ dƒZ#dS )a`  Generic Taskmaster module for the SCons build engine.

This module contains the primary interface(s) between a wrapping user
interface and the SCons build engine.  There are two key classes here:

Taskmaster
    This is the main engine for walking the dependency graph and
    calling things to decide what does or doesn't need to be built.

Task
    This is the base class for allowing a wrapping interface to
    decide what does or doesn't actually need to be done.  The
    intention is for a wrapping interface to subclass this as
    appropriate for different types of behavior it may need.

    The canonical example is the SCons native Python interface,
    which has Task subclasses that handle its specific behavior,
    like printing "'foo' is up to date" when a top-level target
    doesn't need to be built, and handling the -c option by removing
    targets as its "build" action.  There is also a separate subclass
    for suppressing this output when the -q option is used.

    The Taskmaster instantiates a Task object for each (set of)
    target(s) that it decides need to be evaluated and/or built.
é    N)ÚABCÚabstractmethod)ÚchainFc               @   s   e Zd ZdZdd„ ZdS )ÚStatsaN  
    A simple class for holding statistics about the disposition of a
    Node by the Taskmaster.  If we're collecting statistics, each Node
    processed by the Taskmaster gets one of these attached, in which case
    the Taskmaster records its decision each time it processes the Node.
    (Ideally, that's just once per Node.)
    c             C   s.   d| _ d| _d| _d| _d| _d| _d| _dS )zp
        Instantiates a Taskmaster.Stats object, initializing all
        appropriate counters to zero.
        r   N)Ú
consideredÚalready_handledÚproblemÚchild_failedÚ	not_builtÚside_effectsÚbuild)Úself© r   ú/lib/python3.7/site-packages/SCons/Taskmaster.pyÚ__init__R   s    zStats.__init__N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   r   J   s   r   zp%(considered)3d %(already_handled)3d %(problem)3d %(child_failed)3d %(not_built)3d %(side_effects)3d %(build)3d c              C   s8   x2t tdd„ dD ]} tt| jjj t| ƒ ƒ qW d S )Nc             S   s   t | ƒS )N)Ústr)Úar   r   r   Ú<lambda>j   ó    zdump_stats.<locals>.<lambda>)Úkey)ÚsortedÚ
StatsNodesÚprintÚfmtÚ
attributesÚstatsÚ__dict__r   )Únr   r   r   Ú
dump_statsi   s    r"   c               @   sÀ   e Zd ZdZdd„ Zd,dd„Zdd„ Zd	d
„ Zdd„ Ze	dd„ ƒZ
dd„ Zdd„ Zdd„ ZeZdd„ Zdd„ Zdd„ Zdd„ Zdd„ ZeZdd „ Zd!d"„ Zd#d$„ Zd-d&d'„Zd(d)„ Zd*d+„ Zd%S ).ÚTaskaù   SCons build engine abstract task class.

    This controls the interaction of the actual building of node
    and the rest of the engine.

    This is expected to handle all of the normally-customizable
    aspects of controlling a build, so any given application
    *should* be able to do what it wants by sub-classing this
    class and overriding methods as appropriate.  If an application
    needs to customize something by sub-classing Taskmaster (or
    some other build engine class), we should first try to migrate
    that functionality into this class.

    Note that it's generally a good idea for sub-classes to call
    these methods explicitly to update state, etc., rather than
    roll their own interaction with Taskmaster from scratch.
    c             C   s$   || _ || _|| _|| _|  ¡  d S )N)ÚtmÚtargetsÚtopÚnodeÚ	exc_clear)r   r$   r%   r&   r'   r   r   r   r   €   s
    zTask.__init__r'   c             C   s   d}||d || j  |¡f S )Nz%-20s %s %s
ú:)r$   Ú
trace_node)r   Úmethodr'   Zdescriptionr   r   r   r   Útrace_message‡   s    zTask.trace_messagec             C   s   dS )aà  
        Hook to allow the calling interface to display a message.

        This hook gets called as part of preparing a task for execution
        (that is, a Node to be built).  As part of figuring out what Node
        should be built next, the actual target list may be altered,
        along with a message describing the alteration.  The calling
        interface can subclass Task and provide a concrete implementation
        of this method to see those messages.
        Nr   )r   Úmessager   r   r   Údisplay‹   s    zTask.displayc             C   sÚ   | j j}|r | |  d| j¡¡ |  ¡  | j jrF|  | j j¡ d| j _| jd  	¡ }|dkr`dS | 
¡  xl| ¡ D ]`}tr¢td| ƒ x|jD ]}td| ƒ qŽW | 
¡  x&|jD ]}trÆtd| ƒ | 
¡  q²W qrW dS )a  
        Called just before the task is executed.

        This is mainly intended to give the target Nodes a chance to
        unlink underlying files and make all necessary directories before
        the Action is actually called to build the targets.
        zTask.prepare()Nr   zPreparing target %s...z...with side-effect %s...z...Preparing side-effect %s...)r$   ÚtraceÚwriter,   r'   Úexception_raiser-   r.   r%   Úget_executorÚprepareÚget_action_targetsÚprint_preparer   r   )r   ÚTÚexecutorÚtÚsr   r   r   r3   ˜   s*    	 zTask.preparec             C   s   | j S )z>Fetch the target being built or updated by this task.
        )r'   )r   r   r   r   Ú
get_targetÆ   s    zTask.get_targetc             C   s   d S )Nr   )r   r   r   r   Úneeds_executeË   s    zTask.needs_executec          
   C   sv  | j j}|r | |  d| j¡¡ yžg }x"| jD ]}| ¡ s<P | |¡ q.W t|ƒt| jƒk r¨x:|D ]2}y|j	 
| ¡ ¡ W qb ttfk
r’   Y qbX qbW | jd  ¡  nx|D ]
}d|_q®W W n² tk
rô   t ¡ d }tj | jd |j¡‚Y n~ tjjk
r   ‚ Y nd tjjk
r(   ‚ Y nJ tk
rp } z*tj |¡}| jd |_t ¡ |_|‚W dd}~X Y nX dS )zè
        Called to execute the task.

        This method is called from multiple threads in a parallel build,
        so only do thread safe stuff here.  Do thread unsafe stuff in
        prepare(), executed() or failed().
        zTask.execute()r   é   N)r$   r/   r0   r,   r'   r%   Zretrieve_from_cacheÚappendÚlenZfsÚunlinkZget_internal_pathÚIOErrorÚOSErrorr   ÚcachedÚ
SystemExitÚsysÚexc_infoÚSConsÚErrorsÚExplicitExitÚcodeÚ	UserErrorÚ
BuildErrorÚ	ExceptionZconvert_to_BuildError)r   r6   Zcached_targetsr8   Ú	exc_valueÚeZ
buildErrorr   r   r   ÚexecuteÏ   s<     



zTask.executec             C   sd   | j j}|r | |  d| j¡¡ x>| jD ]4}| ¡ tkr(x|jD ]}| 	t
¡ q@W | 	t¡ q(W dS )z£
        Called when the task has been successfully executed
        and the Taskmaster instance doesn't want to call
        the Node's callback methods.
        z!Task.executed_without_callbacks()N)r$   r/   r0   r,   r'   r%   Ú	get_stateÚNODE_EXECUTINGr   Ú	set_stateÚNODE_NO_STATEÚNODE_EXECUTED)r   r6   r8   Úside_effectr   r   r   Úexecuted_without_callbacksü   s     

zTask.executed_without_callbacksc             C   sª   | j j}|r | |  d| j¡¡ x„| jD ]z}| ¡ tkršx|jD ]}| 	t
¡ q@W | 	t¡ |jsj| ¡  | ¡  | ¡  ts¢t| dƒr| jjs¢| ¡  q(| ¡  q(W dS )aL  
        Called when the task has been successfully executed and
        the Taskmaster instance wants to call the Node's callback
        methods.

        This may have been a do-nothing operation (to preserve build
        order), so we must check the node's state before deciding whether
        it was "built", in which case we call the appropriate Node method.
        In any event, we always call "visited()", which will handle any
        post-visit actions that must take place regardless of whether
        or not the target was an actual built target or a source Node.
        zTask.executed_with_callbacks()ÚoptionsN)r$   r/   r0   r,   r'   r%   rP   rQ   r   rR   rS   rT   rB   Zpush_to_cacheZbuiltÚvisitedr5   ÚhasattrrW   Údebug_includesÚrelease_target_info)r   r6   r8   rU   r   r   r   Úexecuted_with_callbacks  s"     



zTask.executed_with_callbacksc             C   s   |   ¡  dS )zô
        Default action when a task fails:  stop the build.

        Note: Although this function is normally invoked on nodes in
        the executing state, it might also be invoked on up-to-date
        nodes when using Configure().
        N)Ú	fail_stop)r   r   r   r   Úfailed/  s    zTask.failedc             C   sT   | j j}|r | |  d| j¡¡ | j  | jdd„ ¡ | j  ¡  | j jg| _d| _	dS )aI  
        Explicit stop-the-build failure.

        This sets failure status on the target nodes and all of
        their dependent parent nodes.

        Note: Although this function is normally invoked on nodes in
        the executing state, it might also be invoked on up-to-date
        nodes when using Configure().
        zTask.failed_stop()c             S   s
   |   t¡S )N)rR   ÚNODE_FAILED)r!   r   r   r   r   I  r   z Task.fail_stop.<locals>.<lambda>r<   N)
r$   r/   r0   r,   r'   Úwill_not_buildr%   ÚstopÚcurrent_topr&   )r   r6   r   r   r   r]   9  s     
zTask.fail_stopc             C   s8   | j j}|r | |  d| j¡¡ | j  | jdd„ ¡ dS )aM  
        Explicit continue-the-build failure.

        This sets failure status on the target nodes and all of
        their dependent parent nodes.

        Note: Although this function is normally invoked on nodes in
        the executing state, it might also be invoked on up-to-date
        nodes when using Configure().
        zTask.failed_continue()c             S   s
   |   t¡S )N)rR   r_   )r!   r   r   r   r   b  r   z$Task.fail_continue.<locals>.<lambda>N)r$   r/   r0   r,   r'   r`   r%   )r   r6   r   r   r   Úfail_continueT  s     zTask.fail_continuec             C   sp   | j j}|r | |  d| j¡¡ | jdd… | _x:| jD ]0}| ¡  t	¡ x|j
D ]}| ¡  t	¡ qRW q8W dS )zÍ
        Marks all targets in a task ready for execution.

        This is used when the interface needs every target Node to be
        visited--the canonical example being the "scons -c" option.
        zTask.make_ready_all()N)r$   r/   r0   r,   r'   r%   Úout_of_dateÚdisambiguaterR   rQ   r   )r   r6   r8   r9   r   r   r   Úmake_ready_alld  s     zTask.make_ready_allc             C   s6  | j j}|r | |  d| j¡¡ g | _d}x†| jD ]|}y*| ¡  ¡  | 	¡  p\|j
 o\| ¡ }W n8 tk
r˜ } ztjj||j|jd‚W dd}~X Y nX |s2| j |¡ d}q2W |rðxz| jD ],}| t¡ x|jD ]}| ¡  t¡ qÔW q¾W nBx@| jD ]6}| ¡  | t¡ tsøt| dƒr&| jjsø| ¡  qøW dS )z±
        Marks all targets in a task ready for execution if any target
        is not current.

        This is the default behavior for building only what's necessary.
        zTask.make_ready_current()F)r'   ZerrstrÚfilenameNTrW   )r$   r/   r0   r,   r'   rd   r%   re   Ú
make_readyZhas_builderZalways_buildÚis_up_to_dateÚEnvironmentErrorrF   rG   rK   Ústrerrorrg   r=   rR   rQ   r   rX   ÚNODE_UP_TO_DATEr5   rY   rW   rZ   r[   )r   r6   Zneeds_executingr8   ri   rN   r9   r   r   r   Úmake_ready_currentu  s6     


(

zTask.make_ready_currentc       	      C   sÂ  | j j}|r | |  d| j¡¡ t| jƒ}| j j}i }x`|D ]X}|jrh|r^| |  d|d¡¡ | 	|¡ x"|jD ]}| 
|d¡d ||< qpW tƒ |_q<W x´|D ]¬}|jdk	ržxœ|jD ]’}| ¡ tkrÎ| t¡ | ¡ tkr|jr| 	|¡ x"|jD ]}| 
|d¡d ||< qöW tƒ |_x*|jD ] }|jdkr"| j j |¡ q"W q´W qžW xV| ¡ D ]J\}}|j| |_|r†| |  d|d¡¡ |jdkrX| j j |¡ qXW x|D ]}| ¡  q¬W dS )a  
        Post-processes a task after it's been executed.

        This examines all the targets just built (or not, we don't care
        if the build was successful, or even if there was no build
        because everything was up-to-date) to see if they have any
        waiting parent Nodes, or Nodes waiting on a common side effect,
        that can be put back on the candidates list.
        zTask.postprocess()Zremovingr   r<   Nzadjusted parent ref count)r$   r/   r0   r,   r'   Úsetr%   Úpending_childrenÚwaiting_parentsÚdiscardÚgetr   rP   rQ   rR   rS   Zwaiting_s_eÚ	ref_countÚ
candidatesr=   ÚitemsÚpostprocess)	r   r6   r%   ro   Úparentsr8   Úpr9   Úsubtractr   r   r   rv   £  sN    
 	

 





 

zTask.postprocessc             C   s   | j S )z:
        Returns info about a recorded exception.
        )Ú	exception)r   r   r   r   rE   î  s    zTask.exc_infoc             C   s   d| _ | j| _dS )z¢
        Clears any recorded exception.

        This also changes the "exception_raise" attribute to point
        to the appropriate do-nothing method.
        )NNNN)rz   Ú_no_exception_to_raiser1   )r   r   r   r   r(   ô  s    zTask.exc_clearNc             C   s   |st  ¡ }|| _| j| _dS )z¹
        Records an exception to be raised at the appropriate time.

        This also changes the "exception_raise" attribute to point
        to the method that will, in fact
        N)rD   rE   rz   Ú_exception_raiser1   )r   rz   r   r   r   Úexception_setþ  s    zTask.exception_setc             C   s   d S )Nr   )r   r   r   r   r{   
  s    zTask._no_exception_to_raisec             C   sh   |   ¡ dd… }y|\}}}W n  tk
r>   |\}}d}Y nX t|tƒrV| |¡‚n||ƒ |¡‚dS )zp
        Raises a pending exception that was recorded while getting a
        Task ready for execution.
        N)rE   Ú
ValueErrorÚ
isinstancerL   Úwith_traceback)r   ÚexcÚexc_typerM   Úexc_tracebackr   r   r   r|     s    

zTask._exception_raise)r'   )N)r   r   r   r   r   r,   r.   r3   r:   r   r;   rO   rV   r\   Úexecutedr^   r]   rc   rf   rm   rh   rv   rE   r(   r}   r{   r|   r   r   r   r   r#   n   s.   
.-!
,K

r#   c               @   s   e Zd Zdd„ ZdS )Ú
AlwaysTaskc             C   s   dS )a›  
        Always returns True (indicating this Task should always
        be executed).

        Subclasses that need this behavior (as opposed to the default
        of only executing Nodes that are out of date w.r.t. their
        dependencies) can use this as follows:

            class MyTaskSubclass(SCons.Taskmaster.Task):
                needs_execute = SCons.Taskmaster.AlwaysTask.needs_execute
        Tr   )r   r   r   r   r;   (  s    zAlwaysTask.needs_executeN)r   r   r   r;   r   r   r   r   r…   '  s   r…   c               @   s   e Zd Zdd„ ZdS )ÚOutOfDateTaskc             C   s   | j d  ¡ tjjkS )zÔ
        Returns True (indicating this Task should be executed) if this
        Task's target state indicates it needs executing, which has
        already been determined by an earlier up-to-date check.
        r   )r%   rP   rF   ÚNodeÚ	executing)r   r   r   r   r;   7  s    zOutOfDateTask.needs_executeN)r   r   r   r;   r   r   r   r   r†   6  s   r†   c             C   sj   | d |krd S |  | d ¡ xF| d jD ]8}|  |¡ | d | d krL| S t| |ƒrZ| S |  ¡  q*W d S )Néÿÿÿÿr   )Úaddrp   r=   Ú
find_cycleÚpop)ÚstackrX   r!   r   r   r   r‹   @  s    

r‹   c               @   sz   e Zd ZdZg ddd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„ fdd„Zdd„ Zdd„ ZdS )Ú
Taskmasterz8
    The Taskmaster for walking the dependency DAG.
    Nc             C   sh   || _ |d d … | _| j ¡  g | _|d kr0t}|| _|sBdd„ }|| _d | _|| _| j	| _
tƒ | _d S )Nc             S   s   | S )Nr   )Úlr   r   r   r   \  r   z%Taskmaster.__init__.<locals>.<lambda>)Úoriginal_topÚtop_targets_leftÚreversert   r†   ÚtaskerÚorderr-   r/   Úfind_next_candidateÚnext_candidatern   ro   )r   r%   r“   r”   r/   r   r   r   r   S  s    
zTaskmaster.__init__c             C   sŒ   y
| j  ¡ S  tk
r   Y nX y| j ¡ }W n tk
rB   dS X || _| ¡ \}}|rˆ|| _| j  |¡ | j  |  	|¡¡ | j  ¡ }|S )aÍ  
        Returns the next candidate Node for (potential) evaluation.

        The candidate list (really a stack) initially consists of all of
        the top-level (command line) targets provided when the Taskmaster
        was initialized.  While we walk the DAG, visiting Nodes, all the
        children that haven't finished processing get pushed on to the
        candidate list.  Each child can then be popped and examined in
        turn for whether *their* children are all up-to-date, in which
        case a Task will be created for their actual evaluation and
        potential building.

        Here is where we also allow candidate Nodes to alter the list of
        Nodes that should be examined.  This is used, for example, when
        invoking SCons in a source directory.  A source directory Node can
        return its corresponding build directory Node, essentially saying,
        "Hey, you really need to build this thing over here instead."
        N)
rt   rŒ   Ú
IndexErrorr‘   rb   Zalter_targetsr-   r=   Úextendr”   )r   r'   Zaltr-   r   r   r   r•   c  s     

zTaskmaster.find_next_candidatec             C   s&   x | j r | j }g | _ |  |¡ qW dS )zü
        Stops Taskmaster processing by not returning a next candidate.

        Note that we have to clean-up the Taskmaster candidate list
        because the cycle detection depends on the fact all nodes have
        been processed somehow.
        N)rt   r`   )r   rt   r   r   r   Úno_next_candidate‡  s
    zTaskmaster.no_next_candidatec             C   sŽ   xˆ| j D ]~}|jttfks0tt|ƒt|j fƒ‚t|jƒdksTtt|ƒt|jƒfƒ‚x0|jD ]&}|j	dks\tt|ƒt|ƒ|j	fƒ‚q\W qW dS )aÜ  
        Validate the content of the pending_children set. Assert if an
        internal error is found.

        This function is used strictly for debugging the taskmaster by
        checking that no invariants are violated. It is not used in
        normal operation.

        The pending_children set is used to detect cycles in the
        dependency graph. We call a "pending child" a child that is
        found in the "pending" state when checking the dependencies of
        its parent node.

        A pending child can occur when the Taskmaster completes a loop
        through a cycle. For example, let's imagine a graph made of
        three nodes (A, B and C) making a cycle. The evaluation starts
        at node A. The Taskmaster first considers whether node A's
        child B is up-to-date. Then, recursively, node B needs to
        check whether node C is up-to-date. This leaves us with a
        dependency graph looking like::

                                          Next candidate                                                                       Node A (Pending) --> Node B(Pending) --> Node C (NoState)
                    ^                                     |
                    |                                     |
                    +-------------------------------------+

        Now, when the Taskmaster examines the Node C's child Node A,
        it finds that Node A is in the "pending" state. Therefore,
        Node A is a pending child of node C.

        Pending children indicate that the Taskmaster has potentially
        loop back through a cycle. We say potentially because it could
        also occur when a DAG is evaluated in parallel. For example,
        consider the following graph::

            Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ...
                    |                                     ^
                    |                                     |
                    +----------> Node D (NoState) --------+
                                      /
                      Next candidate /

        The Taskmaster first evaluates the nodes A, B, and C and
        starts building some children of node C. Assuming, that the
        maximum parallel level has not been reached, the Taskmaster
        will examine Node D. It will find that Node C is a pending
        child of Node D.

        In summary, evaluating a graph with a cycle will always
        involve a pending child at one point. A pending child might
        indicate either a cycle or a diamond-shaped DAG. Only a
        fraction of the nodes ends-up being a "pending child" of
        another node. This keeps the pending_children set small in
        practice.

        We can differentiate between the two cases if we wait until
        the end of the build. At this point, all the pending children
        nodes due to a diamond-shaped DAG will have been properly
        built (or will have failed to build). But, the pending
        children involved in a cycle will still be in the pending
        state.

        The taskmaster removes nodes from the pending_children set as
        soon as a pending_children node moves out of the pending
        state. This also helps to keep the pending_children set small.
        r   N)
ro   ÚstateÚNODE_PENDINGrQ   ÚAssertionErrorr   ÚStateStringr>   rp   rs   )r   r!   rx   r   r   r   Ú_validate_pending_children•  s    F$z%Taskmaster._validate_pending_childrenc             C   s   d| S )NzTaskmaster: %s
r   )r   r-   r   r   r   r,   ã  s    zTaskmaster.trace_messagec             C   s    dt | ¡  |jtt|ƒƒf S )Nz<%-10s %-3s %s>)r   rP   rs   Úreprr   )r   r'   r   r   r   r*   æ  s    zTaskmaster.trace_nodec          
   C   s  d| _ | j}|r$| d|  d¡ ¡ xì|  ¡ }|dkrT|rP| |  d¡d ¡ dS | ¡ }| ¡ }tržt|j	dƒsˆt
ƒ |j	_t |¡ |j	j}|jd |_nd}|rÀ| |  d|  |¡ ¡¡ |tkrÔ| t¡ n0|tkr|rî|jd |_|r(| |  d¡¡ q(| ¡ }y| ¡ }W n® tk
rn   t ¡ d }tj ||j¡}tjj|f| _ |rj| |  d	¡¡ |S  tk
rÆ } z:t ¡ | _ |rœ|jd |_|r¶| |  d
| ¡¡ |S d}~X Y nX g }	tƒ }
g }d}xŽt | !¡ |ƒD ]|}| ¡ }|r| |  d|  |¡ ¡¡ |tkr,|	 |¡ n$|tkrB|
 "|¡ n|t#krPd}|t$krê| |¡ qêW |	r˜t%|	ƒdkr†|	 &¡  | j' (|  )|	¡¡ |rîx| *¡ D ]}| t#¡ q¨W |rÎ|j+d |_+|r(| |  d|  |¡ ¡¡ q(|r’x^|D ]V}|r|j,d |_,|j-| .|¡ |_-|rú| |  d|  |¡t/t0|ƒƒf ¡¡ qúW |r„x(|
D ] }| |  d|  |¡ ¡¡ q`W | j1|
B | _1q(d}x.| 2¡ D ]"}| ¡ t$kr | 3|¡ d}q W |rÞ|r(|j4d |_4q(|rð|j5d |_5|r| |  d|  |¡ ¡¡ |S dS )aO  
        Finds the next node that is ready to be built.

        This is *the* main guts of the DAG walk.  We loop through the
        list of candidates, looking for something that has no un-built
        children (i.e., that is a leaf Node or has dependencies that are
        all leaf Nodes or up-to-date).  Candidate Nodes are re-scanned
        (both the target Node itself and its sources, which are always
        scanned in the context of a given target) to discover implicit
        dependencies.  A Node that must wait for some children to be
        built will be put back on the candidates list after the children
        have finished building.  A Node that has been put back on the
        candidates list in this way may have itself (or its sources)
        re-scanned, in order to handle generated header files (e.g.) and
        the implicit dependencies therein.

        Note that this method does not do any signature calculation or
        up-to-date check itself.  All of that is handled by the Task
        class.  This is purely concerned with the dependency graph walk.
        NÚ
zLooking for a node to evaluatezNo candidate anymore.r   r<   z)    Considering node %s and its children:z!       already handled (executed)z       SystemExitz-       exception %s while scanning children.
Fz       Tz
****** %s
z%     adjusted ref count: %s, child %sz-       adding %s to the pending children set
zEvaluating %s
)6Ú	ready_excr/   r0   r,   r–   re   rP   ÚCollectStatsrY   r   r   r   r   r=   r   r*   rS   rR   r›   r   r2   Zget_all_childrenrC   rD   rE   rF   rG   rH   rI   rL   r   rn   r   Zget_all_prerequisitesrŠ   r_   rQ   r>   r’   rt   r˜   r”   r4   r	   r
   rs   Zadd_to_waiting_parentsrŸ   r   ro   Zget_action_side_effectsZadd_to_waiting_s_er   r   )r   r6   r'   rš   ÚSr7   ZchildrenrM   rN   Zchildren_not_visitedZchildren_pendingZchildren_not_readyZchildren_failedZchildZ
childstater!   ZpcZwait_side_effectsZser   r   r   Ú_find_next_ready_nodeë  sÐ      


 
   
   



  
  
"



   

z Taskmaster._find_next_ready_nodec          
   C   sœ   |   ¡ }|dkrdS | ¡ }|dkr(dS | ¡ }|  | ||| jk|¡}y| ¡  W n, tk
r~ } zt ¡ | _	W dd}~X Y nX | j	r’| 
| j	¡ d| _	|S )zÌ
        Returns the next task to be executed.

        This simply asks for the next Node to be evaluated, and then wraps
        it in the specific Task subclass with which we were initialized.
        N)r¤   r2   Zget_all_targetsr“   r   rh   rL   rD   rE   r¡   r}   )r   r'   r7   ZtlistZtaskrN   r   r   r   Ú	next_task­  s     zTaskmaster.next_taskc             C   s   d S )Nr   )r!   r   r   r   r   Ð  r   zTaskmaster.<lambda>c       
   	   C   sà   | j }| j}t|ƒ}|| }|rHx&|D ]}| |  d|  |¡ ¡¡ q&W yxxrt|ƒr¼| ¡ }||ƒ |j}tƒ |_||B }|| }x6|D ].}	|	j	d |	_	|rˆ| |  d|  |	¡ ¡¡ qˆW qLW W n t
k
rÔ   Y nX || _dS )z°
        Perform clean-up about nodes that will never be built. Invokes
        a user defined function on all of these nodes (including all
        of their parents).
        z6       removing node %s from the pending children set
r<   z8       removing parent %s from the pending children set
N)r/   ro   rn   r0   r,   r*   r>   rŒ   rp   rs   ÚKeyError)
r   ZnodesZ	node_funcr6   ro   Zto_visitr!   r'   rw   rx   r   r   r   r`   Ð  s0    



 
zTaskmaster.will_not_buildc             C   s   | j | _dS )z5
        Stops the current build completely.
        N)r™   r–   )r   r   r   r   ra   ü  s    zTaskmaster.stopc             C   s–   | j s
dS dd„ | j D ƒ}dd„ |D ƒ}|s0dS d}xP|D ]H\}}|rd|d d tt|ƒ¡ d }q:|d	|t|ƒt| ¡  f  }q:W tj 	|¡‚dS )
z.
        Check for dependency cycles.
        Nc             S   s   g | ]}|t |gtƒ ƒf‘qS r   )r‹   rn   )Ú.0r!   r   r   r   ú
<listcomp>	  s    z&Taskmaster.cleanup.<locals>.<listcomp>c             S   s$   g | ]\}}|s|  ¡ tkr|‘qS r   )rP   rT   )r§   r'   Úcycler   r   r   r¨     s    zFound dependency cycle(s):
z  z -> r    z>  Internal Error: no cycle found for node %s (%s) in state %s
)
ro   ÚjoinÚmapr   rŸ   r   rP   rF   rG   rJ   )r   ZnclistZgenuine_cyclesZdescr'   r©   r   r   r   Úcleanup  s    zTaskmaster.cleanup)r   r   r   r   r   r•   r™   rž   r,   r*   r¤   r¥   r`   ra   r¬   r   r   r   r   rŽ   N  s   $N C#,rŽ   )$r   rD   Úabcr   r   Ú	itertoolsr   ZSCons.ErrorsrF   Z
SCons.NodeZSCons.Warningsr‡   r   Zno_staterS   Úpendingr›   rˆ   rQ   Z
up_to_daterl   r„   rT   r^   r_   r5   r¢   r   r   r   r"   r#   r…   r†   r‹   rŽ   r   r   r   r   Ú<module>0   s6      <
