
    wBf@                         d 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 d	d
lmZ d	dlmZ  ee      Z G d d      Z G d de      Zy)zImplements directed graphs to sort and manipulate packages within a prefix.

Object inheritance:

.. autoapi-inheritance-diagram:: PrefixGraph GeneralGraph
   :top-classes: conda.models.prefix_graph.PrefixGraph
   :parts: 1
    )defaultdict)	getLogger)
IndexedSet   )context)on_win)CyclicalDependencyError   )
NoarchType	MatchSpecc                       e Zd ZdZddZd Zd Zed        Zd Z	d Z
d Zd	 Zd
 Zd Zed        Zed        Zed        Zed        Zy)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                 T  	 t        |      }t        |      }i x| _        }i x| _        }|D ]d  	t        d 	j                  D              }|D ch c]  t        fd|D              s }}||	<   t        	fd|D              }|s`||	<   f | j                          y c c}w )Nc              3   2   K   | ]  }t        |        y wNr   .0ds     9lib/python3.12/site-packages/conda/models/prefix_graph.py	<genexpr>z'PrefixGraph.__init__.<locals>.<genexpr>.   s     &Jy|&J   c              3   @   K   | ]  }|j                          y wr   match)r   mrecs     r   r   z'PrefixGraph.__init__.<locals>.<genexpr>0   s     -Wqaggcl-Ws   c              3   F   K   | ]  }|j                        s|  y wr   r   )r   snodes     r   r   z'PrefixGraph.__init__.<locals>.<genexpr>3   s     'JaAGGDM'J   !!)tuplesetgraphspec_matchesdependsanyr   	_toposort)
selfrecordsspecsr$   r%   parent_match_specsr   parent_nodesmatching_specsr    s
         `  @r   __init__zPrefixGraph.__init__(   s    .E

U+--L 	4D!&&JT\\&J!J&#-WDV-W*WL  'E$K''J5'JJN%3T"	4 	s   B%+B%c                 (   | j                   D ch c]  }|j                  |      s| }}|j                  d      xs dD ]2  }t        |      |j	                  fd| j                   D               4 t               |D ]3  }j                  |       j	                  | j                  |             5 t        t        fd| j                               D ]  }| j                  |        | j                          t              S c c}w )z
        Remove all matching nodes, and any associated child nodes.

        Args:
            spec (MatchSpec):

        Returns:
            tuple[PrefixRecord]: The removed nodes.

        track_features )featuresc              3   F   K   | ]  }j                  |      s|  y wr   r   )r   r    feature_specs     r   r   z*PrefixGraph.remove_spec.<locals>.<genexpr>J   s     X|?Q?QRV?WXr!   c                     | v S r   r2   )r    remove_theses    r   <lambda>z)PrefixGraph.remove_spec.<locals>.<lambda>P   s    1E     )r$   r   get_raw_valuer   updater#   addall_descendantsr"   filter_remove_noder(   )r)   specr    node_matchesfeature_namer5   r7   s        @@r   remove_speczPrefixGraph.remove_spec9   s     *.Htzz$7GHH !../?@FB 	YL$l;LXXX	Y u  	<DT" 4 4T :;	< V$EtzzRS  	$Dd#	$\""! Is
   DDc                 x   | j                   }| j                  |D ci c]  }||D ch c]  }|||   v s| c} }}}t        fd|j                         D              t        t	        fd| j                               }|D ]  }| j                  |        | j                          |S c c}w c c}}w )z
        A specialized method used to determine only dependencies of requested specs.

        Returns:
            tuple[PrefixRecord]: The removed nodes.

        c              3   4   K   | ]  \  }}|s|v r|  y wr   r2   r   r    childrenr%   s      r   r   zJPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<genexpr>c   s'      *
h 4 *
   c                     | v S r   r2   )r    youngest_nodes_with_specss    r   r8   zIPrefixGraph.remove_youngest_descendant_nodes_with_specs.<locals>.<lambda>i   s    (A A r9   )r$   r%   r"   itemsr>   r?   r(   )r)   r$   r    keyinverted_graphremoved_nodesr%   rJ   s         @@r   +remove_youngest_descendant_nodes_with_specsz7PrefixGraph.remove_youngest_descendant_nodes_with_specsV   s     

