mirror of
				https://github.com/docker/compose.git
				synced 2025-10-30 18:53:51 +01:00 
			
		
		
		
	Support reading config from stdin.
Signed-off-by: Daniel Nephin <dnephin@gmail.com>
This commit is contained in:
		
							parent
							
								
									cd2cdb25e3
								
							
						
					
					
						commit
						ae96fc0071
					
				| @ -10,7 +10,7 @@ from .. import config | |||||||
| from ..project import Project | from ..project import Project | ||||||
| from ..service import ConfigError | from ..service import ConfigError | ||||||
| from .docopt_command import DocoptCommand | from .docopt_command import DocoptCommand | ||||||
| from .utils import call_silently, is_mac, is_ubuntu, find_candidates_in_parent_dirs | from .utils import call_silently, is_mac, is_ubuntu | ||||||
| from .docker_client import docker_client | from .docker_client import docker_client | ||||||
| from . import verbose_proxy | from . import verbose_proxy | ||||||
| from . import errors | from . import errors | ||||||
| @ -18,13 +18,6 @@ from .. import __version__ | |||||||
| 
 | 
 | ||||||
| log = logging.getLogger(__name__) | log = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
| SUPPORTED_FILENAMES = [ |  | ||||||
|     'docker-compose.yml', |  | ||||||
|     'docker-compose.yaml', |  | ||||||
|     'fig.yml', |  | ||||||
|     'fig.yaml', |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class Command(DocoptCommand): | class Command(DocoptCommand): | ||||||
|     base_dir = '.' |     base_dir = '.' | ||||||
| @ -59,7 +52,7 @@ class Command(DocoptCommand): | |||||||
| 
 | 
 | ||||||
|         explicit_config_path = options.get('--file') or os.environ.get('COMPOSE_FILE') or os.environ.get('FIG_FILE') |         explicit_config_path = options.get('--file') or os.environ.get('COMPOSE_FILE') or os.environ.get('FIG_FILE') | ||||||
|         project = self.get_project( |         project = self.get_project( | ||||||
|             self.get_config_path(explicit_config_path), |             explicit_config_path, | ||||||
|             project_name=options.get('--project-name'), |             project_name=options.get('--project-name'), | ||||||
|             verbose=options.get('--verbose')) |             verbose=options.get('--verbose')) | ||||||
| 
 | 
 | ||||||
| @ -76,16 +69,18 @@ class Command(DocoptCommand): | |||||||
|             return verbose_proxy.VerboseProxy('docker', client) |             return verbose_proxy.VerboseProxy('docker', client) | ||||||
|         return client |         return client | ||||||
| 
 | 
 | ||||||
|     def get_project(self, config_path, project_name=None, verbose=False): |     def get_project(self, config_path=None, project_name=None, verbose=False): | ||||||
|  |         config_details = config.find(self.base_dir, config_path) | ||||||
|  | 
 | ||||||
|         try: |         try: | ||||||
|             return Project.from_dicts( |             return Project.from_dicts( | ||||||
|                 self.get_project_name(config_path, project_name), |                 self.get_project_name(config_details.working_dir, project_name), | ||||||
|                 config.load(config_path), |                 config.load(config_details), | ||||||
|                 self.get_client(verbose=verbose)) |                 self.get_client(verbose=verbose)) | ||||||
|         except ConfigError as e: |         except ConfigError as e: | ||||||
|             raise errors.UserError(six.text_type(e)) |             raise errors.UserError(six.text_type(e)) | ||||||
| 
 | 
 | ||||||
|     def get_project_name(self, config_path, project_name=None): |     def get_project_name(self, working_dir, project_name=None): | ||||||
|         def normalize_name(name): |         def normalize_name(name): | ||||||
|             return re.sub(r'[^a-z0-9]', '', name.lower()) |             return re.sub(r'[^a-z0-9]', '', name.lower()) | ||||||
| 
 | 
 | ||||||
| @ -93,38 +88,15 @@ class Command(DocoptCommand): | |||||||
|             log.warn('The FIG_PROJECT_NAME environment variable is deprecated.') |             log.warn('The FIG_PROJECT_NAME environment variable is deprecated.') | ||||||
|             log.warn('Please use COMPOSE_PROJECT_NAME instead.') |             log.warn('Please use COMPOSE_PROJECT_NAME instead.') | ||||||
| 
 | 
 | ||||||
|         project_name = project_name or os.environ.get('COMPOSE_PROJECT_NAME') or os.environ.get('FIG_PROJECT_NAME') |         project_name = ( | ||||||
|  |             project_name or | ||||||
|  |             os.environ.get('COMPOSE_PROJECT_NAME') or | ||||||
|  |             os.environ.get('FIG_PROJECT_NAME')) | ||||||
|         if project_name is not None: |         if project_name is not None: | ||||||
|             return normalize_name(project_name) |             return normalize_name(project_name) | ||||||
| 
 | 
 | ||||||
|         project = os.path.basename(os.path.dirname(os.path.abspath(config_path))) |         project = os.path.basename(os.path.abspath(working_dir)) | ||||||
|         if project: |         if project: | ||||||
|             return normalize_name(project) |             return normalize_name(project) | ||||||
| 
 | 
 | ||||||
|         return 'default' |         return 'default' | ||||||
| 
 |  | ||||||
|     def get_config_path(self, file_path=None): |  | ||||||
|         if file_path: |  | ||||||
|             return os.path.join(self.base_dir, file_path) |  | ||||||
| 
 |  | ||||||
|         (candidates, path) = find_candidates_in_parent_dirs(SUPPORTED_FILENAMES, self.base_dir) |  | ||||||
| 
 |  | ||||||
|         if len(candidates) == 0: |  | ||||||
|             raise errors.ComposeFileNotFound(SUPPORTED_FILENAMES) |  | ||||||
| 
 |  | ||||||
|         winner = candidates[0] |  | ||||||
| 
 |  | ||||||
|         if len(candidates) > 1: |  | ||||||
|             log.warning("Found multiple config files with supported names: %s", ", ".join(candidates)) |  | ||||||
|             log.warning("Using %s\n", winner) |  | ||||||
| 
 |  | ||||||
|         if winner == 'docker-compose.yaml': |  | ||||||
|             log.warning("Please be aware that .yml is the expected extension " |  | ||||||
|                         "in most cases, and using .yaml can cause compatibility " |  | ||||||
|                         "issues in future.\n") |  | ||||||
| 
 |  | ||||||
|         if winner.startswith("fig."): |  | ||||||
|             log.warning("%s is deprecated and will not be supported in future. " |  | ||||||
|                         "Please rename your config file to docker-compose.yml\n" % winner) |  | ||||||
| 
 |  | ||||||
|         return os.path.join(path, winner) |  | ||||||
|  | |||||||
| @ -53,12 +53,3 @@ class ConnectionErrorGeneric(UserError): | |||||||
| 
 | 
 | ||||||
|         If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable. |         If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable. | ||||||
|         """ % url) |         """ % url) | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class ComposeFileNotFound(UserError): |  | ||||||
|     def __init__(self, supported_filenames): |  | ||||||
|         super(ComposeFileNotFound, self).__init__(""" |  | ||||||
|         Can't find a suitable configuration file in this directory or any parent. Are you in the right directory? |  | ||||||
| 
 |  | ||||||
|         Supported filenames: %s |  | ||||||
|         """ % ", ".join(supported_filenames)) |  | ||||||
|  | |||||||
| @ -1,7 +1,13 @@ | |||||||
|  | import logging | ||||||
| import os | import os | ||||||
|  | import sys | ||||||
| import yaml | import yaml | ||||||
|  | from collections import namedtuple | ||||||
|  | 
 | ||||||
