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

View File

@ -6,7 +6,9 @@ import contextlib
import functools import functools
import json import json
import logging import logging
import pipes
import re import re
import subprocess
import sys import sys
from inspect import getdoc from inspect import getdoc
from operator import attrgetter from operator import attrgetter
@ -406,11 +408,6 @@ class TopLevelCommand(object):
service = self.project.get_service(options['SERVICE']) service = self.project.get_service(options['SERVICE'])
detach = options['-d'] 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: try:
container = service.get_container(number=index) container = service.get_container(number=index)
except ValueError as e: except ValueError as e:
@ -418,6 +415,28 @@ class TopLevelCommand(object):
command = [options['COMMAND']] + options['ARGS'] command = [options['COMMAND']] + options['ARGS']
tty = not options["-T"] 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 = { create_exec_options = {
"privileged": options["--privileged"], "privileged": options["--privileged"],
"user": options["--user"], "user": options["--user"],
@ -675,12 +694,6 @@ class TopLevelCommand(object):
service = self.project.get_service(options['SERVICE']) service = self.project.get_service(options['SERVICE'])
detach = options['-d'] 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']: if options['--publish'] and options['--service-ports']:
raise UserError( raise UserError(
'Service port mapping and manual port mapping ' 'Service port mapping and manual port mapping '
@ -969,6 +982,9 @@ def run_one_off_container(container_options, project, service, options):
signals.set_signal_handler_to_shutdown() signals.set_signal_handler_to_shutdown()
try: try:
try: try:
if IS_WINDOWS_PLATFORM:
exit_code = call_docker(["start", "--attach", "--interactive", container.id])
else:
operation = RunOperation( operation = RunOperation(
project.client, project.client,
container.id, container.id,
@ -1044,3 +1060,15 @@ def exit_if(condition, message, exit_code):
if condition: if condition:
log.error(message) log.error(message)
raise SystemExit(exit_code) 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 docker
import compose import compose
from ..const import IS_WINDOWS_PLATFORM
# WindowsError is not defined on non-win32 platforms. Avoid runtime errors by # WindowsError is not defined on non-win32 platforms. Avoid runtime errors by
# defining it as OSError (its parent class) if missing. # 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' return platform.system() == 'Linux' and platform.linux_distribution()[0] == 'Ubuntu'
def is_windows():
return IS_WINDOWS_PLATFORM
def get_version_info(scope): def get_version_info(scope):
versioninfo = 'docker-compose version {}, build {}'.format( versioninfo = 'docker-compose version {}, build {}'.format(
compose.__version__, compose.__version__,