((KP
CGD%>345:+=3>>
 
 %* *
"0"6"6"8*
 %
!
 A4::N
 " 	$Dd#	$ ?
s   
B6B1B1B61B6c                 ,    t        | j                        S r   )iterr$   )r)   s    r   r*   zPrefixGraph.recordsp   s    DJJr9   c                    | j                   }| j                  t        | j                         }t               	 |D ci c]  }||D ch c]  }|||   v s| c} }}}t        fd|j	                         D              }|sn*|D ]$  }j                  |       | j                  |       & wt        t        fd|            | j                          S c c}w c c}}w )zPrune back all packages until all child nodes are anchored by a spec.

        Returns:
            tuple[PrefixRecord]: The pruned nodes.

        c              3   4   K   | ]  \  }}|s|vr|  y wr   r2   rF   s      r   r   z$PrefixGraph.prune.<locals>.<genexpr>   s'      #"D(D$< #rH   c                     | v S r   r2   )r    rN   s    r   r8   z#PrefixGraph.prune.<locals>.<lambda>   s     5 r9   )	r$   r%   r"   r#   rK   r<   r?   r>   r(   )	r)   r$   original_orderr    rL   rM   prunable_nodesrN   r%   s	          @@r   prunezPrefixGraph.prunet   s     

((tzz*OTGKeBstuSz/AsBBN  # #&4&:&:&<# N
 "& (!!$'!!$'(  5~F
 	# Cs    
C!
CCC!C!c                 @    t        fd| j                  D              S )Nc              3   B   K   | ]  }|j                   k(  s|  y wr   name)r   r   r[   s     r   r   z/PrefixGraph.get_node_by_name.<locals>.<genexpr>   s     BCT1ACBs   )nextr$   )r)   r[   s    `r   get_node_by_namezPrefixGraph.get_node_by_name   s    B4::BBBr9   c                 |   | j                   }|D ci c]  }||D ch c]  }|||   v s| c} }}}g}t               d}|t        |      k  rH|||      D ])  }|vsj                  |       |j	                  |       + |dz  }|t        |      k  rHt        t        fd|            S c c}w c c}}w )Nr   r
   c                     | v S r   r2   r    
nodes_seens    r   r8   z-PrefixGraph.all_descendants.<locals>.<lambda>       ); r9   r$   r#   lenr<   appendr"   r>   )	r)   r    r$   rL   rM   nodesq
child_nodera   s	           @r   r=   zPrefixGraph.all_descendants   s    

KP
CGD%>345:+=3>>
 
 U
#e*n,U1X6 -
Z/NN:.LL,- FA #e*n V;UCDD ?
s   
B8B3B3B83B8c                    | j                   }|g}t               d}|t        |      k  rH|||      D ])  }|vsj                  |       |j	                  |       + |dz  }|t        |      k  rHt        t        fd|            S )Nr   r
   c                     | v S r   r2   r`   s    r   r8   z+PrefixGraph.all_ancestors.<locals>.<lambda>   rb   r9   rc   )r)   r    r$   rf   rg   parent_nodera   s         @r   all_ancestorszPrefixGraph.all_ancestors   s    

U
#e*n$U1X .j0NN;/LL-. FA #e*n V;UCDDr9   c                     | j                   }||vrt        d|z        |j                  |       | j                  j                  |d       |j	                         D ]  \  }}||v s|j                  |        y)z/Removes this node and all edges referencing it.znode %s does not existN)r$   KeyErrorpopr%   rK   remove)r)   r    r$   edgess       r   r?   zPrefixGraph._remove_node   sq    

