command.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. from __future__ import unicode_literals
  2. from __future__ import absolute_import
  3. from ..packages.docker import Client
  4. from requests.exceptions import ConnectionError
  5. import errno
  6. import logging
  7. import os
  8. import re
  9. import yaml
  10. from ..packages import six
  11. from ..project import Project
  12. from ..service import ConfigError
  13. from .docopt_command import DocoptCommand
  14. from .utils import docker_url, call_silently, is_mac, is_ubuntu
  15. from . import verbose_proxy
  16. from . import errors
  17. from .. import __version__
  18. log = logging.getLogger(__name__)
  19. class Command(DocoptCommand):
  20. base_dir = '.'
  21. def dispatch(self, *args, **kwargs):
  22. try:
  23. super(Command, self).dispatch(*args, **kwargs)
  24. except ConnectionError:
  25. if call_silently(['which', 'docker']) != 0:
  26. if is_mac():
  27. raise errors.DockerNotFoundMac()
  28. elif is_ubuntu():
  29. raise errors.DockerNotFoundUbuntu()
  30. else:
  31. raise errors.DockerNotFoundGeneric()
  32. elif call_silently(['which', 'docker-osx']) == 0:
  33. raise errors.ConnectionErrorDockerOSX()
  34. else:
  35. raise errors.ConnectionErrorGeneric(self.get_client().base_url)
  36. def perform_command(self, options, handler, command_options):
  37. explicit_config_path = options.get('--file') or os.environ.get('FIG_FILE')
  38. project = self.get_project(
  39. self.get_config_path(explicit_config_path),
  40. project_name=options.get('--project-name'),
  41. verbose=options.get('--verbose'))
  42. handler(project, command_options)
  43. def get_client(self, verbose=False):
  44. client = Client(docker_url())
  45. if verbose:
  46. version_info = six.iteritems(client.version())
  47. log.info("Fig version %s", __version__)
  48. log.info("Docker base_url: %s", client.base_url)
  49. log.info("Docker version: %s",
  50. ", ".join("%s=%s" % item for item in version_info))
  51. return verbose_proxy.VerboseProxy('docker', client)
  52. return client
  53. def get_config(self, config_path):
  54. try:
  55. with open(config_path, 'r') as fh:
  56. return yaml.safe_load(fh)
  57. except IOError as e:
  58. if e.errno == errno.ENOENT:
  59. raise errors.FigFileNotFound(os.path.basename(e.filename))
  60. raise errors.UserError(six.text_type(e))
  61. def get_project(self, config_path, project_name=None, verbose=False):
  62. try:
  63. return Project.from_config(
  64. self.get_project_name(config_path, project_name),
  65. self.get_config(config_path),
  66. self.get_client(verbose=verbose))
  67. except ConfigError as e:
  68. raise errors.UserError(six.text_type(e))
  69. def get_project_name(self, config_path, project_name=None):
  70. def normalize_name(name):
  71. return re.sub(r'[^a-zA-Z0-9]', '', name)
  72. if project_name is not None:
  73. return normalize_name(project_name)
  74. project = os.path.basename(os.path.dirname(os.path.abspath(config_path)))
  75. if project:
  76. return normalize_name(project)
  77. return 'default'
  78. def get_config_path(self, file_path=None):
  79. if file_path:
  80. return os.path.join(self.base_dir, file_path)
  81. if os.path.exists(os.path.join(self.base_dir, 'fig.yaml')):
  82. log.warning("Fig just read the file 'fig.yaml' on startup, rather "
  83. "than 'fig.yml'")
  84. log.warning("Please be aware that fig.yml the expected extension "
  85. "in most cases, and using .yaml can cause compatibility "
  86. "issues in future")
  87. return os.path.join(self.base_dir, 'fig.yaml')
  88. return os.path.join(self.base_dir, 'fig.yml')