command.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. from __future__ import absolute_import
  2. from __future__ import unicode_literals
  3. import logging
  4. import os
  5. import re
  6. import six
  7. from requests.exceptions import ConnectionError
  8. from requests.exceptions import SSLError
  9. from . import errors
  10. from . import verbose_proxy
  11. from .. import __version__
  12. from .. import config
  13. from ..project import Project
  14. from ..service import ConfigError
  15. from .docker_client import docker_client
  16. from .docopt_command import DocoptCommand
  17. from .utils import call_silently
  18. from .utils import is_mac
  19. from .utils import is_ubuntu
  20. log = logging.getLogger(__name__)
  21. class Command(DocoptCommand):
  22. base_dir = '.'
  23. def dispatch(self, *args, **kwargs):
  24. try:
  25. super(Command, self).dispatch(*args, **kwargs)
  26. except SSLError as e:
  27. raise errors.UserError('SSL error: %s' % e)
  28. except ConnectionError:
  29. if call_silently(['which', 'docker']) != 0:
  30. if is_mac():
  31. raise errors.DockerNotFoundMac()
  32. elif is_ubuntu():
  33. raise errors.DockerNotFoundUbuntu()
  34. else:
  35. raise errors.DockerNotFoundGeneric()
  36. elif call_silently(['which', 'boot2docker']) == 0:
  37. raise errors.ConnectionErrorBoot2Docker()
  38. else:
  39. raise errors.ConnectionErrorGeneric(self.get_client().base_url)
  40. def perform_command(self, options, handler, command_options):
  41. if options['COMMAND'] in ('help', 'version'):
  42. # Skip looking up the compose file.
  43. handler(None, command_options)
  44. return
  45. if 'FIG_FILE' in os.environ:
  46. log.warn('The FIG_FILE environment variable is deprecated.')
  47. log.warn('Please use COMPOSE_FILE instead.')
  48. explicit_config_path = (
  49. options.get('--file') or
  50. os.environ.get('COMPOSE_FILE') or
  51. os.environ.get('FIG_FILE'))
  52. project = get_project(
  53. self.base_dir,
  54. explicit_config_path,
  55. project_name=options.get('--project-name'),
  56. verbose=options.get('--verbose'))
  57. handler(project, command_options)
  58. def get_client(verbose=False):
  59. client = docker_client()
  60. if verbose:
  61. version_info = six.iteritems(client.version())
  62. log.info("Compose version %s", __version__)
  63. log.info("Docker base_url: %s", client.base_url)
  64. log.info("Docker version: %s",
  65. ", ".join("%s=%s" % item for item in version_info))
  66. return verbose_proxy.VerboseProxy('docker', client)
  67. return client
  68. def get_project(base_dir, config_path=None, project_name=None, verbose=False):
  69. config_details = config.find(base_dir, config_path)
  70. try:
  71. return Project.from_dicts(
  72. get_project_name(config_details.working_dir, project_name),
  73. config.load(config_details),
  74. get_client(verbose=verbose))
  75. except ConfigError as e:
  76. raise errors.UserError(six.text_type(e))
  77. def get_project_name(working_dir, project_name=None):
  78. def normalize_name(name):
  79. return re.sub(r'[^a-z0-9]', '', name.lower())
  80. if 'FIG_PROJECT_NAME' in os.environ:
  81. log.warn('The FIG_PROJECT_NAME environment variable is deprecated.')
  82. log.warn('Please use COMPOSE_PROJECT_NAME instead.')
  83. project_name = (
  84. project_name or
  85. os.environ.get('COMPOSE_PROJECT_NAME') or
  86. os.environ.get('FIG_PROJECT_NAME'))
  87. if project_name is not None:
  88. return normalize_name(project_name)
  89. project = os.path.basename(os.path.abspath(working_dir))
  90. if project:
  91. return normalize_name(project)
  92. return 'default'