U
    ee0                     @   s   d dl mZ d dlmZ d dlmZ d dlmZ d dlm	Z	 d dl
mZ dd ZG d	d
 d
eZdddZdddZdd ZdddZdddZdS )    )deepcopy)product)info)Recipe)	Bootstrap)BuildInterruptingExceptionc                 C   s   dd | D } | S )z Turn a dependency list into lowercase, and make sure all entries
        that are just a string become a tuple of strings
    c                 S   s6   g | ].}t |ttfs | fntd d |D qS )c                 S   s   g | ]}|  qS  lower).0Z	dep_entryr   r   :/tmp/pip-unpacked-wheel-h4dze4ss/pythonforandroid/graph.py
<listcomp>   s   z*fix_deplist.<locals>.<listcomp>.<listcomp>)
isinstancelisttupler
   r   depr   r   r   r      s   zfix_deplist.<locals>.<listcomp>r   )depsr   r   r   fix_deplist
   s    r   c                   @   s   e Zd Zdd Zdd ZdS )RecipeOrderc                 C   s
   || _ d S N)ctx)selfr   r   r   r   __init__   s    zRecipeOrder.__init__c              	      sj      D ]\}z"t| j}dd |jD }W n tk
rF   g }Y nX t fdd|D r dS qdS )Nc                 S   s   g | ]}|  qS r   r	   r   r   r   r   r   !   s     z)RecipeOrder.conflicts.<locals>.<listcomp>c                    s   g | ]}| kqS r   r   r   cr   r   r   r   %   s     TF)keysr   
get_reciper   	conflicts
ValueErrorany)r   namereciper   r   r   r   r      s    
zRecipeOrder.conflictsN)__name__
__module____qualname__r   r   r   r   r   r   r      s   r   Nc                    sN    dkrt   t t kst| jdkr.g }nt| j} fdd|D }|S )zu Get the dependencies of a recipe with filtered out blacklist, and
        turned into tuples with fix_deplist()
    Nc                    s,   g | ]$}t t|  rt t|  qS r   )r   set)r   Zdeptuple	blacklistr   r   r   8   s   z8get_dependency_tuple_list_for_recipe.<locals>.<listcomp>)r'   typeAssertionErrordependsr   )r#   r)   dependenciesr   r(   r   $get_dependency_tuple_list_for_recipe*   s    


r.   c              
      s:  |   } |dkrg } dkr"t  z^t| |}t| d}|t fdd||D  |jdkrng }ndd |jD }W n t	k
r   g }g }Y nX g }|D ]| kr|
t q rqtfdd|D rqt| D ]F}	t}
t|	|
| < |
g}|	D ]}t|||| d}q|| qq|S )zFor each possible recipe ordering, try to add the new recipe name
    to that order. Recursively do the same thing with all the
    dependencies of each recipe.

    Nr(   c                    s   g | ]}|   kr|gqS r   r	   )r   dr(   r   r   r   V   s    z.recursively_collect_orders.<locals>.<listcomp>c                 S   s   g | ]}|  qS r   r	   r   r   r   r   r   ]   s     c                    s   g | ]}| kqS r   r   )r   conflictorderr   r   r   l   s     )r
   r'   r   r   r.   extendr   Zget_opt_depends_in_listr   r    appendr   r!   r   recursively_collect_orders)r"   r   Z
all_inputsordersr)   r#   r-   r   Z
new_ordersZdependency_setZ	new_orderZdependency_new_orders
dependencyr   )r)   r2   r   r5   @   sV     

   
r5   c                 c   sf   | rbdd |   D }|s&td|  |  |D ],}|V  | | |  D ]}|| qNq2q dS )z=
    Do a topological sort on the dependency graph dict.
    c                 S   s   g | ]\}}|s|qS r   r   )r   r"   r   r   r   r   r      s      zfind_order.<locals>.<listcomp>zDependency cycle detected! %sN)itemsr    sortpopvaluesdiscard)graphleftmostresultZbsetr   r   r   
