command.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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 .formatter import Formatter
  15. from .utils import cached_property, docker_url, call_silently, is_mac, is_ubuntu
  16. from . import errors
  17. log = logging.getLogger(__name__)
  18. class Command(DocoptCommand):
  19. base_dir = '.'
  20. def __init__(self):
  21. self._yaml_path = os.environ.get('FIG_FILE', None)
  22. self.explicit_project_name = None
  23. def dispatch(self, *args, **kwargs):
  24. try:
  25. super(Command, self).dispatch(*args, **kwargs)
  26. except ConnectionError:
  27. if call_silently(['which', 'docker']) != 0:
  28. if is_mac():
  29. raise errors.DockerNotFoundMac()
  30. elif is_ubuntu():
  31. raise errors.DockerNotFoundUbuntu()
  32. else:
  33. raise errors.DockerNotFoundGeneric()
  34. elif call_silently(['which', 'docker-osx']) == 0:
  35. raise errors.ConnectionErrorDockerOSX()
  36. else:
  37. raise errors.ConnectionErrorGeneric(self.client.base_url)
  38. def perform_command(self, options, *args, **kwargs):
  39. if options['--file'] is not None:
  40. self.yaml_path = os.path.join(self.base_dir, options['--file'])
  41. if options['--project-name'] is not None:
  42. self.explicit_project_name = options['--project-name']
  43. return super(Command, self).perform_command(options, *args, **kwargs)
  44. @cached_property
  45. def client(self):
  46. return Client(docker_url())
  47. @cached_property
  48. def project(self):
  49. try:
  50. config = yaml.safe_load(open(self.yaml_path))
  51. except IOError as e:
  52. if e.errno == errno.ENOENT:
  53. raise errors.FigFileNotFound(os.path.basename(e.filename))
  54. raise errors.UserError(six.text_type(e))
  55. try:
  56. return Project.from_config(self.project_name, config, self.client)
  57. except ConfigError as e:
  58. raise errors.UserError(six.text_type(e))
  59. @cached_property
  60. def project_name(self):
  61. project = os.path.basename(os.path.dirname(os.path.abspath(self.yaml_path)))
  62. if self.explicit_project_name is not None:
  63. project = self.explicit_project_name
  64. project = re.sub(r'[^a-zA-Z0-9]', '', project)
  65. if not project:
  66. project = 'default'
  67. return project
  68. @cached_property
  69. def formatter(self):
  70. return Formatter()
  71. @cached_property
  72. def yaml_path(self):
  73. if self._yaml_path is not None:
  74. return self._yaml_path
  75. elif os.path.exists(os.path.join(self.base_dir, 'fig.yaml')):
  76. log.warning("Fig just read the file 'fig.yaml' on startup, rather than 'fig.yml'")
  77. log.warning("Please be aware that fig.yml the expected extension in most cases, and using .yaml can cause compatibility issues in future")
  78. return os.path.join(self.base_dir, 'fig.yaml')
  79. else:
  80. return os.path.join(self.base_dir, 'fig.yml')
  81. @yaml_path.setter
  82. def yaml_path(self, value):
  83. self._yaml_path = value