Merge pull request #3980 from aanand/shell-out-attach

Attach interactively on Windows by shelling out
This commit is contained in:
Joffrey F 2016-10-19 11:14:36 -07:00 committed by GitHub
commit de15ec835a
3 changed files with 73 additions and 42 deletions

View File

@ -17,6 +17,7 @@ from .utils import call_silently
from .utils import is_docker_for_mac_installed
from .utils import is_mac
from .utils import is_ubuntu
from .utils import is_windows
log = logging.getLogger(__name__)
@ -90,11 +91,7 @@ def exit_with_error(msg):
def get_conn_error_message(url):
if call_silently(['which', 'docker']) != 0:
if is_mac():
return docker_not_found_mac
if is_ubuntu():
return docker_not_found_ubuntu
return docker_not_found_generic
return docker_not_found_msg("Couldn't connect to Docker daemon.")
if is_docker_for_mac_installed():
return conn_error_docker_for_mac
if call_silently(['which', 'docker-machine']) == 0:
@ -102,25 +99,26 @@ def get_conn_error_message(url):
return conn_error_generic.format(url=url)
docker_not_found_mac = """
Couldn't connect to Docker daemon. You might need to install Docker:
https://docs.docker.com/engine/installation/mac/
"""
def docker_not_found_msg(problem):
return "{} You might need to install Docker:\n\n{}".format(
problem, docker_install_url())
docker_not_found_ubuntu = """
Couldn't connect to Docker daemon. You might need to install Docker:
https://docs.docker.com/engine/installation/ubuntulinux/
"""
def docker_install_url():
if is_mac():
return docker_install_url_mac
elif is_ubuntu():
return docker_install_url_ubuntu
elif is_windows():
return docker_install_url_windows
else:
return docker_install_url_generic
docker_not_found_generic = """
Couldn't connect to Docker daemon. You might need to install Docker:
https://docs.docker.com/engine/installation/
"""
docker_install_url_mac = "https://docs.docker.com/engine/installation/mac/"
docker_install_url_ubuntu = "https://docs.docker.com/engine/installation/ubuntulinux/"
docker_install_url_windows = "https://docs.docker.com/engine/installation/windows/"
docker_install_url_generic = "https://docs.docker.com/engine/installation/"
conn_error_docker_machine = """

View File

@ -6,7 +6,9 @@ import contextlib
import functools
import json
import logging
import pipes
import re
import subprocess
import sys
from inspect import getdoc
from operator import attrgetter
@ -406,11 +408,6 @@ class TopLevelCommand(object):
service = self.project.get_service(options['SERVICE'])
detach = options['-d']
if IS_WINDOWS_PLATFORM and not detach:
raise UserError(
"Interactive mode is not yet supported on Windows.\n"
"Please pass the -d flag when using `docker-compose exec`."
)
try:
container = service.get_container(number=index)
except ValueError as e:
@ -418,6 +415,28 @@ class TopLevelCommand(object):
command = [options['COMMAND']] + options['ARGS']
tty = not options["-T"]
if IS_WINDOWS_PLATFORM and not detach:
args = ["exec"]
if options["-d"]:
args += ["--detach"]
else:
args += ["--interactive"]
if not options["-T"]:
args += ["--tty"]
if options["--privileged"]:
args += ["--privileged"]
if options["--user"]:
args += ["--user", options["--user"]]
args += [container.id]
args += command
sys.exit(call_docker(args))
create_exec_options = {
"privileged": options["--privileged"],
"user": options["--user"],
@ -675,12 +694,6 @@ class TopLevelCommand(object):
service = self.project.get_service(options['SERVICE'])
detach = options['-d']
if IS_WINDOWS_PLATFORM and not detach:
raise UserError(
"Interactive mode is not yet supported on Windows.\n"
"Please pass the -d flag when using `docker-compose run`."
)
if options['--publish'] and options['--service-ports']:
raise UserError(
'Service port mapping and manual port mapping '
@ -969,17 +982,20 @@ def run_one_off_container(container_options, project, service, options):
signals.set_signal_handler_to_shutdown()
try:
try:
operation = RunOperation(
project.client,
container.id,
interactive=not options['-T'],
logs=False,
)
pty = PseudoTerminal(project.client, operation)
sockets = pty.sockets()
service.start_container(container)
pty.start(sockets)
exit_code = container.wait()
if IS_WINDOWS_PLATFORM:
exit_code = call_docker(["start", "--attach", "--interactive", container.id])
else:
operation = RunOperation(
project.client,
container.id,
interactive=not options['-T'],
logs=False,
)
pty = PseudoTerminal(project.client, operation)
sockets = pty.sockets()
service.start_container(container)
pty.start(sockets)
exit_code = container.wait()
except signals.ShutdownException:
project.client.stop(container.id)
exit_code = 1
@ -1044,3 +1060,15 @@ def exit_if(condition, message, exit_code):
if condition:
log.error(message)
raise SystemExit(exit_code)
def call_docker(args):
try:
executable_path = subprocess.check_output(["which", "docker"]).strip()
except subprocess.CalledProcessError:
raise UserError(errors.docker_not_found_msg("Couldn't find `docker` binary."))
args = [executable_path] + args
log.debug(" ".join(map(pipes.quote, args)))
return subprocess.call(args)

View File

@ -11,6 +11,7 @@ import sys
import docker
import compose
from ..const import IS_WINDOWS_PLATFORM
# WindowsError is not defined on non-win32 platforms. Avoid runtime errors by
# defining it as OSError (its parent class) if missing.
@ -73,6 +74,10 @@ def is_ubuntu():
return platform.system() == 'Linux' and platform.linux_distribution()[0] == 'Ubuntu'
def is_windows():
return IS_WINDOWS_PLATFORM
def get_version_info(scope):
versioninfo = 'docker-compose version {}, build {}'.format(
compose.__version__,