B
    '\y9                 @   s   d dl mZmZmZmZ d dlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ dd	lmZmZmZmZ dd
lmZ eeZG dd deZdS )    )absolute_importdivisionprint_functionunicode_literals)	getLogger   )
NoarchType)	MatchSpec   )
IndexedSet)context)	iteritems
itervaluesodicton_win)CyclicalDependencyErrorc               @   s   e Zd ZdZd ddZdd Zdd Zed	d
 Zdd Z	dd Z
dd Zdd Zdd Zdd Zedd Zedd Zedd Zedd ZdS )!PrefixGraphaR  
    A directed graph structure used for sorting packages (prefix_records) in prefixes and
    manipulating packages within prefixes (e.g. removing and pruning).

    The terminology used for edge direction is "parents" and "children" rather than "successors"
    and "predecessors". The parent nodes of a record are those records in the graph that
    match the record's "depends" field.  E.g. NodeA depends on NodeB, then NodeA is a child
    of NodeB, and NodeB is a parent of NodeA.  Nodes can have zero parents, or more than two
    parents.

    Most public methods mutate the graph.
     c                s   t |}t|}i }i  | _}x`|D ]X t dd  jD tfdd|D }|| < t fdd|D }|r$|| < q$W || _|   d S )Nc             s   s   | ]}t |V  qd S )N)r	   ).0dr   r   8lib/python3.7/site-packages/conda/models/prefix_graph.py	<genexpr>&   s    z'PrefixGraph.__init__.<locals>.<genexpr>c             3   s(   | ]  t  fd dD r V  qdS )c             3   s   | ]}|  V  qd S )N)match)r   m)recr   r   r   (   s    z1PrefixGraph.__init__.<locals>.<genexpr>.<genexpr>N)any)r   )parent_match_specs)r   r   r   (   s    c             3   s   | ]}|  r|V  qd S )N)r   )r   s)noder   r   r   +   s    )tuplesetspec_matchesZdependsr   graph	_toposort)selfrecordsZspecsr"   r!   Zparent_nodesZmatching_specsr   )r   r   r   __init__    s    

zPrefixGraph.__init__c                s   t fdd| jD }x:dp&dD ](}t|d | fdd| jD  q(W t  x&|D ]}| | | q`W ttfdd| jxD ]}| 	| qW | 
  tS )	z
        Remove all matching nodes, and any associated child nodes.

        Args:
            spec (MatchSpec):

        Returns:
            Tuple[PrefixRecord]: The removed nodes.

        c             3   s   | ]}  |r|V  qd S )N)r   )r   r   )specr   r   r   <   s    z*PrefixGraph.remove_spec.<locals>.<genexpr>Ztrack_featuresr   )Zfeaturesc             3   s   | ]}  |r|V  qd S )N)r   )r   r   )feature_specr   r   r   B   s    c                s   |  kS )Nr   )r   )remove_theser   r   <lambda>I       z)PrefixGraph.remove_spec.<locals>.<lambda>)r    r"   Zget_raw_valuer	   updateaddall_descendantsr   filter_remove_noder#   )r$   r'   Znode_matchesZfeature_namer   r   )r(   r)   r'   r   remove_spec1   s    





zPrefixGraph.remove_specc                st   | j  | j fdd D }tfddt|D ttfdd| j }x|D ]}| | qVW |   |S )z
        A specialized method used to determine only dependencies of requested specs.

        Returns:
            Tuple[PrefixRecord]: The removed nodes.

        c                s&   i | ] t  fd dD  qS )c             3   s   | ]} | kr|V  qd S )Nr   )r   key)r"   r   r   r   r   \   s    zUPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<dictcomp>.<genexpr>)r    )r   )r"   )r   r   
