U
    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 N)signalSIGWINCHr   resize)Z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k	rttj| j  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   s
   t  dS )z3
        are we dealing with a tty or not?
        NNotImplementedErrorr   kwargsr   r   r   israwR   s    zOperation.israwc                 K   s
   t  dS )!
        start execution
        Nr   r   r   r   r   r
   X   s    zOperation.startc                 K   s
   t  dS )z0
        if we have terminal, resize it
        Nr   r   heightwidthr   r   r   r   r   ^   s    zOperation.resizec                 C   s
   t  dS )zReturn sockets for streams.Nr   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krt dt d}|| _|| _d| _|| _|p8tj| _|pDtj	| _	|pPt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,   r.   r0   r1   r2   r3   r   r   r   r	   n   s    zRunOperation.__init__c                 K   s   |p
|   \}}}g }|r>| jr>|tjt| j|dd |r`|tj|t| jdd |r|tj|t| jdd | 	 d d s| j
j| jf| |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Zwait_for_outputZpropagate_closeStateZRunning)r$   r.   appendioPumpStreamr2   r0   r1   _container_infor+   r
   r,   )r   r$   r   Z	pty_stdinZ
pty_stdoutZ
pty_stderrpumpsr   r   r   r
      s    
zRunOperation.startc                 K   s0   | j dk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)r-   r;   r0   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              	      sb    d d |   rZjj| ddddji}t|} d d rN|S t|S nd S d S )Nr=   z	Attach{0}r'   streamr3   r>   )	format
capitalizer+   attach_socketr,   r3   r8   r:   Demuxer)keysocketrA   r@   r   r   r   rD      s    
z+RunOperation.sockets.<locals>.attach_socket)r2   r0   r1   )r;   map)r   rD   r   rH   r   r$      s    zRunOperation.socketsc                 K   s   | j j| j||d dS )z-
        resize pty within container
        r"   r#   N)r+   r   r,   r!   r   r   r   r      s    zRunOperation.resizec                 C   s   | j | jS )zA
        Thin wrapper around client.inspect_container().
        )r+   Zinspect_containerr,   r   r   r   r   r;      s    zRunOperation._container_info)TNNNN)N)
r   r   r   r   r	   r
   r   r$   r   r;   r   r   r   r   r%   i   s   

r%   Tc                 C   s   | j ||||d}|S )N)ttyr2   )exec_create)r+   r,   Zcommandr.   exec_idr   r   r   rL      s    rL   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| _|p8tj| _d | _d S r   )	rM   r+   r-   r.   r/   r0   r1   r2   _info)r   r+   rM   r.   r0   r1   r2   r   r   r   r	      s    zExecOperation.__init__c                 K   sV   |p
|   }g }| jr4|tjt| j|dd |tj|t| jdd |S )r    Fr4   r5   )r$   r.   r7   r8   r9   r:   r2   r0   )r   r$   r   rA   r<   r   r   r   r
      s    zExecOperation.startc                 K   s$   | j dk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)r-   r0   r?   is_process_ttyr   r   r   r   r      s    
zExecOperation.israwc                 C   s:   | j j| jd| jd}t|}|  r,|S t|S dS )zL
        Return a single socket which is processing all I/O to exec
        T)rG   rK   N)r+   Z
exec_startrM   r.   r8   r:   rP   rE   )r   rG   rA   r   r   r   r$      s
    
zExecOperation.socketsc                 K   s   | j j| j||d dS )z1
        resize pty of an execed process
        rJ   N)r+   Zexec_resizerM   r!   r   r   r   r     s    zExecOperation.resizec                 C   s   |   d d S )z9
        does execed process have allocated tty?
        ZProcessConfigrK   )
_exec_infor   r   r   r   rP     s    zExecOperation.is_process_ttyc                 C   s    | j dkr| j| j| _ | j S )z<
        Caching wrapper around client.exec_inspect
        N)rO   r+   Zexec_inspectrM   r   r   r   r   rQ     s    
zExecOperation._exec_info)TNNN)N)r   r   r   r   r	   r
   r   r$   r   rP   rQ   r   r   r   r   rN      s   


rN   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+   rS   r   r   r   r	   <  s    zPseudoTerminal.__init__c                 C   s
   | j  S r   )rS   r$   r   r   r   r   r$   D  s    zPseudoTerminal.socketsNc                 C   sj   | j j|d}dd |D }z"t|  | | W 5 Q R X W 5 |rdt||D ]\}}t|| qNX d S )N)r$   c                 S   s   g | ]}| d qS )F)set_blocking.0pr   r   r   
<listcomp>J  s     z(PseudoTerminal.start.<locals>.<listcomp>)rS   r
   zipr8   rT   r   _hijack_tty)r   r$   r<   flagspumpflagr   r   r   r
   G  s    
zPseudoTerminal.startc                 C   s^   | j  sdS |pt| j j}|dk	rZ|\}}z| j j||d W n tk
rX   Y nX 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.
        NrJ   )rS   r   rK   sizer0   r   IOError)r   r^   ZrowsZ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 ]}|  qX|D ]}|	  qjt
dd |D rW qW q" tk
r } zd|jkr|W 5 d }~X Y q"X q"W 5 Q R X d S )	N)r-   c                 S   s   g | ]}|j s|qS r   )eofrU   r   r   r   rX   l  s      z.PseudoTerminal._hijack_tty.<locals>.<listcomp>c                 S   s   g | ]}|j  r|j qS r   )Z	to_streamZneeds_writerU   r   r   r   rX   m  s     
 <   )Ztimeoutc                 S   s   g | ]}|  qS r   )Zis_donerU   r   r   r   rX   w  s     zThe operation did not complete)rK   ZTerminalrS   r2   r   r   r8   ZselectZdo_writeflushallr   strerror)	r   r<   Z
read_pumpsZwrite_streamsZ
read_readyZwrite_readyZwrite_streamr\   er   r   r   rZ   h  s    


zPseudoTerminal._hijack_tty)N)N)	r   r   r   r   r	   r$   r
   r   rZ   r   r   r   r   rR      s   

rR   )T)r/   r   r(   Zsslr   Zdockerpty.ior8   Zdockerpty.ttyrK   objectr   r   r%   rL   rN   rR   r   r   r   r   <module>   s   6f
L