u3d:;;		$dD) ;;= 	#KD%u}T"	#r9   c                 ~   | j                   j                         D ci c]  \  }}|t        |       }}}| j                  |       t        j
                  rt        | j                  |            }nt        | j                  |            }| j                   }|D ci c]  }|||   
 c}| _         |S c c}}w c c}w r   )	r$   rK   r   _toposort_prepare_graphr   allow_cyclesr"   _topo_sort_handle_cycles_toposort_raise_on_cycles)r)   r    parents
graph_copysorted_nodesoriginal_graphs         r   r(   zPrefixGraph._toposort   s    EIZZEUEUEWXMD'dJw//X
X$$Z0 !>!>z!JKL !?!?
!KLL=IJTdN400J
 Y Ks   B4B:c              #   &  K   |sy 	 t        t        d |j                         D        d             }|sn8|D ]  }| |j                  |d         |j	                         D ]  }||z  }	 gt        |      dk7  rt        t        |            y w)Nc              3   D   K   | ]  \  }}t        |      d k(  s|  yw)r   N)rd   r   r    rw   s      r   r   z8PrefixGraph._toposort_raise_on_cycles.<locals>.<genexpr>   s      RmdGGPQ@QTRs     c                     | j                   S r   rZ   xs    r   r8   z7PrefixGraph._toposort_raise_on_cycles.<locals>.<lambda>   s
    !&& r9   rL   r   )r   sortedrK   ro   valuesrd   r	   r"   )clsr$   no_parent_nodesr    rw   s        r   rv   z%PrefixGraph._toposort_raise_on_cycles   s     (Ru{{}R(O #' &
		$%& !<<> +?*+ " u:?)%,77 s   BBc              #     K   j                         D ]  \  }}|j                  |        j                         D ch c]  }|D ]  }|  c}}fdD        }t        fd|D        d       }|E d {    | j	                        }	 	 t        |      }	|	 c c}}w 7 -# t        $ rD}
t        j                  d|
       | j                         | j	                        }Y d }