<dictcomp>[   s   zKPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<dictcomp>c             3   s"   | ]\}}|s| kr|V  qd S )Nr   )r   r   children)r!   r   r   r   _   s    zJPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<genexpr>c                s   |  kS )Nr   )r   )youngest_nodes_with_specsr   r   r*   b   r+   zIPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<lambda>)r"   r!   r   r   r/   r0   r#   )r$   inverted_graphremoved_nodesr   r   )r"   r!   r5   r   +remove_youngest_descendant_nodes_with_specsQ   s    



z7PrefixGraph.remove_youngest_descendant_nodes_with_specsc             C   s
   t | jS )N)iterr"   )r$   r   r   r   r%   j   s    zPrefixGraph.recordsc                s   | j  | jt| j }t xX fdd D }tfddt|D }|sPP x |D ]}| | | qVW qW ttfdd||   S )zPrune back all packages until all child nodes are anchored by a spec.

        Returns:
            Tuple[PrefixRecord]: The pruned nodes.

        c                s&   i | ] t  fd dD  qS )c             3   s   | ]} | kr|V  qd S )Nr   )r   r2   )r"   r   r   r   r   |   s    z/PrefixGraph.prune.<locals>.<dictcomp>.<genexpr>)r    )r   )r"   )r   r   r3   {   s   z%PrefixGraph.prune.<locals>.<dictcomp>c             3   s"   | ]\}}|s| kr|V  qd S )Nr   )r   r   r4   )r!   r   r   r      s    z$PrefixGraph.prune.<locals>.<genexpr>c                s   |  kS )Nr   )r   )r7   r   r   r*      r+   z#PrefixGraph.prune.<locals>.<lambda>)	r"   r!   r   r    r   r-   r0   r/   r#   )r$   Zoriginal_orderr6   Zprunable_nodesr   r   )r"   r7   r!   r   prunen   s$    




zPrefixGraph.prunec                s   t  fdd| jD S )Nc             3   s   | ]}|j  kr|V  qd S )N)name)r   r   )r;   r   r   r      s    z/PrefixGraph.get_node_by_name.<locals>.<genexpr>)nextr"   )r$   r;   r   )r;   r   get_node_by_name   s    zPrefixGraph.get_node_by_namec                s   | j   fdd D }|g}t d}xJ|t|k rrx0|||  D ] }|krD| || qDW |d7 }q*W ttfdd S )Nc                s&   i | ] t  fd dD  qS )c             3   s   | ]} | kr|V  qd S )Nr   )r   r2   )r"   r   r   r   r      s    z9PrefixGraph.all_descendants.<locals>.<dictcomp>.<genexpr>)r    )r   )r"   )r   r   r3      s   z/PrefixGraph.all_descendants.<locals>.<dictcomp>r   r   c                s   |  kS )Nr   )r   )
nodes_seenr   r   r*      r+   z-PrefixGraph.all_descendants.<locals>.<lambda>)r"   r    lenr-   appendr   r/   )r$   r   r6   nodesqZ
child_noder   )r"   r>   r   r.      s     


