U
    b
A                     @   s   d dl mZmZmZmZ d dl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 ddlmZ e	eZG dd deZG dd deZdS )    )absolute_importdivisionprint_functionunicode_literals)defaultdictOrderedDict)	getLogger   )
NoarchType	MatchSpec   
IndexedSet)context)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  | _}|D ]X t dd  jD tfdd|D }|| < t fdd|D }|r(|| < q(|   d S )Nc                 s   s   | ]}t |V  qd S Nr   .0dr   r   8lib/python3.8/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 r   match)r   mrecr   r   r   *   s     z1PrefixGraph.__init__.<locals>.<genexpr>.<genexpr>N)anyr   )parent_match_specsr   r   r   (   s   c                 3   s   | ]}|  r|V  qd S r   r   )r   snoder   r   r   -   s     
 )tuplesetgraphspec_matchesdependsr   	_toposort)selfrecordsspecsr)   r*   parent_nodesZmatching_specsr   )r&   r#   r   __init__!   s    


zPrefixGraph.__init__c                    s   t fdd| jD }dp$dD ](}t|d | fdd| jD  q&t  |D ]}| | | qZttfdd| jD ]}| 	| q| 
  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 r   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 r   r   r2   )feature_specr   r   r   D   s     
 c                    s   |  kS r   r   r%   )remove_theser   r   <lambda>K       z)PrefixGraph.remove_spec.<locals>.<lambda>)r(   r)   Zget_raw_valuer   updateaddall_descendantsr'   filter_remove_noder,   )r-   r3   Znode_matchesZfeature_namer&   r   )r4   r5   r3   r   remove_spec3   s     


zPrefixGraph.remove_specc                    sp   | j  | j fdd D }tfdd| D ttfdd| j }|D ]}| | qT|   |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 r   r   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 r   r   r   r&   childrenr*   r   r   r   a   s     zJPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<genexpr>c                    s   |  kS r   r   r%   )youngest_nodes_with_specsr   r   r6   d   r7   zIPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<lambda>)r)   r*   r'   itemsr;   r<   r,   )r-   inverted_graphremoved_nodesr&   r   )r)   r*   rG   r   +remove_youngest_descendant_nodes_with_specsS   s    

z7PrefixGraph.remove_youngest_descendant_nodes_with_specsc                 C   s
   t | jS r   )iterr)   )r-   r   r   r   r.   l   s    zPrefixGraph.recordsc                    s   | j  | jt| j }t  fdd D }tfdd| D }|sNqn|D ]}| | | qRq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 r   r   r>   r@   r   r   r   ~   s      z/PrefixGraph.prune.<locals>.<dictcomp>.<genexpr>rA   r"   rB   r%   r   rC   }   s    z%PrefixGraph.prune.<locals>.<dictcomp>c                 3   s"   | ]\}}|s| kr|V  qd S r   r   rD   rF   r   r   r      s     z$PrefixGraph.prune.<locals>.<genexpr>c                    s   |  kS r   r   r%   )rJ   r   r   r6      r7   z#PrefixGraph.prune.<locals>.<lambda>)	r)   r*   r'   r(   rH   r9   r<   r;   r,   )r-   Zoriginal_orderrI   Zprunable_nodesr&   r   )r)   rJ   r*   r   prunep   s&    



zPrefixGraph.prunec                    s   t  fdd| jD S )Nc                 3   s   | ]}|j  kr|V  qd S r   name)r   r    rN   r   r   r      s     
 z/PrefixGraph.get_node_by_name.<locals>.<genexpr>)nextr)   )r-   rO   r   rN   r   get_node_by_name   s    zPrefixGraph.get_node_by_namec                    s   | j   fdd D }|g}t d}|t|k rl|||  D ] }|kr@| || q@|d7 }q(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 r   r   r>   r@   r   r   r      s      z9PrefixGraph.all_descendants.<locals>.<dictcomp>.<genexpr>rA   r"   rB   r%   r   rC      s    z/PrefixGraph.all_descendants.<locals>.<dictcomp>r   r	   c                    s   |  kS r   r   r%   
nodes_seenr   r   r6      r7   z-PrefixGraph.all_descendants.<locals>.<lambda>r)   r(   lenr9   appendr'   r;   )r-   r&   rI   nodesqZ
child_noder   )r)   rS   r   r:      s&    



