From 9bc7604e0e47ab3debe6bf41e86ed6a4db842ca6 Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Wed, 28 Jan 2015 17:19:27 -0500 Subject: [PATCH 1/2] Make sure we're testing uppercase directories properly (OS X is case-sensitive so we can't have fixture dirs which are identically named if you ignore case) Signed-off-by: Aanand Prasad --- tests/fixtures/UpperCaseDir/docker-compose.yml | 6 ++++++ tests/unit/cli_test.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/UpperCaseDir/docker-compose.yml diff --git a/tests/fixtures/UpperCaseDir/docker-compose.yml b/tests/fixtures/UpperCaseDir/docker-compose.yml new file mode 100644 index 000000000..3538ab097 --- /dev/null +++ b/tests/fixtures/UpperCaseDir/docker-compose.yml @@ -0,0 +1,6 @@ +simple: + image: busybox:latest + command: /bin/sleep 300 +another: + image: busybox:latest + command: /bin/sleep 300 diff --git a/tests/unit/cli_test.py b/tests/unit/cli_test.py index 1154d3de1..98a8f9ee0 100644 --- a/tests/unit/cli_test.py +++ b/tests/unit/cli_test.py @@ -31,9 +31,9 @@ class CLITestCase(unittest.TestCase): def test_project_name_with_explicit_uppercase_base_dir(self): command = TopLevelCommand() - command.base_dir = 'tests/fixtures/Simple-figfile' + command.base_dir = 'tests/fixtures/UpperCaseDir' project_name = command.get_project_name(command.get_config_path()) - self.assertEquals('simplefigfile', project_name) + self.assertEquals('uppercasedir', project_name) def test_project_name_with_explicit_project_name(self): command = TopLevelCommand() From 7c087f1c07fefeeef092b010841fc36b77eda3bc Mon Sep 17 00:00:00 2001 From: Aanand Prasad Date: Wed, 28 Jan 2015 17:27:53 -0500 Subject: [PATCH 2/2] Support fig.y(a)ml and show a deprecation warning Closes #864 Signed-off-by: Aanand Prasad --- compose/cli/command.py | 36 +++++++++++++++++++++-------- compose/cli/errors.py | 8 ++++--- tests/unit/cli_test.py | 51 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 77 insertions(+), 18 deletions(-) diff --git a/compose/cli/command.py b/compose/cli/command.py index f92f95cd6..67b77f31b 100644 --- a/compose/cli/command.py +++ b/compose/cli/command.py @@ -1,7 +1,6 @@ from __future__ import unicode_literals from __future__ import absolute_import from requests.exceptions import ConnectionError, SSLError -import errno import logging import os import re @@ -75,8 +74,6 @@ class Command(DocoptCommand): with open(config_path, 'r') as fh: return yaml.safe_load(fh) except IOError as e: - if e.errno == errno.ENOENT: - raise errors.ComposeFileNotFound(os.path.basename(e.filename)) raise errors.UserError(six.text_type(e)) def get_project(self, config_path, project_name=None, verbose=False): @@ -110,13 +107,34 @@ class Command(DocoptCommand): if file_path: return os.path.join(self.base_dir, file_path) - if os.path.exists(os.path.join(self.base_dir, 'docker-compose.yaml')): - log.warning("Compose just read the file 'docker-compose.yaml' on startup, rather " - "than 'docker-compose.yml'") + supported_filenames = [ + 'docker-compose.yml', + 'docker-compose.yaml', + 'fig.yml', + 'fig.yaml', + ] + + def expand(filename): + return os.path.join(self.base_dir, filename) + + candidates = [filename for filename in supported_filenames if os.path.exists(expand(filename))] + + 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") + "issues in future.\n") - return os.path.join(self.base_dir, 'docker-compose.yaml') + 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(self.base_dir, 'docker-compose.yml') + return expand(winner) diff --git a/compose/cli/errors.py b/compose/cli/errors.py index d0d947246..d439aa61c 100644 --- a/compose/cli/errors.py +++ b/compose/cli/errors.py @@ -56,7 +56,9 @@ class ConnectionErrorGeneric(UserError): class ComposeFileNotFound(UserError): - def __init__(self, filename): + def __init__(self, supported_filenames): super(ComposeFileNotFound, self).__init__(""" - Can't find %s. Are you in the right directory? - """ % filename) + Can't find a suitable configuration file. Are you in the right directory? + + Supported filenames: %s + """ % ", ".join(supported_filenames)) diff --git a/tests/unit/cli_test.py b/tests/unit/cli_test.py index 98a8f9ee0..57e2f327f 100644 --- a/tests/unit/cli_test.py +++ b/tests/unit/cli_test.py @@ -2,12 +2,15 @@ from __future__ import unicode_literals from __future__ import absolute_import import logging import os +import tempfile +import shutil from .. import unittest import mock from compose.cli import main from compose.cli.main import TopLevelCommand +from compose.cli.errors import ComposeFileNotFound from six import StringIO @@ -57,12 +60,30 @@ class CLITestCase(unittest.TestCase): project_name = command.get_project_name(None) self.assertEquals(project_name, name) - def test_yaml_filename_check(self): - command = TopLevelCommand() - command.base_dir = 'tests/fixtures/longer-filename-composefile' - with mock.patch('compose.cli.command.log', autospec=True) as mock_log: - self.assertTrue(command.get_config_path()) - self.assertEqual(mock_log.warning.call_count, 2) + def test_filename_check(self): + self.assertEqual('docker-compose.yml', get_config_filename_for_files([ + 'docker-compose.yml', + 'docker-compose.yaml', + 'fig.yml', + 'fig.yaml', + ])) + + self.assertEqual('docker-compose.yaml', get_config_filename_for_files([ + 'docker-compose.yaml', + 'fig.yml', + 'fig.yaml', + ])) + + self.assertEqual('fig.yml', get_config_filename_for_files([ + 'fig.yml', + 'fig.yaml', + ])) + + self.assertEqual('fig.yaml', get_config_filename_for_files([ + 'fig.yaml', + ])) + + self.assertRaises(ComposeFileNotFound, lambda: get_config_filename_for_files([])) def test_get_project(self): command = TopLevelCommand() @@ -81,3 +102,21 @@ class CLITestCase(unittest.TestCase): main.setup_logging() self.assertEqual(logging.getLogger().level, logging.DEBUG) self.assertEqual(logging.getLogger('requests').propagate, False) + + +def get_config_filename_for_files(filenames): + project_dir = tempfile.mkdtemp() + try: + make_files(project_dir, filenames) + command = TopLevelCommand() + 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('') +