~
bd }
~
wt        $ r Y y w xY ww)Nc              3   .   K   | ]  }|   r	|  y wr   r2   )r   r    r$   s     r   r   z7PrefixGraph._topo_sort_handle_cycles.<locals>.<genexpr>   s      K$uT{ Ks   
c              3   *   K   | ]
  }|vr|  y wr   r2   )r   r    nodes_that_are_parentss     r   r   z7PrefixGraph._topo_sort_handle_cycles.<locals>.<genexpr>   s"      55 s   c                     | j                   S r   rZ   r   s    r   r8   z6PrefixGraph._topo_sort_handle_cycles.<locals>.<lambda>   s
    !&& r9   r   z%r)rK   discardr   r   rv   r\   r	   logdebug_toposort_pop_keyStopIteration)r   r$   kvrw   r    nodes_without_parentsdisconnected_nodestvalueer   s    `         @r   ru   z$PrefixGraph._topo_sort_handle_cycles   s     KKM 	DAqIIaL	
 !&"
7"
37D"
"
 !L% K#1
 !
 &%%))%0Q !"
 	& +  		$"++E2211%8  sS   =DB$+D<B*=DB, #D,	D5:C4/D4D DDDc                     t        d | j                         D              d   d   }| j                  |       | j                         D ]  }|j	                  |        |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              3   Z   K   | ]#  \  }}t        |      |j                         |f % y wr   )rd   dist_strr}   s      r   r   z0PrefixGraph._toposort_pop_key.<locals>.<genexpr>  s*      *
6CdGS\4==?D1*
s   )+r   r   )r   rK   ro   r   r   )r$   node_with_fewest_parentsrw   s      r   r   zPrefixGraph._toposort_pop_key  sk     $* *
GL{{}*
 $

$$  			*+||~ 	6GOO45	6 ('r9   c                 \   | D ]H  }|j                   dk(  s| |   }t        |      D ]#  }|j                   dk(  s|j                  |       % J t        d | D        d       }t        d | D        d       }|r<|J | |   }| j	                         D ]   \  }}||v s||vs|j                  |       " t        rut        d | D        d       }|r_| |   }| j	                         D ]F  \  }}t        |d      s|j                  t        j                  k(  s1||vs6|j                  |       H y y y )Npythonpipc              3   @   K   | ]  }|j                   d k(  s|  yw)menuinstNrZ   r   r    s     r   r   z6PrefixGraph._toposort_prepare_graph.<locals>.<genexpr>.  s     Pt		Z8OdP   c              3   @   K   | ]  }|j                   d k(  s|  yw)r   NrZ   r   s     r   r   z6PrefixGraph._toposort_prepare_graph.<locals>.<genexpr>/  s     LTdii86KDLr   c              3   @   K   | ]  }|j                   d k(  s|  yw)condaNrZ   r   s     r   r   z6PrefixGraph._toposort_prepare_graph.<locals>.<genexpr>?  s     Ng9MtNr   noarch)r[   r"   rp   r\   rK   r<   r   hasattrr   r   r   )	r$   r    rw   parentmenuinst_nodepython_nodemenuinst_parents
conda_nodeconda_parentss	            r   rs   z#PrefixGraph._toposort_prepare_graph  sE     	/DyyH$+#Gn /F{{e+v./	/ PuPRVWLULdS ***$]3!& /g')d:J.JKK./  NNPTUJ %j 1%*[[] 0MD'h/ KK:+<+<< 5J/0  r9   Nr2   )__name__
__module____qualname____doc__r/   rC   rO   propertyr*   rW   r]   r=   rl   r?   r(   classmethodrv   ru   staticmethodr   rs   r2   r9   r   r   r      s    "#:4    BCE"E
#	 8 80 % %N ( ( *0 *0r9   r   c                   *     e Zd ZdZd fd	Zd Z x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
    c                    t        |      }t        
| 	  ||       t        t              | _        |D ]  }| j
                  j                  |j                  i       }t        d |j                  D              D ]F  }|j                  |j                  t                     }|j                  |       |||j                  <   H || j
                  |j                  <    i }t        t        | j                  j                                     D ]P  \  }}|j                  |j                  t                     }	|	j                  d |D               |	||j                  <   R || _        y )Nc              3   2   K   | ]  }t        |        y wr   r   r   s     r   r   z(GeneralGraph.__init__.<locals>.<genexpr>  s     @aYq\@r   c              3   4   K   | ]  }|j                     y wr   rZ   )r   _s     r   r   z(GeneralGraph.__init__.<locals>.<genexpr>  s     3aff3s   )r"   superr/   r   dictspecs_by_namegetr[   r&   r#   r<   reversedlistr$   rK   r;   graph_by_name)r)   r*   r+   r    parent_dictdepdepsconsolidated_graphr-   cg	__class__s             r   r/   zGeneralGraph.__init__  s,   .%((. 	8D,,00B?K@4<<@@ -"sxx7(,CHH%- -8Dtyy)	8  "*4

0@0@0B+C"D 	/D,#''		359BII3l33,.tyy)	/ 0r9   c                 (   g }|j                  |g       g }|r|j                  d      }|d   }||v r|j                  |       ||k(  r|S g }| j                  j                  |j                        }|_|j                         D ]  \  }	}
|j                  t        |
             ! |D ]b  }|j                  |j                  k(  r|j                  |j                  k7  r6t        |      }|j                  |       |j                  |       d |ryy)z/Return shorted path from root_spec to spec_namer   N)	re   ro   r   r   r[   rK   extendr   version)r)   	root_spectarget_specqueuevisitedpathr    rG   r+   r   r   adjnew_paths                r   breadth_first_search_by_namez)GeneralGraph.breadth_first_search_by_name  s   i[!99Q<D8DwNN4 {"H&&**4995E} ;;= ,4T
+, +88{///CKK;CVCV4V#DzHOOC(LL*+ r9   r   )r   r   r   r   r/   r   __classcell__)r   s   @r   r   r     s    0(+r9   r   N)r   collectionsr   loggingr   boltons.setutilsr   base.contextr   common.compatr   
exceptionsr	   enumsr   
match_specr   r   r   r   r   r2   r9   r   <module>r      sG    $  ' " " 0  !o0 o0X5+; 5+r9   