zPrefixGraph.all_descendantsc                    sp   | j }|g}t  d}|t|k rZ|||  D ] }| kr. | || q.|d7 }qtt fdd|S )Nr   r	   c                    s   |  kS r   r   r%   rR   r   r   r6      r7   z+PrefixGraph.all_ancestors.<locals>.<lambda>rT   )r-   r&   r)   rW   rX   Zparent_noder   rR   r   all_ancestors   s     


zPrefixGraph.all_ancestorsc                 C   sZ   | j }||krtd| || | j|d | D ]\}}||kr:|| q:dS )z1 Removes this node and all edges referencing it. znode %s does not existN)r)   KeyErrorpopr*   rH   remove)r-   r&   r)   Zedgesr   r   r   r<      s    
zPrefixGraph._remove_nodec                    sh   t dd | j D }| | tjr8t| |}nt| |}| j t  fdd|D | _|S )Nc                 s   s   | ]\}}|t |fV  qd S r   r   r   r&   parentsr   r   r   r      s     z(PrefixGraph._toposort.<locals>.<genexpr>c                 3   s   | ]}| | fV  qd S r   r   r2   Zoriginal_graphr   r   r      s     )	r   r)   rH   _toposort_prepare_graphr   Zallow_cyclesr'   _topo_sort_handle_cycles_toposort_raise_on_cycles)r-   Z
graph_copyZsorted_nodesr   r_   r   r,      s    
zPrefixGraph._toposortc                 c   s   |sd S t tdd | D dd d}|s0qd|D ]}|V  ||d  q4| D ]}||8 }qTqt|dkr|tt|d S )Nc                 s   s"   | ]\}}t |d kr|V  qdS )r   N)rU   r]   r   r   r   r      s      z8PrefixGraph._toposort_raise_on_cycles.<locals>.<genexpr>c                 S   s   | j S r   rN   xr   r   r   r6      r7   z7PrefixGraph._toposort_raise_on_cycles.<locals>.<lambda>r?   r   )r   sortedrH   r[   valuesrU   r   r'   )clsr)   Zno_parent_nodesr&   r^   r   r   r   rb      s    z%PrefixGraph._toposort_raise_on_cyclesc           
   
   #   s      D ]\}}|| qtdd   D  fdd D }tfdd|D dd d}|D ]
}|V  qf|  }zt|}|V  W q| tk
r }	 z.t	d|	 | 
 V  |  }W Y q|W 5 d }	~	X Y q| tk
r   Y d S X q|d S )	Nc                 s   s   | ]}|D ]
}|V  q
qd S r   r   )r   r^   r&   r   r   r   r      s       z7PrefixGraph._topo_sort_handle_cycles.<locals>.<genexpr>c                 3   s   | ]} | s|V  qd S r   r   r2   rB   r   r   r      s      c                 3   s   | ]}| kr|V  qd S r   r   r2   )nodes_that_are_parentsr   r   r      s      c                 S   s   | j S r   rN   rc   r   r   r   r6      r7   z6PrefixGraph._topo_sort_handle_cycles.<locals>.<lambda>re   z%r)rH   discardr(   rg   rf   rb   rP   r   logdebug_toposort_pop_keyStopIteration)
rh   r)   kvZnodes_without_parentsZdisconnected_nodesr&   tvalueer   )r)   ri   r   ra      s*    