zPrefixGraph.all_descendantsc                sx   | j }|g}t  d}xJ|t|k r`x0|||  D ] }| kr2 | || q2W |d7 }qW tt fdd|S )Nr   r   c                s   |  kS )Nr   )r   )r>   r   r   r*      r+   z+PrefixGraph.all_ancestors.<locals>.<lambda>)r"   r    r?   r-   r@   r   r/   )r$   r   r"   rA   rB   Zparent_noder   )r>   r   all_ancestors   s    

zPrefixGraph.all_ancestorsc             C   s^   | j }||krtd| || | j|d x&t|D ]\}}||kr<|| q<W dS )z1 Removes this node and all edges referencing it. znode %s does not existN)r"   KeyErrorpopr!   r   remove)r$   r   r"   Zedgesr   r   r   r0      s    
zPrefixGraph._remove_nodec                sh   t dd t| jD }| | tjr8t| |}nt| |}| j t  fdd|D | _|S )Nc             s   s   | ]\}}|t |fV  qd S )N)r   )r   r   parentsr   r   r   r      s    z(PrefixGraph._toposort.<locals>.<genexpr>c             3   s   | ]}| | fV  qd S )Nr   )r   r   )original_graphr   r   r      s    )	r   r   r"   _toposort_prepare_graphr   Zallow_cyclesr   _topo_sort_handle_cycles_toposort_raise_on_cycles)r$   Z
graph_copyZsorted_nodesr   )rH   r   r#      s    
zPrefixGraph._toposortc             c   s   |sd S xft tdd t|D dd d}|s2P x|D ]}|V  ||d  q8W xt|D ]}||8 }q\W q
W t|dkrtt|d S )Nc             s   s"   | ]\}}t |d kr|V  qdS )r   N)r?   )r   r   rG   r   r   r   r      s    z8PrefixGraph._toposort_raise_on_cycles.<locals>.<genexpr>c             S   s   | j S )N)r;   )xr   r   r   r*      r+   z7PrefixGraph._toposort_raise_on_cycles.<locals>.<lambda>)r2   r   )r   sortedr   rE   r   r?   r   r   )clsr"   Zno_parent_nodesr   rG   r   r   r   rK      s    
z%PrefixGraph._toposort_raise_on_cyclesc       
   
   #   s   xt  D ]\}}|| q
W tdd t D  fdd D }tfdd|D dd d}x|D ]
}|V  qlW |  }xpyt|}|V  W q tk
r }	 z(t	d|	 | 
 V  |  }wW d d }	~	X Y q tk
r   d S X qW d S )	Nc             s   s   | ]}|D ]
}|V  q
qd S )Nr   )r   rG   r   r   r   r   r      s    z7PrefixGraph._topo_sort_handle_cycles.<locals>.<genexpr>c             3   s   | ]} | s|V  qd S )Nr   )r   r   )r"   r   r   r      s    c             3   s   | ]}| kr|V  qd S )Nr   )r   r   )nodes_that_are_parentsr   r   r      s    c             S   s   | j S )N)r;   )rL   r   r   r   r*      r+   z6PrefixGraph._topo_sort_handle_cycles.<locals>.<lambda>)r2   z%r)r   discardr    r   rM   rK   r<   r   logdebug_toposort_pop_keyStopIteration)
rN   r"   kvZnodes_without_parentsZdisconnected_nodesr   tvalueer   )r"   rO   r   rJ      s*    




z$PrefixGraph._topo_sort_handle_cyclesc             C   sH   t dd t| D d d }| | xt| D ]}|| q2W |S )z
        Pop an item from the graph that has the fewest parents.
        In the case of a tie, use the node with the alphabetically-first package name.
        c             s   s"   | ]\}}t ||j|fV  qd S )N)r?   r;   )r   r   rG   r   r   r   r     s    z0PrefixGraph._toposort_pop_key.<locals>.<genexpr>r   r
   )rM   r   rE   r   rP   )r"   Znode_with_fewest_parentsrG   r   r   r   rS     s    

zPrefixGraph._toposort_pop_keyc       	      C   s   xD| D ]<}|j dkr| | }x$t|D ]}|j dkr&|| q&W qW trtdd | D d }tdd | D d }|r|d k	st| | }x.t| D ]"\}}||kr||kr|| qW tdd | D d }|r| | }x<t| D ]0\}}t|dr|j	t
jkr||kr|| qW d S )NpythonZpipc             s   s   | ]}|j d kr|V  qdS )ZmenuinstN)r;   )r   r   r   r   r   r   ,  s    z6PrefixGraph._toposort_prepare_graph.<locals>.<genexpr>c             s   s   | ]}|j d kr|V  qdS )rZ   N)r;   )r   r   r   r   r   r   -  s    c             s   s   | ]}|j d kr|V  qdS )ZcondaN)r;   )r   r   r   r   r   r   <  s    noarch)r;   r   rF   r   r<   AssertionErrorr   r-   hasattrr[   r   rZ   )	r"   r   rG   parentZmenuinst_nodeZpython_nodeZmenuinst_parentsZ
conda_nodeZconda_parentsr   r   r   rI     s,    


z#PrefixGraph._toposort_prepare_graphN)r   )__name__
__module____qualname____doc__r&   r1   r8   propertyr%   r:   r=   r.   rC   r0   r#   classmethodrK   rJ   staticmethodrS   rI   r   r   r   r   r      s   
  #r   N)Z
__future__r   r   r   r   Zloggingr   Zenumsr   Z
match_specr	   Z_vendor.boltons.setutilsr   Zbase.contextr   Zcommon.compatr   r   r   r   
exceptionsr   r_   rQ   objectr   r   r   r   r   <module>   s   