
    3~h40                         d dl mZ d dlmZ ddlmZ ddlmZ  G d de      Z	 G d d	e	      Z
d
 Z G d de	      Z G d de      Zy)    )Queue)ExceptionHandlingThread   )
Connection)GroupExceptionc                   V    e Zd ZdZd Zed        Zd Zd Zd Z	d Z
d Zd	 Zd
 Zd Zy)Groupak	  
    A collection of `.Connection` objects whose API operates on its contents.

    .. warning::
        **This is a partially abstract class**; you need to use one of its
        concrete subclasses (such as `.SerialGroup` or `.ThreadingGroup`) or
        you'll get ``NotImplementedError`` on most of the methods.

    Most methods in this class wrap those of `.Connection` and will accept the
    same arguments; however their return values and exception-raising behavior
    differ:

    - Return values are dict-like objects (`.GroupResult`) mapping
      `.Connection` objects to the return value for the respective connections:
      `.Group.run` returns a map of `.Connection` to `.runners.Result`,
      `.Group.get` returns a map of `.Connection` to `.transfer.Result`, etc.
    - If any connections encountered exceptions, a `.GroupException` is raised,
      which is a thin wrapper around what would otherwise have been the
      `.GroupResult` returned; within that wrapped `.GroupResult`, the
      excepting connections map to the exception that was raised, in place of a
      ``Result`` (as no ``Result`` was obtained.) Any non-excepting connections
      will have a ``Result`` value, as normal.

    For example, when no exceptions occur, a session might look like this::

        >>> group = SerialGroup('host1', 'host2')
        >>> group.run("this is fine")
        {
            <Connection host='host1'>: <Result cmd='this is fine' exited=0>,
            <Connection host='host2'>: <Result cmd='this is fine' exited=0>,
        }

    With exceptions (anywhere from 1 to "all of them"), it looks like so; note
    the different exception classes, e.g. `~invoke.exceptions.UnexpectedExit`
    for a completed session whose command exited poorly, versus
    `socket.gaierror` for a host that had DNS problems::

        >>> group = SerialGroup('host1', 'host2', 'notahost')
        >>> group.run("will it blend?")
        {
            <Connection host='host1'>: <Result cmd='will it blend?' exited=0>,
            <Connection host='host2'>: <UnexpectedExit: cmd='...' exited=1>,
            <Connection host='notahost'>: gaierror(...),
        }

    As with `.Connection`, `.Group` objects may be used as context managers,
    which will automatically `.close` the object on block exit.

    .. versionadded:: 2.0
    .. versionchanged:: 2.4
        Added context manager behavior.
    c           
      `    | j                  |D cg c]  }t        |fi | c}       yc c}w )a  
        Create a group of connections from one or more shorthand host strings.

        See `.Connection` for details on the format of these strings - they
        will be used as the first positional argument of `.Connection`
        constructors.

        Any keyword arguments given will be forwarded directly to those
        `.Connection` constructors as well. For example, to get a serially
        executing group object that connects to ``admin@host1``,
        ``admin@host2`` and ``admin@host3``, and forwards your SSH agent too::

            group = SerialGroup(
                "host1", "host2", "host3", user="admin", forward_agent=True,
            )

        .. versionchanged:: 2.3
            Added ``**kwargs`` (was previously only ``*hosts``).
        N)extendr   )selfhostskwargshosts       U/var/www/peopleoo.sandbox-dev.co.uk/venv/lib/python3.12/site-packages/fabric/group.py__init__zGroup.__init__?   s(    * 	EBDZ//BCBs   +c                 6     |        }|j                  |       |S )zg
        Alternate constructor accepting `.Connection` objects.

        .. versionadded:: 2.0
        )r   )clsconnectionsgroups      r   from_connectionszGroup.from_connectionsV   s     [!    c                     t         N)NotImplementedError)r   methodargsr   s       r   _doz	Group._doc   s
     "!r   c                 .     | j                   dg|i |S )z
        Executes `.Connection.run` on all member `Connections <.Connection>`.

        :returns: a `.GroupResult`.

        .. versionadded:: 2.0
        runr   r   r   r   s      r   r   z	Group.runh   s     txx////r   c                 .     | j                   dg|i |S )z
        Executes `.Connection.sudo` on all member `Connections <.Connection>`.

        :returns: a `.GroupResult`.

        .. versionadded:: 2.6
        sudor    r!   s      r   r#   z
Group.sudov   s     txx0000r   c                 .     | j                   dg|i |S )a  
        Executes `.Connection.put` on all member `Connections <.Connection>`.

        This is a straightforward application: aside from whatever the concrete
        group subclass does for concurrency or lack thereof, the effective
        result is like running a loop over the connections and calling their
        ``put`` method.

        :returns:
            a `.GroupResult` whose values are `.transfer.Result` instances.

        .. versionadded:: 2.6
        putr    r!   s      r   r%   z	Group.put   s     txx////r   c                 \    t        |      dk  r	d|vrd|d<    | j                  dg|i |S )a  
        Executes `.Connection.get` on all member `Connections <.Connection>`.

        .. note::
            This method changes some behaviors over e.g. directly calling
            `.Connection.get` on a ``for`` loop of connections; the biggest is
            that the implied default value for the ``local`` parameter is
            ``"{host}/"``, which triggers use of local path parameterization
            based on each connection's target hostname.

            Thus, unless you override ``local`` yourself, a copy of the
            downloaded file will be stored in (relative) directories named
            after each host in the group.

        .. warning::
            Using file-like objects as the ``local`` argument is not currently
            supported, as it would be equivalent to supplying that same object
            to a series of individual ``get()`` calls.

        :returns:
            a `.GroupResult` whose values are `.transfer.Result` instances.

        .. versionadded:: 2.6
           localz{host}/get)lenr   r!   s      r   r)   z	Group.get   s:    : t9q=WF2'F7Otxx////r   c                 2    | D ]  }|j                           y)zx
        Executes `.Connection.close` on all member `Connections <.Connection>`.

        .. versionadded:: 2.4
        Nclose)r   cxns     r   r-   zGroup.close   s      	CIIK	r   c                     | S r    r   s    r   	__enter__zGroup.__enter__   s    r   c                 $    | j                          y r   r,   )r   excs     r   __exit__zGroup.__exit__   s    

r   N)__name__
__module____qualname____doc__r   classmethodr   r   r   r#   r%   r)   r-   r2   r5   r0   r   r   r	   r	   	   sK    3jD. 
 
"
0	1*0 0Br   r	   c                       e Zd ZdZd Zy)SerialGroupzc
    Subclass of `.Group` which executes in simple, serial fashion.

    .. versionadded:: 2.0
    c                     t               }d}| D ]  }	  t        ||      |i |||<    |rt        |      |S # t        $ r}|||<   d}Y d }~?d }~ww xY w)NFT)GroupResultgetattr	Exceptionr   )r   r   r   r   resultsexceptedr.   es           r   r   zSerialGroup._do   ss    - 	 C 3wsF3TDVD	   ))     s   9	AAANr6   r7   r8   r9   r   r0   r   r   r<   r<      s    r   r<   c                 N     t        | |      |i |}|j                  | |f       y r   )r?   r%   )r.   queuer   r   r   results         r   thread_workerrH      s*    !WS&!4262F	IIsFmr   c                       e Zd ZdZd Zy)ThreadingGroupzg
    Subclass of `.Group` which uses threading to execute concurrently.

    .. versionadded:: 2.0
    c                 
   t               }t               }g }| D ]2  }t        t        t	        |||||            }|j                  |       4 |D ]  }|j                           |D ]  }|j                           |j                         s+|j                  d      \  }}	|	||<   |j                         s+d}
|D ]8  }|j                         }||j                  d   d   }|j                  ||<   d}
: |
rt        |      |S )N)r.   rF   r   r   r   )targetr   F)blockr   r.   T)r>   r   r   rH   dictappendstartjoinemptyr)   	exceptionr   valuer   )r   r   r   r   rA   rF   threadsr.   threadrG   rB   wrappers               r   r   zThreadingGroup._do   s#   - 	#C,$!!	F NN6"	#  	FLLN	 	FKKM	 ++-))%)0KC "GCL ++-  	 F&&(G" nnX.u5&}}	   ))r   NrD   r0   r   r   rJ   rJ      s    -r   rJ   c                   H     e Zd ZdZ fdZd Zed        Zed        Z xZ	S )r>   a  
    Collection of results and/or exceptions arising from `.Group` methods.

    Acts like a dict, but adds a couple convenience methods, to wit:

    - Keys are the individual `.Connection` objects from within the `.Group`.
    - Values are either return values / results from the called method (e.g.
      `.runners.Result` objects), *or* an exception object, if one prevented
      the method from returning.
    - Subclasses `dict`, so has all dict methods.
    - Has `.succeeded` and `.failed` attributes containing sub-dicts limited to
      just those key/value pairs that succeeded or encountered exceptions,
      respectively.

      - Of note, these attributes allow high level logic, e.g. ``if
        mygroup.run('command').failed`` and so forth.

    .. versionadded:: 2.0
    c                 @    t        |   |i | i | _        i | _        y r   )superr   
_successes	_failures)r   r   r   	__class__s      r   r   zGroupResult.__init__3  s#    $)&)r   c                     | j                   s| j                  ry | j                         D ]4  \  }}t        |t              r|| j                  |<   &|| j                   |<   6 y r   )r[   r\   items
isinstanceBaseException)r   keyrT   s      r   
_bifurcatezGroupResult._bifurcate8  sS    ??dnn **, 	-JC%/&+s#',$		-r   c                 :    | j                          | j                  S )z_
        A sub-dict containing only successful results.

        .. versionadded:: 2.0
        )rc   r[   r1   s    r   	succeededzGroupResult.succeededD  s     	r   c                 :    | j                          | j                  S )z[
        A sub-dict containing only failed results.

        .. versionadded:: 2.0
        )rc   r\   r1   s    r   failedzGroupResult.failedN  s     	~~r   )
r6   r7   r8   r9   r   rc   propertyre   rg   __classcell__)r]   s   @r   r>   r>     s:    (

-    r   r>   N)rF   r   invoke.utilr   
connectionr   
exceptionsr   listr	   r<   rH   rJ   rN   r>   r0   r   r   <module>rn      sJ     / " &@D @F% *4U 4n8$ 8r   