z$PrefixGraph._topo_sort_handle_cyclesc                 C   sD   t dd |  D d d }| | |  D ]}|| q0|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 || |fV  qd S r   )rU   Zdist_strr]   r   r   r   r     s    z0PrefixGraph._toposort_pop_key.<locals>.<genexpr>r   r   )rf   rH   r[   rg   rj   )r)   Znode_with_fewest_parentsr^   r   r   r   rm     s    
zPrefixGraph._toposort_pop_keyc           	      C   s  | D ]8}|j dkr| | }t|D ]}|j dkr"|| q"qtrtdd | D d }tdd | D d }|r|d k	s|t| | }|  D ]"\}}||kr||kr|| qtdd | D d }|r| | }|  D ]0\}}t|dr|j	t
jkr||kr|| qd S )NpythonZpipc                 s   s   | ]}|j d kr|V  qdS )ZmenuinstNrN   r2   r   r   r   r   .  s     
 z6PrefixGraph._toposort_prepare_graph.<locals>.<genexpr>c                 s   s   | ]}|j d kr|V  qdS )rt   NrN   r2   r   r   r   r   /  s     
 c                 s   s   | ]}|j d kr|V  qdS )ZcondaNrN   r2   r   r   r   r   >  s     
 noarch)rO   r'   r\   r   rP   AssertionErrorrH   r9   hasattrru   r
   rt   )	r)   r&   r^   parentZmenuinst_nodeZpython_nodeZmenuinst_parentsZ
conda_nodeZconda_parentsr   r   r   r`     s.    

z#PrefixGraph._toposort_prepare_graphN)r   )__name__
__module____qualname____doc__r1   r=   rK   propertyr.   rM   rQ   r:   rY   r<   r,   classmethodrb   ra   staticmethodrm   r`   r   r   r   r   r      s(   
 
 

"
r   c                       s*   e Zd ZdZd fdd	Zdd Z  ZS )GeneralGrapha;  
    Compared with PrefixGraph, this class takes in more than one record of a given name,
    and operates on that graph from the higher view across any matching dependencies.  It is
    not a Prefix thing, but more like a "graph of all possible candidates" thing, and is used
    for unsatisfiability analysis
    r   c           
         s   t |}tt| || tt| _|D ]`}| j|jt	 }t dd |j
D D ](}||jt }|| |||j< qR|| j|j< q(t	 }t| j D ]6\}}||jt }	|	dd |D  |	||j< q|| _d S )Nc                 s   s   | ]}t |V  qd S r   r   r   r   r   r   r     s     z(GeneralGraph.__init__.<locals>.<genexpr>c                 s   s   | ]}|j V  qd S r   rN   )r   _r   r   r   r     s     )r'   superr   r1   r   dictspecs_by_namegetrO   r   r+   r(   r9   reversedr)   rH   r8   Zgraph_by_name)
r-   r.   r/   r&   Zparent_dictZdepdepsZconsolidated_graphr0   Zcg	__class__r   r   r1     s     

zGeneralGraph.__init__c                 C   s   g }| |g g }|r|d}|d }||kr4q| | ||krJ|S g }| j|j}|dkrfq| D ]\}	}
|t|
 qn|D ]:}|j|jkr|j|jkrqt|}| | | | qqdS )z/Return shorted path from root_spec to spec_namer   N)	rV   r[   r   r   rO   rH   extendlistversion)r-   Z	root_specZtarget_specZqueueZvisitedpathr&   rE   r/   r   r   Zadjnew_pathr   r   r   breadth_first_search_by_name  s.    


z)GeneralGraph.breadth_first_search_by_name)r   )ry   rz   r{   r|   r1   r   __classcell__r   r   r   r   r     s   r   N)Z
__future__r   r   r   r   collectionsr   r   Zloggingr   Zenumsr
   Z
match_specr   Z_vendor.boltons.setutilsr   Zbase.contextr   Zcommon.compatr   r   
exceptionsr   ry   rk   objectr   r   r   r   r   r   <module>   s     p