Merge pull request #1232 from aleksandr-vin/add-parent-directories-search-for-default-compose-files

Add parent directories search for default compose-files
This commit is contained in:
Daniel Nephin 2015-04-24 13:12:24 -04:00
commit 89789c54ad
5 changed files with 61 additions and 35 deletions

View File

@ -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 from .utils import call_silently, is_mac, is_ubuntu, find_candidates_in_parent_dirs
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,6 +18,13 @@ 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 = '.'
@ -100,20 +107,10 @@ class Command(DocoptCommand):
if file_path: if file_path:
return os.path.join(self.base_dir, file_path) return os.path.join(self.base_dir, file_path)
supported_filenames = [ (candidates, path) = find_candidates_in_parent_dirs(SUPPORTED_FILENAMES, self.base_dir)
'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: if len(candidates) == 0:
raise errors.ComposeFileNotFound(supported_filenames) raise errors.ComposeFileNotFound(SUPPORTED_FILENAMES)
winner = candidates[0] winner = candidates[0]
@ -130,4 +127,4 @@ class Command(DocoptCommand):
log.warning("%s is deprecated and will not be supported in future. " log.warning("%s is deprecated and will not be supported in future. "
"Please rename your config file to docker-compose.yml\n" % winner) "Please rename your config file to docker-compose.yml\n" % winner)
return expand(winner) return os.path.join(path, winner)

View File

@ -58,7 +58,7 @@ class ConnectionErrorGeneric(UserError):
class ComposeFileNotFound(UserError): class ComposeFileNotFound(UserError):
def __init__(self, supported_filenames): def __init__(self, supported_filenames):
super(ComposeFileNotFound, self).__init__(""" super(ComposeFileNotFound, self).__init__("""
Can't find a suitable configuration file. Are you in the right directory? Can't find a suitable configuration file in this directory or any parent. Are you in the right directory?
Supported filenames: %s Supported filenames: %s
""" % ", ".join(supported_filenames)) """ % ", ".join(supported_filenames))

View File

@ -62,6 +62,25 @@ def mkdir(path, permissions=0o700):
return path return path
def find_candidates_in_parent_dirs(filenames, path):
"""
Given a directory path to start, looks for filenames in the
directory, and then each parent directory successively,
until found.
Returns tuple (candidates, path).
"""
candidates = [filename for filename in filenames
if os.path.exists(os.path.join(path, filename))]
if len(candidates) == 0:
parent_dir = os.path.join(path, '..')
if os.path.abspath(parent_dir) != os.path.abspath(path):
return find_candidates_in_parent_dirs(filenames, parent_dir)
return (candidates, path)
def split_buffer(reader, separator): def split_buffer(reader, separator):
""" """
Given a generator which yields strings and a separator string, Given a generator which yields strings and a separator string,

View File

@ -136,7 +136,10 @@ By default, if there are existing containers for a service, `docker-compose up`
### -f, --file FILE ### -f, --file FILE
Specifies an alternate Compose yaml file (default: `docker-compose.yml`) Specify what file to read configuration from. If not provided, Compose will look
for `docker-compose.yml` in the current working directory, and then each parent
directory successively, until found.
### -p, --project-name NAME ### -p, --project-name NAME
@ -157,7 +160,9 @@ Sets the project name, which is prepended to the name of every container started
### COMPOSE\_FILE ### COMPOSE\_FILE
Sets the path to the `docker-compose.yml` to use. Defaults to `docker-compose.yml` in the current working directory. Specify what file to read configuration from. If not provided, Compose will look
for `docker-compose.yml` in the current working directory, and then each parent
directory successively, until found.
### DOCKER\_HOST ### DOCKER\_HOST

View File

@ -62,30 +62,32 @@ class CLITestCase(unittest.TestCase):
self.assertEquals(project_name, name) self.assertEquals(project_name, name)
def test_filename_check(self): def test_filename_check(self):
self.assertEqual('docker-compose.yml', get_config_filename_for_files([ files = [
'docker-compose.yml', 'docker-compose.yml',
'docker-compose.yaml', 'docker-compose.yaml',
'fig.yml', 'fig.yml',
'fig.yaml', 'fig.yaml',
])) ]
self.assertEqual('docker-compose.yaml', get_config_filename_for_files([ """Test with files placed in the basedir"""
'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.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([])) 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'
@ -184,11 +186,14 @@ class CLITestCase(unittest.TestCase):
self.assertFalse('RestartPolicy' in call_kwargs['host_config']) self.assertFalse('RestartPolicy' in call_kwargs['host_config'])
def get_config_filename_for_files(filenames): def get_config_filename_for_files(filenames, subdir=None):
project_dir = tempfile.mkdtemp() project_dir = tempfile.mkdtemp()
try: try:
make_files(project_dir, filenames) make_files(project_dir, filenames)
command = TopLevelCommand() command = TopLevelCommand()
if subdir:
command.base_dir = tempfile.mkdtemp(dir=project_dir)
else:
command.base_dir = project_dir command.base_dir = project_dir
return os.path.basename(command.get_config_path()) return os.path.basename(command.get_config_path())
finally: finally: