o
    V+                     @   s   d dl Z d dlZd dlZd dlmZ d dlmZ d dlmZ G dd de	Z
G dd de	ZG dd deZdd
dZG dd deZG dd de	ZdS )    N)SSLErrorc                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )WINCHHandlerz?
    WINCH Signal handler to keep the PTY correctly sized.
    c                 C   s   || _ d| _dS )z
        Initialize a new WINCH handler for the given PTY.

        Initializing a handler has no immediate side-effects. The `start()`
        method must be invoked for the signals to be trapped.
        N)ptyoriginal_handler)selfr    r   //usr/lib/python3/dist-packages/dockerpty/pty.py__init__   s   
zWINCHHandler.__init__c                 C   s   |    | S )z5
        Invoked on entering a `with` block.
        )startr   r   r   r   	__enter__*   s   zWINCHHandler.__enter__c                 G   s   |    dS )z4
        Invoked on exiting a `with` block.
        N)stop)r   _r   r   r   __exit__2   s   zWINCHHandler.__exit__c                    s     fdd}t  t j| _dS )z
        Start trapping WINCH signals and resizing the PTY.

        This method saves the previous WINCH handler so it can be restored on
        `stop()`.
        c                    s   | t jkr j  d S d S N)signalSIGWINCHr   resize)signumframer   r   r   handleA   s   
z"WINCHHandler.start.<locals>.handleN)r   r   r   )r   r   r   r   r   r
   9   s   zWINCHHandler.startc                 C   s"   | j durttj| j  dS dS )zU
        Stop trapping WINCH signals and restore the previous WINCH handler.
        N)r   r   r   r   r   r   r   r   G   s   
zWINCHHandler.stopN)	__name__
__module____qualname____doc__r	   r   r   r
   r   r   r   r   r   r      s    r   c                   @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
	Operationc                 K      t  )z3
        are we dealing with a tty or not?
        NotImplementedErrorr   kwargsr   r   r   israwR      zOperation.israwc                 K   r   )!
        start execution
        r   r   r   r   r   r
   X   r"   zOperation.startc                 K   r   )z0
        if we have terminal, resize it
        r   r   heightwidthr    r   r   r   r   ^   r"   zOperation.resizec                 C   r   )zReturn sockets for streams.r   r   r   r   r   socketsd   s   zOperation.socketsN)r   r   r   r!   r
   r   r'   r   r   r   r   r   P   s
    r   c                   @   sD   e Zd ZdZdddZdddZdd	 Zd
d Zdd Zdd Z	dS )RunOperationz6
    class for handling `docker run`-like command
    TNc                 C   s^   |du rt dt d}|| _|| _d| _|| _|ptj| _|p"tj	| _	|p(tj
| _
|| _dS )Y
        Initialize the PTY using the docker.Client instance and container dict.
        NzThe default behaviour of dockerpty is changing. Please add logs=1 to your dockerpty.start call to maintain existing behaviour. See https://github.com/d11wtq/dockerpty/issues/51 for details.   )warningswarnDeprecationWarningclient	containerrawinteractivesysstdoutstderrstdinlogs)r   r.   r/   r1   r3   r4   r5   r6   r   r   r   r	   n   s   
zRunOperation.__init__c                 K   s   |p|   \}}}g }|r| jr|tjt| j|dd |r0|tj|t| jdd |rA|tj|t| jdd | 	 d d sT| j
j| jfi | |S )z
        Present the PTY of the container inside the current process.

        This will take over the current process' TTY until the container's PTY
        is closed.
        Fwait_for_outputpropagate_closeStateRunning)r'   r1   appendioPumpStreamr5   r3   r4   _container_infor.   r
   r/   )r   r'   r    	pty_stdin
pty_stdout
pty_stderrpumpsr   r   r   r
      s   
zRunOperation.startc                 K   s0   | j du r|  }| j o|d d | _ | j S )z
        Returns True if the PTY should operate in raw mode.

        If the container was not started with tty=True, this will return False.
        NConfigTty)r0   rA   r3   isatty)r   r    infor   r   r   r!      s   
zRunOperation.israwc                    s        fdd}t|dS )z
        Returns a tuple of sockets connected to the pty (stdin,stdout,stderr).

        If any of the sockets are not attached in the container, `None` is
        returned in the tuple.
        c              	      s\    d d |   r,jj| ddddji}t|} d d r'|S t|S d S )NrF   z	Attach{0}r*   streamr6   rG   )	format
capitalizer.   attach_socketr/   r6   r>   r@   Demuxer)keysocketrJ   rI   r   r   r   rM      s   

z+RunOperation.sockets.<locals>.attach_socket)r5   r3   r4   )rA   map)r   rM   r   rQ   r   r'      s   
zRunOperation.socketsc                 K      | j j| j||d dS )z-
        resize pty within container
        r%   r&   N)r.   r   r/   r$   r   r   r   r         zRunOperation.resizec                 C   s   | j | jS )zA
        Thin wrapper around client.inspect_container().
        )r.   inspect_containerr/   r   r   r   r   rA      s   zRunOperation._container_info)TNNNNr   )
r   r   r   r   r	   r
   r!   r'   r   rA   r   r   r   r   r(   i   s    

r(   Tc                 C   s   | j ||||d}|S )N)ttyr5   )exec_create)r.   r/   commandr1   exec_idr   r   r   rX      s   rX   c                   @   sL   e Zd ZdZdddZdddZdd	 Zd
d Zdd Zdd Z	dd Z
dS )ExecOperationz7
    class for handling `docker exec`-like command
    TNc                 C   sF   || _ || _d | _|| _|ptj| _|ptj| _|ptj| _d | _d S r   )	rZ   r.   r0   r1   r2   r3   r4   r5   _info)r   r.   rZ   r1   r3   r4   r5   r   r   r   r	      s   
zExecOperation.__init__c                 K   sV   |p|   }g }| jr|tjt| j|dd |tj|t| jdd |S )r#   Fr7   r9   )r'   r1   r=   r>   r?   r@   r5   r3   )r   r'   r    rJ   rE   r   r   r   r
      s   zExecOperation.startc                 K   s$   | j du r| j o|  | _ | j S )z
        Returns True if the PTY should operate in raw mode.

        If the exec was not started with tty=True, this will return False.
        N)r0   r3   rH   is_process_ttyr   r   r   r   r!      s   
zExecOperation.israwc                 C   s6   | j j| jd| jd}t|}|  r|S t|S )zL
        Return a single socket which is processing all I/O to exec
        T)rP   rW   )r.   
exec_startrZ   r1   r>   r@   r]   rN   )r   rP   rJ   r   r   r   r'      s
   

zExecOperation.socketsc                 K   rS   )z1
        resize pty of an execed process
        rT   N)r.   exec_resizerZ   r$   r   r   r   r     rU   zExecOperation.resizec                 C   s   |   d d S )z9
        does execed process have allocated tty?
        ProcessConfigrW   )
_exec_infor   r   r   r   r]     s   zExecOperation.is_process_ttyc                 C   s    | j du r| j| j| _ | j S )z<
        Caching wrapper around client.exec_inspect
        N)r\   r.   exec_inspectrZ   r   r   r   r   ra     s   
zExecOperation._exec_info)TNNNr   )r   r   r   r   r	   r
   r!   r'   r   r]   ra   r   r   r   r   r[      s    


r[   c                   @   s<   e Zd ZdZdd Zdd ZdddZdd	d
Zdd ZdS )PseudoTerminala!  
    Wraps the pseudo-TTY (PTY) allocated to a docker container.

    The PTY is managed via the current process' TTY until it is closed.

    Example:

        import docker
        from dockerpty import PseudoTerminal

        client = docker.Client()
        container = client.create_container(
            image='busybox:latest',
            stdin_open=True,
            tty=True,
            command='/bin/sh',
        )

        # hijacks the current tty until the pty is closed
        PseudoTerminal(client, container).start()

    Care is taken to ensure all file descriptors are restored on exit. For
    example, you can attach to a running container from within a Python REPL
    and when the container exits, the user will be returned to the Python REPL
    without adverse effects.
    c                 C   s   || _ || _dS )r)   N)r.   	operation)r   r.   rd   r   r   r   r	   <  s   
zPseudoTerminal.__init__c                 C   s
   | j  S r   )rd   r'   r   r   r   r   r'   D  s   
zPseudoTerminal.socketsNc                 C   s   | j j|d}dd |D }z0t|  | | W d    n1 s#w   Y  W |r;t||D ]\}}t|| q0d S d S |rQt||D ]\}}t|| qFw w )N)r'   c                 S   s   g | ]}| d qS )F)set_blocking.0pr   r   r   
<listcomp>J      z(PseudoTerminal.start.<locals>.<listcomp>)rd   r
   r   _hijack_ttyzipr>   re   )r   r'   rE   flagspumpflagr   r   r   r
   G  s"   
zPseudoTerminal.startc                 C   s`   | j  sdS |pt| j j}|dur.|\}}z| j j||d W dS  ty-   Y dS w dS )z
        Resize the container's PTY.

        If `size` is not None, it must be a tuple of (height,width), otherwise
        it will be determined by the size of the current TTY.
        NrT   )rd   r!   rW   sizer3   r   IOError)r   rp   rowscolsr   r   r   r   T  s   
zPseudoTerminal.resizec           	      C   s   t j| jj| j d` |   	 dd |D }dd |D }tj||dd\}}z|D ]}|  q-|D ]}|	  q6t
dd |D rHW nW n tyb } zd	|jvrX|W Y d }~nd }~ww qW d    d S 1 sow   Y  d S )
N)r0   Tc                 S   s   g | ]}|j s|qS r   )eofrf   r   r   r   ri   l  rj   z.PseudoTerminal._hijack_tty.<locals>.<listcomp>c                 S   s   g | ]
}|j  r|j qS r   )	to_streamneeds_writerf   r   r   r   ri   m  s    <   )timeoutc                 S   s   g | ]}|  qS r   )is_donerf   r   r   r   ri   w  s    zThe operation did not complete)rW   Terminalrd   r5   r!   r   r>   selectdo_writeflushallr   strerror)	r   rE   
read_pumpswrite_streams
read_readywrite_readywrite_streamrn   er   r   r   rk   h  s.   


"zPseudoTerminal._hijack_ttyr   )	r   r   r   r   r	   r'   r
   r   rk   r   r   r   r   rc      s    

rc   )T)r2   r   r+   sslr   dockerpty.ior>   dockerpty.ttyrW   objectr   r   r(   rX   r[   rc   r   r   r   r   <module>   s   6
fL