mirror of
https://github.com/docker/compose.git
synced 2025-07-21 12:44:54 +02:00
Merge pull request #270 from d11wtq/bugfix/tty_size
Use dockerpty instead for pseudo-tty behaviour (fixes TTY size issue #253 & #97)
This commit is contained in:
commit
50c588176c
@ -6,6 +6,7 @@ import re
|
|||||||
import signal
|
import signal
|
||||||
|
|
||||||
from inspect import getdoc
|
from inspect import getdoc
|
||||||
|
import dockerpty
|
||||||
|
|
||||||
from .. import __version__
|
from .. import __version__
|
||||||
from ..project import NoSuchService, ConfigurationError
|
from ..project import NoSuchService, ConfigurationError
|
||||||
@ -18,7 +19,6 @@ from .utils import yesno
|
|||||||
from ..packages.docker.errors import APIError
|
from ..packages.docker.errors import APIError
|
||||||
from .errors import UserError
|
from .errors import UserError
|
||||||
from .docopt_command import NoSuchCommand
|
from .docopt_command import NoSuchCommand
|
||||||
from .socketclient import SocketClient
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -240,9 +240,8 @@ class TopLevelCommand(Command):
|
|||||||
service.start_container(container, ports=None, one_off=True)
|
service.start_container(container, ports=None, one_off=True)
|
||||||
print(container.name)
|
print(container.name)
|
||||||
else:
|
else:
|
||||||
with self._attach_to_container(container.id, raw=tty) as c:
|
|
||||||
service.start_container(container, ports=None, one_off=True)
|
service.start_container(container, ports=None, one_off=True)
|
||||||
c.run()
|
dockerpty.start(self.client, container.id)
|
||||||
exit_code = container.wait()
|
exit_code = container.wait()
|
||||||
if options['--rm']:
|
if options['--rm']:
|
||||||
log.info("Removing %s..." % container.name)
|
log.info("Removing %s..." % container.name)
|
||||||
@ -341,17 +340,5 @@ class TopLevelCommand(Command):
|
|||||||
print("Gracefully stopping... (press Ctrl+C again to force)")
|
print("Gracefully stopping... (press Ctrl+C again to force)")
|
||||||
self.project.stop(service_names=service_names)
|
self.project.stop(service_names=service_names)
|
||||||
|
|
||||||
def _attach_to_container(self, container_id, raw=False):
|
|
||||||
socket_in = self.client.attach_socket(container_id, params={'stdin': 1, 'stream': 1})
|
|
||||||
socket_out = self.client.attach_socket(container_id, params={'stdout': 1, 'logs': 1, 'stream': 1})
|
|
||||||
socket_err = self.client.attach_socket(container_id, params={'stderr': 1, 'logs': 1, 'stream': 1})
|
|
||||||
|
|
||||||
return SocketClient(
|
|
||||||
socket_in=socket_in,
|
|
||||||
socket_out=socket_out,
|
|
||||||
socket_err=socket_err,
|
|
||||||
raw=raw,
|
|
||||||
)
|
|
||||||
|
|
||||||
def list_containers(containers):
|
def list_containers(containers):
|
||||||
return ", ".join(c.name for c in containers)
|
return ", ".join(c.name for c in containers)
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
from __future__ import print_function
|
|
||||||
# Adapted from https://github.com/benthor/remotty/blob/master/socketclient.py
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import tty
|
|
||||||
import fcntl
|
|
||||||
import os
|
|
||||||
import termios
|
|
||||||
import threading
|
|
||||||
import errno
|
|
||||||
|
|
||||||
import logging
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class SocketClient:
|
|
||||||
def __init__(self,
|
|
||||||
socket_in=None,
|
|
||||||
socket_out=None,
|
|
||||||
socket_err=None,
|
|
||||||
raw=True,
|
|
||||||
):
|
|
||||||
self.socket_in = socket_in
|
|
||||||
self.socket_out = socket_out
|
|
||||||
self.socket_err = socket_err
|
|
||||||
self.raw = raw
|
|
||||||
|
|
||||||
self.stdin_fileno = sys.stdin.fileno()
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.create()
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, type, value, trace):
|
|
||||||
self.destroy()
|
|
||||||
|
|
||||||
def create(self):
|
|
||||||
if os.isatty(sys.stdin.fileno()):
|
|
||||||
self.settings = termios.tcgetattr(sys.stdin.fileno())
|
|
||||||
else:
|
|
||||||
self.settings = None
|
|
||||||
|
|
||||||
if self.socket_in is not None:
|
|
||||||
self.set_blocking(sys.stdin, False)
|
|
||||||
self.set_blocking(sys.stdout, True)
|
|
||||||
self.set_blocking(sys.stderr, True)
|
|
||||||
|
|
||||||
if self.raw:
|
|
||||||
tty.setraw(sys.stdin.fileno())
|
|
||||||
|
|
||||||
def set_blocking(self, file, blocking):
|
|
||||||
fd = file.fileno()
|
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
|
||||||
flags = (flags & ~os.O_NONBLOCK) if blocking else (flags | os.O_NONBLOCK)
|
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
if self.socket_in is not None:
|
|
||||||
self.start_background_thread(target=self.send, args=(self.socket_in, sys.stdin))
|
|
||||||
|
|
||||||
recv_threads = []
|
|
||||||
|
|
||||||
if self.socket_out is not None:
|
|
||||||
recv_threads.append(self.start_background_thread(target=self.recv, args=(self.socket_out, sys.stdout)))
|
|
||||||
|
|
||||||
if self.socket_err is not None:
|
|
||||||
recv_threads.append(self.start_background_thread(target=self.recv, args=(self.socket_err, sys.stderr)))
|
|
||||||
|
|
||||||
for t in recv_threads:
|
|
||||||
t.join()
|
|
||||||
|
|
||||||
def start_background_thread(self, **kwargs):
|
|
||||||
thread = threading.Thread(**kwargs)
|
|
||||||
thread.daemon = True
|
|
||||||
thread.start()
|
|
||||||
return thread
|
|
||||||
|
|
||||||
def recv(self, socket, stream):
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
chunk = socket.recv(4096)
|
|
||||||
|
|
||||||
if chunk:
|
|
||||||
stream.write(chunk)
|
|
||||||
stream.flush()
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
log.debug(e)
|
|
||||||
|
|
||||||
def send(self, socket, stream):
|
|
||||||
while True:
|
|
||||||
chunk = stream.read(1)
|
|
||||||
|
|
||||||
if chunk == '':
|
|
||||||
socket.close()
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
socket.send(chunk)
|
|
||||||
except Exception as e:
|
|
||||||
if hasattr(e, 'errno') and e.errno == errno.EPIPE:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def destroy(self):
|
|
||||||
if self.settings is not None:
|
|
||||||
termios.tcsetattr(self.stdin_fileno, termios.TCSADRAIN, self.settings)
|
|
||||||
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import websocket
|
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
sys.stderr.write("Usage: python socketclient.py WEBSOCKET_URL\n")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
url = sys.argv[1]
|
|
||||||
socket = websocket.create_connection(url)
|
|
||||||
|
|
||||||
print("connected\r")
|
|
||||||
|
|
||||||
with SocketClient(socket, interactive=True) as client:
|
|
||||||
client.run()
|
|
@ -3,3 +3,4 @@ PyYAML==3.10
|
|||||||
requests==2.2.1
|
requests==2.2.1
|
||||||
texttable==0.8.1
|
texttable==0.8.1
|
||||||
websocket-client==0.11.0
|
websocket-client==0.11.0
|
||||||
|
dockerpty==0.0.8
|
||||||
|
Loading…
x
Reference in New Issue
Block a user