| import six | import six | ||||||
| 
 | 
 | ||||||
|  | from compose.cli.utils import find_candidates_in_parent_dirs | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| DOCKER_CONFIG_KEYS = [ | DOCKER_CONFIG_KEYS = [ | ||||||
|     'cap_add', |     'cap_add', | ||||||
| @ -64,12 +70,57 @@ DOCKER_CONFIG_HINTS = { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def load(filename): | SUPPORTED_FILENAMES = [ | ||||||
|     working_dir = os.path.dirname(filename) |     'docker-compose.yml', | ||||||
|     return from_dictionary(load_yaml(filename), working_dir=working_dir, filename=filename) |     'docker-compose.yaml', | ||||||
|  |     'fig.yml', | ||||||
|  |     'fig.yaml', | ||||||
|  | ] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def from_dictionary(dictionary, working_dir=None, filename=None): | log = logging.getLogger(__name__) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ConfigDetails = namedtuple('ConfigDetails', 'config working_dir filename') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def find(base_dir, filename): | ||||||
|  |     if filename == '-': | ||||||
|  |         return ConfigDetails(yaml.safe_load(sys.stdin), os.getcwd(), None) | ||||||
|  | 
 | ||||||
|  |     if filename: | ||||||
|  |         filename = os.path.join(base_dir, filename) | ||||||
|  |     else: | ||||||
|  |         filename = get_config_path(base_dir) | ||||||
|  |     return ConfigDetails(load_yaml(filename), os.path.dirname(filename), filename) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_config_path(base_dir): | ||||||
|  |     (candidates, path) = find_candidates_in_parent_dirs(SUPPORTED_FILENAMES, base_dir) | ||||||
|  | 
 | ||||||
|  |     if len(candidates) == 0: | ||||||
|  |         raise ComposeFileNotFound(SUPPORTED_FILENAMES) | ||||||
|  | 
 | ||||||
|  |     winner = candidates[0] | ||||||
|  | 
 | ||||||
|  |     if len(candidates) > 1: | ||||||
|  |         log.warn("Found multiple config files with supported names: %s", ", ".join(candidates)) | ||||||
|  |         log.warn("Using %s\n", winner) | ||||||
|  | 
 | ||||||
|  |     if winner == 'docker-compose.yaml': | ||||||
|  |         log.warn("Please be aware that .yml is the expected extension " | ||||||
|  |                  "in most cases, and using .yaml can cause compatibility " | ||||||
|  |                  "issues in future.\n") | ||||||
|  | 
 | ||||||
|  |     if winner.startswith("fig."): | ||||||
|  |         log.warn("%s is deprecated and will not be supported in future. " | ||||||
|  |                  "Please rename your config file to docker-compose.yml\n" % winner) | ||||||
|  | 
 | ||||||
|  |     return os.path.join(path, winner) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def load(config_details): | ||||||
|  |     dictionary, working_dir, filename = config_details | ||||||
|     service_dicts = [] |     service_dicts = [] | ||||||
| 
 | 
 | ||||||
|     for service_name, service_dict in list(dictionary.items()): |     for service_name, service_dict in list(dictionary.items()): | ||||||
| @ -488,3 +539,12 @@ class CircularReference(ConfigurationError): | |||||||
|             for (filename, service_name) in self.trail |             for (filename, service_name) in self.trail | ||||||
|         ] |         ] | ||||||
|         return "Circular reference:\n  {}".format("\n  extends ".join(lines)) |         return "Circular reference:\n  {}".format("\n  extends ".join(lines)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ComposeFileNotFound(ConfigurationError): | ||||||
|  |     def __init__(self, supported_filenames): | ||||||
|  |         super(ComposeFileNotFound, self).__init__(""" | ||||||
|  |         Can't find a suitable configuration file in this directory or any parent. Are you in the right directory? | ||||||
|  | 
 | ||||||
|  |         Supported filenames: %s | ||||||
|  |         """ % ", ".join(supported_filenames)) | ||||||
|  | |||||||
| @ -153,6 +153,9 @@ By default, if there are existing containers for a service, `docker-compose up` | |||||||
|  for `docker-compose.yml` in the current working directory, and then each parent |  for `docker-compose.yml` in the current working directory, and then each parent | ||||||
|  directory successively, until found. |  directory successively, until found. | ||||||
| 
 | 
 | ||||||
|  |  Use a `-` as the filename to read configuration from stdin. When stdin is used | ||||||
|  |  all paths in the configuration will be relative to the current working | ||||||
|  |  directory. | ||||||
| 
 | 
 | ||||||
| ### -p, --project-name NAME | ### -p, --project-name NAME | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ class CLITestCase(DockerClientTestCase): | |||||||
|         if hasattr(self, '_project'): |         if hasattr(self, '_project'): | ||||||
|             return self._project |             return self._project | ||||||
| 
 | 
 | ||||||
|         return self.command.get_project(self.command.get_config_path()) |         return self.command.get_project() | ||||||
| 
 | 
 | ||||||
|     def test_help(self): |     def test_help(self): | ||||||
|         old_base_dir = self.command.base_dir |         old_base_dir = self.command.base_dir | ||||||
|  | |||||||
| @ -7,6 +7,10 @@ from compose.container import Container | |||||||
| from .testcases import DockerClientTestCase | from .testcases import DockerClientTestCase | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def build_service_dicts(service_config): | ||||||
|  |     return config.load(config.ConfigDetails(service_config, 'working_dir', None)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class ProjectTest(DockerClientTestCase): | class ProjectTest(DockerClientTestCase): | ||||||
| 
 | 
 | ||||||
|     def test_containers(self): |     def test_containers(self): | ||||||
| @ -32,7 +36,7 @@ class ProjectTest(DockerClientTestCase): | |||||||
|             ['composetest_web_1']) |             ['composetest_web_1']) | ||||||
| 
 | 
 | ||||||
|     def test_volumes_from_service(self): |     def test_volumes_from_service(self): | ||||||
|         service_dicts = config.from_dictionary({ |         service_dicts = build_service_dicts({ | ||||||
|             'data': { |             'data': { | ||||||
|                 'image': 'busybox:latest', |                 'image': 'busybox:latest', | ||||||
|                 'volumes': ['/var/data'], |                 'volumes': ['/var/data'], | ||||||
| @ -41,7 +45,7 @@ class ProjectTest(DockerClientTestCase): | |||||||
|                 'image': 'busybox:latest', |                 'image': 'busybox:latest', | ||||||
|                 'volumes_from': ['data'], |                 'volumes_from': ['data'], | ||||||
|             }, |             }, | ||||||
|         }, working_dir='.') |         }) | ||||||
|         project = Project.from_dicts( |         project = Project.from_dicts( | ||||||
|             name='composetest', |             name='composetest', | ||||||
|             service_dicts=service_dicts, |             service_dicts=service_dicts, | ||||||
| @ -61,7 +65,7 @@ class ProjectTest(DockerClientTestCase): | |||||||
|         ) |         ) | ||||||
|         project = Project.from_dicts( |         project = Project.from_dicts( | ||||||
|             name='composetest', |             name='composetest', | ||||||
|             service_dicts=config.from_dictionary({ |             service_dicts=build_service_dicts({ | ||||||
|                 'db': { |                 'db': { | ||||||
|                     'image': 'busybox:latest', |                     'image': 'busybox:latest', | ||||||
|                     'volumes_from': ['composetest_data_container'], |                     'volumes_from': ['composetest_data_container'], | ||||||
| @ -75,7 +79,7 @@ class ProjectTest(DockerClientTestCase): | |||||||
|     def test_net_from_service(self): |     def test_net_from_service(self): | ||||||
|         project = Project.from_dicts( |         project = Project.from_dicts( | ||||||
|             name='composetest', |             name='composetest', | ||||||
|             service_dicts=config.from_dictionary({ |             service_dicts=build_service_dicts({ | ||||||
|                 'net': { |                 'net': { | ||||||
|                     'image': 'busybox:latest', |                     'image': 'busybox:latest', | ||||||
|                     'command': ["top"] |                     'command': ["top"] | ||||||
| @ -107,7 +111,7 @@ class ProjectTest(DockerClientTestCase): | |||||||
| 
 | 
 | ||||||
|         project = Project.from_dicts( |         project = Project.from_dicts( | ||||||
|             name='composetest', |             name='composetest', | ||||||
|             service_dicts=config.from_dictionary({ |             service_dicts=build_service_dicts({ | ||||||
|                 'web': { |                 'web': { | ||||||
|                     'image': 'busybox:latest', |                     'image': 'busybox:latest', | ||||||
|                     'net': 'container:composetest_net_container' |                     'net': 'container:composetest_net_container' | ||||||
| @ -274,7 +278,7 @@ class ProjectTest(DockerClientTestCase): | |||||||
|     def test_project_up_starts_depends(self): |     def test_project_up_starts_depends(self): | ||||||
|         project = Project.from_dicts( |         project = Project.from_dicts( | ||||||
|             name='composetest', |             name='composetest', | ||||||
|             service_dicts=config.from_dictionary({ |             service_dicts=build_service_dicts({ | ||||||
|                 'console': { |                 'console': { | ||||||
|                     'image': 'busybox:latest', |                     'image': 'busybox:latest', | ||||||
|                     'command': ["top"], |                     'command': ["top"], | ||||||
| @ -309,7 +313,7 @@ class ProjectTest(DockerClientTestCase): | |||||||
|     def test_project_up_with_no_deps(self): |     def test_project_up_with_no_deps(self): | ||||||
|         project = Project.from_dicts( |         project = Project.from_dicts( | ||||||
|             name='composetest', |             name='composetest', | ||||||
|             service_dicts=config.from_dictionary({ |             service_dicts=build_service_dicts({ | ||||||
|                 'console': { |                 'console': { | ||||||
|                     'image': 'busybox:latest', |                     'image': 'busybox:latest', | ||||||
|                     'command': ["top"], |                     'command': ["top"], | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ class ProjectTestCase(DockerClientTestCase): | |||||||
|         return Project.from_dicts( |         return Project.from_dicts( | ||||||
|             name='composetest', |             name='composetest', | ||||||
|             client=self.client, |             client=self.client, | ||||||
|             service_dicts=config.from_dictionary(cfg), |             service_dicts=config.load(config.ConfigDetails(cfg, 'working_dir', None)) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,17 +2,14 @@ from __future__ import unicode_literals | |||||||
| from __future__ import absolute_import | from __future__ import absolute_import | ||||||
| import logging | import logging | ||||||
| import os | import os | ||||||
| import tempfile |  | ||||||
| import shutil |  | ||||||
| from .. import unittest | from .. import unittest | ||||||
| 
 | 
 | ||||||
| import docker | import docker | ||||||
| import mock | import mock | ||||||
| 
 | 
 | ||||||
| from compose.cli import main | from compose.cli import main | ||||||
| from compose.cli.main import TopLevelCommand |  | ||||||
| from compose.cli.docopt_command import NoSuchCommand | from compose.cli.docopt_command import NoSuchCommand | ||||||
| from compose.cli.errors import ComposeFileNotFound | from compose.cli.main import TopLevelCommand | ||||||
| from compose.service import Service | from compose.service import Service | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -23,7 +20,7 @@ class CLITestCase(unittest.TestCase): | |||||||
|         try: |         try: | ||||||
|             os.chdir('tests/fixtures/simple-composefile') |             os.chdir('tests/fixtures/simple-composefile') | ||||||
|             command = TopLevelCommand() |             command = TopLevelCommand() | ||||||
|             project_name = command.get_project_name(command.get_config_path()) |             project_name = command.get_project_name('.') | ||||||
|             self.assertEquals('simplecomposefile', project_name) |             self.assertEquals('simplecomposefile', project_name) | ||||||
|         finally: |         finally: | ||||||
|             os.chdir(cwd) |             os.chdir(cwd) | ||||||
| @ -31,13 +28,13 @@ class CLITestCase(unittest.TestCase): | |||||||
|     def test_project_name_with_explicit_base_dir(self): |     def test_project_name_with_explicit_base_dir(self): | ||||||
|         command = TopLevelCommand() |         command = TopLevelCommand() | ||||||
|         command.base_dir = 'tests/fixtures/simple-composefile' |         command.base_dir = 'tests/fixtures/simple-composefile' | ||||||
|         project_name = command.get_project_name(command.get_config_path()) |         project_name = command.get_project_name(command.base_dir) | ||||||
|         self.assertEquals('simplecomposefile', project_name) |         self.assertEquals('simplecomposefile', project_name) | ||||||
| 
 | 
 | ||||||
|     def test_project_name_with_explicit_uppercase_base_dir(self): |     def test_project_name_with_explicit_uppercase_base_dir(self): | ||||||
|         command = TopLevelCommand() |         command = TopLevelCommand() | ||||||
|         command.base_dir = 'tests/fixtures/UpperCaseDir' |         command.base_dir = 'tests/fixtures/UpperCaseDir' | ||||||
|         project_name = command.get_project_name(command.get_config_path()) |         project_name = command.get_project_name(command.base_dir) | ||||||
|         self.assertEquals('uppercasedir', project_name) |         self.assertEquals('uppercasedir', project_name) | ||||||
| 
 | 
 | ||||||
|     def test_project_name_with_explicit_project_name(self): |     def test_project_name_with_explicit_project_name(self): | ||||||
| @ -62,37 +59,10 @@ class CLITestCase(unittest.TestCase): | |||||||
|             project_name = command.get_project_name(None) |             project_name = command.get_project_name(None) | ||||||
|         self.assertEquals(project_name, name) |         self.assertEquals(project_name, name) | ||||||
| 
 | 
 | ||||||
|     def test_filename_check(self): |  | ||||||
|         files = [ |  | ||||||
|             'docker-compose.yml', |  | ||||||
|             'docker-compose.yaml', |  | ||||||
|             'fig.yml', |  | ||||||
|             'fig.yaml', |  | ||||||
|         ] |  | ||||||
| 
 |  | ||||||
|         """Test with files placed in the basedir""" |  | ||||||
| 
 |  | ||||||
|         self.assertEqual('docker-compose.yml', get_config_filename_for_files(files[0:])) |  | ||||||
|         self.assertEqual('docker-compose.yaml', get_config_filename_for_files(files[1:])) |  | ||||||
|         self.assertEqual('fig.yml', get_config_filename_for_files(files[2:])) |  | ||||||
|         self.assertEqual('fig.yaml', get_config_filename_for_files(files[3:])) |  | ||||||
|         self.assertRaises(ComposeFileNotFound, lambda: get_config_filename_for_files([])) |  | ||||||
| 
 |  | ||||||
|         """Test with files placed in the subdir""" |  | ||||||
| 
 |  | ||||||
|         def get_config_filename_for_files_in_subdir(files): |  | ||||||
|             return get_config_filename_for_files(files, subdir=True) |  | ||||||
| 
 |  | ||||||
|         self.assertEqual('docker-compose.yml', get_config_filename_for_files_in_subdir(files[0:])) |  | ||||||
|         self.assertEqual('docker-compose.yaml', get_config_filename_for_files_in_subdir(files[1:])) |  | ||||||
|         self.assertEqual('fig.yml', get_config_filename_for_files_in_subdir(files[2:])) |  | ||||||
|         self.assertEqual('fig.yaml', get_config_filename_for_files_in_subdir(files[3:])) |  | ||||||
|         self.assertRaises(ComposeFileNotFound, lambda: get_config_filename_for_files_in_subdir([])) |  | ||||||
| 
 |  | ||||||
|     def test_get_project(self): |     def test_get_project(self): | ||||||
|         command = TopLevelCommand() |         command = TopLevelCommand() | ||||||
|         command.base_dir = 'tests/fixtures/longer-filename-composefile' |         command.base_dir = 'tests/fixtures/longer-filename-composefile' | ||||||
|         project = command.get_project(command.get_config_path()) |         project = command.get_project() | ||||||
|         self.assertEqual(project.name, 'longerfilenamecomposefile') |         self.assertEqual(project.name, 'longerfilenamecomposefile') | ||||||
|         self.assertTrue(project.client) |         self.assertTrue(project.client) | ||||||
|         self.assertTrue(project.services) |         self.assertTrue(project.services) | ||||||
| @ -201,23 +171,3 @@ class CLITestCase(unittest.TestCase): | |||||||
|         }) |         }) | ||||||
|         _, _, call_kwargs = mock_client.create_container.mock_calls[0] |         _, _, call_kwargs = mock_client.create_container.mock_calls[0] | ||||||
|         self.assertFalse('RestartPolicy' in call_kwargs['host_config']) |         self.assertFalse('RestartPolicy' in call_kwargs['host_config']) | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def get_config_filename_for_files(filenames, subdir=None): |  | ||||||
|     project_dir = tempfile.mkdtemp() |  | ||||||
|     try: |  | ||||||
|         make_files(project_dir, filenames) |  | ||||||
|         command = TopLevelCommand() |  | ||||||
|         if subdir: |  | ||||||
|             command.base_dir = tempfile.mkdtemp(dir=project_dir) |  | ||||||
|         else: |  | ||||||
|             command.base_dir = project_dir |  | ||||||
|         return os.path.basename(command.get_config_path()) |  | ||||||
|     finally: |  | ||||||
|         shutil.rmtree(project_dir) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def make_files(dirname, filenames): |  | ||||||
|     for fname in filenames: |  | ||||||
|         with open(os.path.join(dirname, fname), 'w') as f: |  | ||||||
|             f.write('') |  | ||||||
|  | |||||||
| @ -1,16 +1,24 @@ | |||||||
| import os |  | ||||||
| import mock | import mock | ||||||
|  | import os | ||||||
|  | import shutil | ||||||
|  | import tempfile | ||||||
| from .. import unittest | from .. import unittest | ||||||
| 
 | 
 | ||||||
| from compose import config | from compose import config | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class ConfigTest(unittest.TestCase): | class ConfigTest(unittest.TestCase): | ||||||
|     def test_from_dictionary(self): |     def test_load(self): | ||||||
|         service_dicts = config.from_dictionary({ |         service_dicts = config.load( | ||||||
|             'foo': {'image': 'busybox'}, |             config.ConfigDetails( | ||||||
|             'bar': {'environment': ['FOO=1']}, |                 { | ||||||
|         }) |                     'foo': {'image': 'busybox'}, | ||||||
|  |                     'bar': {'environment': ['FOO=1']}, | ||||||
|  |                 }, | ||||||
|  |                 'working_dir', | ||||||
|  |                 'filename.yml' | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
| 
 | 
 | ||||||
|         self.assertEqual( |         self.assertEqual( | ||||||
|             sorted(service_dicts, key=lambda d: d['name']), |             sorted(service_dicts, key=lambda d: d['name']), | ||||||
| @ -26,11 +34,15 @@ class ConfigTest(unittest.TestCase): | |||||||
|             ]) |             ]) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def test_from_dictionary_throws_error_when_not_dict(self): |     def test_load_throws_error_when_not_dict(self): | ||||||
|         with self.assertRaises(config.ConfigurationError): |         with self.assertRaises(config.ConfigurationError): | ||||||
|             config.from_dictionary({ |             config.load( | ||||||
|                 'web': 'busybox:latest', |                 config.ConfigDetails( | ||||||
|             }) |                     {'web': 'busybox:latest'}, | ||||||
|  |                     'working_dir', | ||||||
|  |                     'filename.yml' | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
| 
 | 
 | ||||||
|     def test_config_validation(self): |     def test_config_validation(self): | ||||||
|         self.assertRaises( |         self.assertRaises( | ||||||
| @ -335,9 +347,13 @@ class EnvTest(unittest.TestCase): | |||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def load_from_filename(filename): | ||||||
|  |     return config.load(config.find('.', filename)) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class ExtendsTest(unittest.TestCase): | class ExtendsTest(unittest.TestCase): | ||||||
|     def test_extends(self): |     def test_extends(self): | ||||||
|         service_dicts = config.load('tests/fixtures/extends/docker-compose.yml') |         service_dicts = load_from_filename('tests/fixtures/extends/docker-compose.yml') | ||||||
| 
 | 
 | ||||||
|         service_dicts = sorted( |         service_dicts = sorted( | ||||||
|             service_dicts, |             service_dicts, | ||||||
| @ -364,7 +380,7 @@ class ExtendsTest(unittest.TestCase): | |||||||
|         ]) |         ]) | ||||||
| 
 | 
 | ||||||
|     def test_nested(self): |     def test_nested(self): | ||||||
|         service_dicts = config.load('tests/fixtures/extends/nested.yml') |         service_dicts = load_from_filename('tests/fixtures/extends/nested.yml') | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(service_dicts, [ |         self.assertEqual(service_dicts, [ | ||||||
|             { |             { | ||||||
| @ -380,7 +396,7 @@ class ExtendsTest(unittest.TestCase): | |||||||
| 
 | 
 | ||||||
|     def test_circular(self): |     def test_circular(self): | ||||||
|         try: |         try: | ||||||
|             config.load('tests/fixtures/extends/circle-1.yml') |             load_from_filename('tests/fixtures/extends/circle-1.yml') | ||||||
|             raise Exception("Expected config.CircularReference to be raised") |             raise Exception("Expected config.CircularReference to be raised") | ||||||
|         except config.CircularReference as e: |         except config.CircularReference as e: | ||||||
|             self.assertEqual( |             self.assertEqual( | ||||||
| @ -445,7 +461,7 @@ class ExtendsTest(unittest.TestCase): | |||||||
|             print load_config() |             print load_config() | ||||||
| 
 | 
 | ||||||
|     def test_volume_path(self): |     def test_volume_path(self): | ||||||
|         dicts = config.load('tests/fixtures/volume-path/docker-compose.yml') |         dicts = load_from_filename('tests/fixtures/volume-path/docker-compose.yml') | ||||||
| 
 | 
 | ||||||
|         paths = [ |         paths = [ | ||||||
|             '%s:/foo' % os.path.abspath('tests/fixtures/volume-path/common/foo'), |             '%s:/foo' % os.path.abspath('tests/fixtures/volume-path/common/foo'), | ||||||
| @ -455,7 +471,7 @@ class ExtendsTest(unittest.TestCase): | |||||||
|         self.assertEqual(set(dicts[0]['volumes']), set(paths)) |         self.assertEqual(set(dicts[0]['volumes']), set(paths)) | ||||||
| 
 | 
 | ||||||
|     def test_parent_build_path_dne(self): |     def test_parent_build_path_dne(self): | ||||||
|         child = config.load('tests/fixtures/extends/nonexistent-path-child.yml') |         child = load_from_filename('tests/fixtures/extends/nonexistent-path-child.yml') | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(child, [ |         self.assertEqual(child, [ | ||||||
|             { |             { | ||||||
| @ -475,14 +491,16 @@ class BuildPathTest(unittest.TestCase): | |||||||
|         self.abs_context_path = os.path.join(os.getcwd(), 'tests/fixtures/build-ctx') |         self.abs_context_path = os.path.join(os.getcwd(), 'tests/fixtures/build-ctx') | ||||||
| 
 | 
 | ||||||
|     def test_nonexistent_path(self): |     def test_nonexistent_path(self): | ||||||
|         options = {'build': 'nonexistent.path'} |         with self.assertRaises(config.ConfigurationError): | ||||||
|         self.assertRaises( |             config.load( | ||||||
|             config.ConfigurationError, |                 config.ConfigDetails( | ||||||
|             lambda: config.from_dictionary({ |                     { | ||||||
|                 'foo': options, |                         'foo': {'build': 'nonexistent.path'}, | ||||||
|                 'working_dir': 'tests/fixtures/build-path' |                     }, | ||||||
|             }) |                     'working_dir', | ||||||
|         ) |                     'filename.yml' | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
| 
 | 
 | ||||||
|     def test_relative_path(self): |     def test_relative_path(self): | ||||||
|         relative_build_path = '../build-ctx/' |         relative_build_path = '../build-ctx/' | ||||||
| @ -502,5 +520,56 @@ class BuildPathTest(unittest.TestCase): | |||||||
|         self.assertEquals(service_dict['build'], self.abs_context_path) |         self.assertEquals(service_dict['build'], self.abs_context_path) | ||||||
| 
 | 
 | ||||||
|     def test_from_file(self): |     def test_from_file(self): | ||||||
|         service_dict = config.load('tests/fixtures/build-path/docker-compose.yml') |         service_dict = load_from_filename('tests/fixtures/build-path/docker-compose.yml') | ||||||
|         self.assertEquals(service_dict, [{'name': 'foo', 'build': self.abs_context_path}]) |         self.assertEquals(service_dict, [{'name': 'foo', 'build': self.abs_context_path}]) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class GetConfigPathTestCase(unittest.TestCase): | ||||||
|  | 
 | ||||||
|  |     files = [ | ||||||
|  |         'docker-compose.yml', | ||||||
|  |         'docker-compose.yaml', | ||||||
|  |         'fig.yml', | ||||||
|  |         'fig.yaml', | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     def test_get_config_path_default_file_in_basedir(self): | ||||||
|  |         files = self.files | ||||||
|  |         self.assertEqual('docker-compose.yml', get_config_filename_for_files(files[0:])) | ||||||
|  |         self.assertEqual('docker-compose.yaml', get_config_filename_for_files(files[1:])) | ||||||
|  |         self.assertEqual('fig.yml', get_config_filename_for_files(files[2:])) | ||||||
|  |         self.assertEqual('fig.yaml', get_config_filename_for_files(files[3:])) | ||||||
|  |         with self.assertRaises(config.ComposeFileNotFound): | ||||||
|  |             get_config_filename_for_files([]) | ||||||
|  | 
 | ||||||
|  |     def test_get_config_path_default_file_in_parent_dir(self): | ||||||
|  |         """Test with files placed in the subdir""" | ||||||
|  |         files = self.files | ||||||
|  | 
 | ||||||
|  |         def get_config_in_subdir(files): | ||||||
|  |             return get_config_filename_for_files(files, subdir=True) | ||||||
|  | 
 | ||||||
|  |         self.assertEqual('docker-compose.yml', get_config_in_subdir(files[0:])) | ||||||
|  |         self.assertEqual('docker-compose.yaml', get_config_in_subdir(files[1:])) | ||||||
|  |         self.assertEqual('fig.yml', get_config_in_subdir(files[2:])) | ||||||
|  |         self.assertEqual('fig.yaml', get_config_in_subdir(files[3:])) | ||||||
|  |         with self.assertRaises(config.ComposeFileNotFound): | ||||||
|  |             get_config_in_subdir([]) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_config_filename_for_files(filenames, subdir=None): | ||||||
|  |     def make_files(dirname, filenames): | ||||||
|  |         for fname in filenames: | ||||||
|  |             with open(os.path.join(dirname, fname), 'w') as f: | ||||||
|  |                 f.write('') | ||||||
|  | 
 | ||||||
|  |     project_dir = tempfile.mkdtemp() | ||||||
|  |     try: | ||||||
|  |         make_files(project_dir, filenames) | ||||||
|  |         if subdir: | ||||||
|  |             base_dir = tempfile.mkdtemp(dir=project_dir) | ||||||
|  |         else: | ||||||
|  |             base_dir = project_dir | ||||||
|  |         return os.path.basename(config.get_config_path(base_dir)) | ||||||
|  |     finally: | ||||||
|  |         shutil.rmtree(project_dir) | ||||||
|  | |||||||
| @ -3,7 +3,6 @@ from .. import unittest | |||||||
| from compose.service import Service | from compose.service import Service | ||||||
| from compose.project import Project | from compose.project import Project | ||||||
| from compose.container import Container | from compose.container import Container | ||||||
| from compose import config |  | ||||||
| 
 | 
 | ||||||
| import mock | import mock | ||||||
| import docker | import docker | ||||||
| @ -51,14 +50,16 @@ class ProjectTest(unittest.TestCase): | |||||||
|         self.assertEqual(project.services[2].name, 'web') |         self.assertEqual(project.services[2].name, 'web') | ||||||
| 
 | 
 | ||||||
|     def test_from_config(self): |     def test_from_config(self): | ||||||
|         dicts = config.from_dictionary({ |         dicts = [ | ||||||
|             'web': { |             { | ||||||
|  |                 'name': 'web', | ||||||
|                 'image': 'busybox:latest', |                 'image': 'busybox:latest', | ||||||
|             }, |             }, | ||||||
|             'db': { |             { | ||||||
|  |                 'name': 'db', | ||||||
|                 'image': 'busybox:latest', |                 'image': 'busybox:latest', | ||||||
|             }, |             }, | ||||||
|         }) |         ] | ||||||
|         project = Project.from_dicts('composetest', dicts, None) |         project = Project.from_dicts('composetest', dicts, None) | ||||||
|         self.assertEqual(len(project.services), 2) |         self.assertEqual(len(project.services), 2) | ||||||
|         self.assertEqual(project.get_service('web').name, 'web') |         self.assertEqual(project.get_service('web').name, 'web') | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user