find_order   s    
r@   c              
      s  t  }t |dkrt }dd |D }t|dkrt|}g }|D ]\}}t|tks`tt|dkrx| qF|d t }g }	z,t	| }
dd |
j
D }t|
|d}	W n tk
r   Y nX |p҈ g }D ]}t||t|kr|| qt|dkrqzt	|d | }W n tk
rB   Y qY nX d	d |j
D }|kr|| q|rd
|d }||fd}|r|}td |
jf||d | |||< | fdd|	D 7 }qFq(dS )z This is a pre-flight check function that will completely ignore
        recipe order or choosing an actual value in any of the multiple
        choice tuples/dependencies, and just do a very basic obvious
        conflict check.
    Nc                 S   s   g | ]}|d fqS r   r   )r   Z
name_tupler   r   r   r      s     z,obvious_conflict_checker.<locals>.<listcomp>r      c                 S   s   h | ]}|  qS r   r	   r   r   r   r   	<setcomp>   s     z+obvious_conflict_checker.<locals>.<setcomp>r(   c                 S   s   g | ]}|  qS r   r	   r   r   r   r   r      s     z'||'z_Conflict detected: '{}' inducing dependencies {}, and '{}' inducing conflicting dependencies {}c                    s    g | ]}|kr| pfqS r   r   r   Zadder_first_recipe_namer   r"   r   r   r      s   )dictr'   lenr   r*   r   r+   addr   r   r   r.   r    intersectionr4   joingetr   formatr"   )r   Zname_tuplesr)   Zdeps_were_added_byZto_be_addedZcurrent_to_be_addedZadded_tupleZadding_recipeZrecipe_conflictsZrecipe_dependenciesr#   Ztriggered_conflictsZdep_tuple_listZ
dep_reciper   Zadder_second_recipe_nameZsecond_recipe_original_adderr   rC   r   obvious_conflict_checker   s    
 


 
rK   c              	      sT  t |}|d k	r&|jr&|t |j}tdd |D } d krFt   dd  D  t|}g }|D ](}t fdd|D }|rd|| qdt| | d g }t| D ]4}t	| g}	|D ]}t
|| ||	 d}	q||	 qg }
|D ]H}zt|}W n( tk
r   td| Y qY nX |
t| qt|
d	d
 d}
|
sNtd|
d }t|
dkrtd |
D ]}td| qptd| ntd| |d krt|| }|d krtdt| || d\}}}nZg }g }|D ]L}zt|| }||j7 }W n  tk
r.   || Y nX || qtt |}|||fS )Nc                 S   s$   g | ]}t |ttfs|gn|qS r   )r   r   r   )r   r"   r   r   r   r      s   z2get_recipe_order_and_bootstrap.<locals>.<listcomp>c                 S   s   h | ]}|  qS r   r	   )r   Zbitemr   r   r   rB      s     z1get_recipe_order_and_bootstrap.<locals>.<setcomp>c                    s   g | ]}| kr|qS r   r   )r   itemr(   r   r   r     s     r(   )r6   r)   z3Circular dependency found in graph {}, skipping it.c                 S   s   d| k d| k S )Npython3Zsdl2r   r1   r   r   r   <lambda>)      z0get_recipe_order_and_bootstrap.<locals>.<lambda>)keyztDidn't find any valid dependency graphs. This means that some of your requirements pull in conflicting dependencies.r   rA   z'Found multiple valid dependency orders:z    {}zUsing the first of these: {}z#Found a single valid recipe set: {}z(Could not find any compatible bootstrap!)bsr)   )r'   Zrecipe_dependsunionr   r   r   r4   rK   r   r   r5   r3   r@   r    r   rJ   sortedr   rE   r   Zget_bootstrap_from_recipesget_recipe_order_and_bootstrapr   r   Zpython_depends)r   namesrQ   r)   Znames_before_blacklistr"   Zcleaned_up_tupleZpossible_ordersZname_setZnew_possible_ordersr6   Zpossible_orderr2   Zchosen_orderZrecipesZpython_modulesr#   r   r(   r   rT      s    
   


   rT   )N)NN)N)NN)copyr   	itertoolsr   Zpythonforandroid.loggerr   Zpythonforandroid.reciper   Zpythonforandroid.bootstrapr   Zpythonforandroid.utilr   r   rD   r   r.   r5   r@   rK   rT   r   r   r   r   <module>   s   
   
?
a