From 3770aac1afac24793a68cd8aa6ce2699aaed8fc5 Mon Sep 17 00:00:00 2001 From: Chris Corbyn Date: Wed, 25 Jun 2014 13:54:57 +0000 Subject: [PATCH] Use dockerpty instead for pseudo-tty behaviour. Signed-off-by: Chris Corbyn --- fig/cli/main.py | 19 +----- fig/cli/socketclient.py | 126 ---------------------------------------- requirements.txt | 1 + 3 files changed, 4 insertions(+), 142 deletions(-) delete mode 100644 fig/cli/socketclient.py diff --git a/fig/cli/main.py b/fig/cli/main.py index 9e4e46699..fdac8a2f8 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -6,6 +6,7 @@ import re import signal from inspect import getdoc +import dockerpty from .. import __version__ from ..project import NoSuchService, ConfigurationError @@ -18,7 +19,6 @@ from .utils import yesno from ..packages.docker.errors import APIError from .errors import UserError from .docopt_command import NoSuchCommand -from .socketclient import SocketClient log = logging.getLogger(__name__) @@ -240,9 +240,8 @@ class TopLevelCommand(Command): service.start_container(container, ports=None, one_off=True) print(container.name) else: - with self._attach_to_container(container.id, raw=tty) as c: - service.start_container(container, ports=None, one_off=True) - c.run() + service.start_container(container, ports=None, one_off=True) + dockerpty.start(self.client, container.id) exit_code = container.wait() if options['--rm']: log.info("Removing %s..." % container.name) @@ -341,17 +340,5 @@ class TopLevelCommand(Command): print("Gracefully stopping... (press Ctrl+C again to force)") 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): return ", ".join(c.name for c in containers) diff --git a/fig/cli/socketclient.py b/fig/cli/socketclient.py deleted file mode 100644 index 6cc1f2c57..000000000 --- a/fig/cli/socketclient.py +++ /dev/null @@ -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() diff --git a/requirements.txt b/requirements.txt index bec418117..4eea6cd34 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ PyYAML==3.10 requests==2.2.1 texttable==0.8.1 websocket-client==0.11.0 +dockerpty==0.0.8