ó
E®Uc           @   sB  d  d l  Z  d  d l Z d  d l m Z m Z m Z m Z m Z d  d l m Z m	 Z	 m
 Z
 d d d e e d d d d d „	 Z d e f d „  ƒ  YZ d „  Z d „  Z d	 „  Z d
 „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d e d e e d „ Z d d e e d e d e d d d d d „ Z d „  Z d S(   iÿÿÿÿN(   t
   null_debugt   PURPLEt   MAGENTAt   DARK_YELLOWt   RED(   t
   DARK_GREENt   C_NORMALt   GREYc      
   C   sî  | r# |  d | j  d  d ƒ 7}  n  t t j j | d |  ƒ d ƒ } | d  k	 ra | | j ƒ n  d j d „  |  Dƒ ƒ } | d | r d n d	 | f IJ| d
 | pª | IJ| rxf t | ƒ D]U \ } } | rè | j d d ƒ } n  |
 rü d |
 | n d } | d | | f IJqÁ Wn  x¶ t | ƒ D]¨ \ } } | \ } } | ro| j d d ƒ } | j d d ƒ } n  | r{d n d } |	 r•d |	 | n d } | r¯d | | n d } | d | | | | | f IJq*W| d IJ| j	 ƒ  d  S(   Nt   _s   , s   %s.dott   wt    c         s   s!   |  ] } | j  ƒ  r | Vq d  S(   N(   t   isalnum(   t   .0t   x(    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pys	   <genexpr>(   s    s   %s %s {t   digrapht   graphs   label="%s";
fontsize=20;t   ,s   \ns
   color="%s"s
   "%s" [%s];s   ->s   --s
   label="%s"s   "%s" %s "%s" [%s %s];t   }(
   t	   translatet   Nonet   opent   ost   patht   joint   namet	   enumeratet   replacet   close(   t   basenamet	   edge_listt   verticest   labelt   dot_file_dirt   reformat_labelst   directedt   debugt   edge_colorst   edge_labelst   vertex_colorst   ft	   graphnamet   it   vt   vct   edget   at   bt   linet   elt   ec(    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   write_dot_file   s2    " !
t
   GraphErrorc           B   s   e  Z RS(    (   t   __name__t
   __module__(    (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyR3   ?   s   c         C   s˜   x‘ | D]‰ } t  ƒ  } xL |  D]D \ } } | | k rE | j | ƒ q | | k r | j | ƒ q q Wt | ƒ d t | ƒ k r t d ƒ ‚ q q Wd S(   sX   The graph is complete, which is to say there is an edge between
    every pair of nodes.i   s   graph is not fully connectedN(   t   sett   addt   lenR3   (   t   edgesR   t   edge_verticesR*   t   remotesR-   R.   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   verify_graph_completeC   s    	c   
      C   sh  |  sA t  | ƒ d k r d St d t | ƒ t |  ƒ f ƒ ‚ n  t |  ƒ } t | j ƒ  ƒ } x³ t rg  } xx t | ƒ D]j \ } } | \ } }	 | | k r¼ | j |	 ƒ | j	 | ƒ q{ |	 | k r{ | j | ƒ | j	 | ƒ q{ q{ W| só Pn  x t
 | ƒ D] } | | =q Wqb W| s-| t | ƒ k rdt d t | ƒ t |  ƒ t | ƒ t | ƒ f ƒ ‚ n  d S(   s&   There is a path between any two nodes.i   Ns9   disconnected vertices were found:
vertices: %s
 edges: %ssR   graph is not connected:
 vertices: %s
 edges: %s
 reached: %s
 remaining edges: %s(   R8   R3   t   sortedt   listR6   t   popt   TrueR   R7   t   appendt   reversed(
   R9   R   R:   t   remaining_edgest   reachedt   doomedR)   t   eR-   R.   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   verify_graph_connectedQ   s2    	c         C   s;   x4 t  j |  t |  ƒ d ƒ D] } t | | | ƒ q Wd S(   s:   The graph stays connected when any single edge is removed.i   N(   t	   itertoolst   combinationsR8   RG   (   R9   R   R:   t   subset(    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt*   verify_graph_connected_under_edge_failuresr   s    #c         C   so   xh | D]` } g  | D] } | | k	 r | ^ q } g  |  D] } | | k r9 | ^ q9 } t  | | | ƒ q Wd S(   s<   The graph stays connected when any single vertex is removed.N(   RG   (   R9   R   R:   R*   R   t   sub_verticest	   sub_edges(    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt,   verify_graph_connected_under_vertex_failuresx   s    %%c         C   s°   g  |  D] } t  | ƒ ^ q } xŠ t r« x} t j | d ƒ D]e \ } } | | @} | r; t | ƒ d k r„ | | O} | j | ƒ Pq  t d | |  | f ƒ ‚ q; q; Wd Sq" Wd S(   sK   The graph contains no loops. A forest that is also connected is a
    tree.i   i   sD   there is a loop in the graph
 vertices %s
 edges %s
 intersection %sN(   R6   R@   RH   RI   R8   t   removeR3   (   R9   R   R:   RF   t   treesR-   R.   t   intersection(    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   verify_graph_forest   s    	

c   	      C   s¯   t  |  ƒ } g  | D] } t  | ƒ ^ q } x} t rª xp t j | d ƒ D]X \ } } | | @} | rG t | ƒ d k r | | O} | j | ƒ PqŸ t d ƒ ‚ qG qG Wd Sq. Wd S(   s,  This allows a forest with duplicate edges. That is if multiple
    edges go between the same two vertices, they are treated as a
    single edge by this test.

    e.g.:
                        o
    pass: o-o=o  o=o   (|)             fail:  o-o
            `o          o                     `o'
    i   i   s   there is a loop in the graphN(   R6   R@   RH   RI   R8   RO   R3   (	   R9   R   R:   t   unique_edgesRF   RP   R-   R.   RQ   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   verify_graph_multi_edge_forestœ   s    
	

c         C   sB   t  | ƒ t  | ƒ } | r> t d d j t | ƒ ƒ ƒ ‚ n  d S(   s$   There are no vertices without edges.s#   some vertices are not connected:
%ss   
N(   R6   R3   R   R=   (   R9   R   R:   t   lonely(    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   verify_graph_no_lonely_vertices¶   s    c         C   sB   t  | ƒ t  | ƒ } | r> t d d j t | ƒ ƒ ƒ ‚ n  d S(   sB   The edge endpoints contain no vertices that are otherwise unknown.s,   some edge vertices are seemingly unknown:
%ss   
N(   R6   R3   R   R=   (   R9   R   R:   t   unknown(    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt    verify_graph_no_unknown_vertices¾   s    c            s,  |  r t  | ƒ d k r d St  |  ƒ d t  | ƒ k  rH t d ƒ ‚ n  t |  ƒ } t ƒ  } xd |  D]\ } | d | d f } | | k rd | | k rd | j | ƒ | j | ƒ | j | ƒ qd qd Wi  } xL | D]D \ } }	 | j | t ƒ  ƒ j |	 ƒ | j |	 t ƒ  ƒ j | ƒ qÑ Wx? | j ƒ  D]1 \ }
 } t  | ƒ d k r&t d |
 ƒ ‚ q&q&Wxv | j ƒ  D]h }
 | |
 } | s„qhn  xB | D]: ‰  | ˆ  } | j |
 ƒ | j ‡  f d †  | Dƒ ƒ q‹W| |
 =qhWt  | ƒ d k rt d d	 j	 | j ƒ  ƒ ƒ ‚ n  t
 | | | ƒ t | | | ƒ d S(
   s7  Each node has at least two directed edges leaving it, and two
    arriving. The edges work in pairs that have the same end points
    but point in opposite directions. The pairs form a path that
    touches every vertex and form a loop.

    There might be other connections that *aren't* part of the ring.

    Deciding this for sure is NP-complete (the Hamiltonian path
    problem), but there are some easy failures that can be detected.
    So far we check for:
      - leaf nodes
      - disjoint subgraphs
      - robustness against edge and vertex failure
    i   Ni   sF   directed double ring requires at least twice as many edges as verticesi    s2   wanted double directed ring, found a leaf node(%s)c         3   s!   |  ] } | ˆ  k r | Vq d  S(   N(    (   R   R   (   t   n(    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pys	   <genexpr>  s    sZ   wanted double directed ring, but this looks like a split graph
(%s can't reach each other)s   , (   R8   R3   R6   R7   RO   t
   setdefaultt   itemst   keyst   updateR   RK   RN   (   R9   R   R:   t   half_duplext   duplex_linksR,   t   rev_edget   edge_mapR-   R.   t   vertext
   neighbourst   nsett   n_neighbours(    (   RY   s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt!   verify_graph_directed_double_ringÆ   sH    	 

!		c         C   s•   t  | ƒ d k  r d St  | ƒ d k r… t  |  ƒ d k rv |  d d |  d d k rv |  d d |  d d k rv d St d ƒ ‚ n  t |  | | ƒ S(   sŒ   This performs the directed_double_ring test but makes special
    concessions for small rings where the strict rules don't really
    apply.i   Ni    i   s0   A two vertex graph should have an edge each way.(   R8   R3   Rf   (   R9   R   R:   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt*   verify_graph_directed_double_ring_or_small  s    c         C   s  g  } | d t  t |  t f ƒ g  | D] } | j d d ƒ ^ q' } t ƒ  }	 x. | D]& \ }
 } |	 j |
 ƒ |	 j | ƒ qU W| d  k r” |	 } n; t | ƒ } | |	 k rÏ | d t |	 ƒ t | ƒ f ƒ n  x¨ | D]  } d | } y t ƒ  | } Wn( t	 k
 r!| j
 | d | f ƒ n Xy+ | | | |	 ƒ | d t | t f ƒ WqÖ t k
 ru} | j
 | | f ƒ qÖ XqÖ W| r| r²t d |  d	 j d
 „  | Dƒ ƒ f ƒ ‚ n  | d t |  t f ƒ x. | D]& \ } } | d | t | t f ƒ qÐW| t ƒ n  d  S(   Ns"   %sStarting verify_graph for %s%s%st    R   s7   vertices in edges don't match given vertices:
 %s != %ss   verify_graph_%ss'   There is no verification check for '%s's    %s%18s:%s verified!s1   The '%s' graph lacks the following properties:
%ss   
c         s   s   |  ] } d  | Vq d S(   s   %s: %sN(    (   R   R   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pys	   <genexpr>L  s    s   %s%s%s FAILED:s    %18s: %s%s%s(   R   R   R   R   R6   R7   R   R=   t   globalst   KeyErrorRA   R   R3   R   R   R   (   t   titleR9   R   R"   t
   propertiest   fatalR#   t   errorsR   R:   R-   R.   t   pt   fnR'   RF   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   verify_graph'  sB    %		
&c         C   s—   d |  | p d f } |	 rA t  | | | d | d | d | ƒn  |
 d  k	 r“ t |  | d | d | d |
 d	 | d
 | d | d | d | d | ƒ	n  d  S(   Ns   %s %sR
   Rl   Rm   R#   R   R   R    R!   R"   R$   R%   R&   (   Rq   R   R2   (   R   R9   R   R   R!   R"   Rl   Rm   R#   t   verifyR    R$   R%   R&   Rk   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   verify_and_dotS  s    c          C   su   xn t  t ƒ  j ƒ  ƒ D]W \ }  } |  j d ƒ r |  j d d ƒ GH| j ri d t | j j ƒ  t f GHqm Hq q Wd  S(   Nt   verify_graph_R
   s
       %s%s%s(	   R=   Ri   R[   t
   startswithR   t   __doc__R   t   rstripR   (   t   kR*   (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   list_verify_testsf  s    "	(    (    (   R   RH   t   samba.kcc.debugR    R   R   R   R   R   R   R   R   R@   t   FalseR2   t	   ExceptionR3   R<   RG   RK   RN   RR   RT   RV   RX   Rf   Rg   Rq   Rs   Ry   (    (    (    s9   /usr/lib/python2.7/dist-packages/samba/kcc/graph_utils.pyt   <module>   s6   (		 		!								P		+	