Refactor validating extends file path

Separating out the steps we need to resolve extends, so that it
will be clear to insert pre-processing of interpolation and
validation.

Signed-off-by: Mazz Mosley <mazz@houseofmnowster.com>
This commit is contained in:
Mazz Mosley 2015-08-24 15:58:17 +01:00
parent 02c52ae673
commit 538a501eec
2 changed files with 31 additions and 18 deletions

View File

@ -11,6 +11,7 @@ from .errors import ComposeFileNotFound
from .errors import ConfigurationError from .errors import ConfigurationError
from .interpolation import interpolate_environment_variables from .interpolation import interpolate_environment_variables
from .validation import validate_against_schema from .validation import validate_against_schema
from .validation import validate_extends_file_path
from .validation import validate_service_names from .validation import validate_service_names
from .validation import validate_top_level_object from .validation import validate_top_level_object
from compose.cli.utils import find_candidates_in_parent_dirs from compose.cli.utils import find_candidates_in_parent_dirs
@ -171,12 +172,20 @@ class ServiceLoader(object):
self.resolve_environment() self.resolve_environment()
if 'extends' in self.service_dict:
validate_extends_file_path(
service_name,
self.service_dict['extends'],
self.filename
)
def detect_cycle(self, name): def detect_cycle(self, name):
if self.signature(name) in self.already_seen: if self.signature(name) in self.already_seen:
raise CircularReference(self.already_seen + [self.signature(name)]) raise CircularReference(self.already_seen + [self.signature(name)])
def make_service_dict(self): def make_service_dict(self):
self.service_dict = self.resolve_extends(self.service_dict) self.service_dict = self.resolve_extends()
return process_container_options(self.service_dict, working_dir=self.working_dir) return process_container_options(self.service_dict, working_dir=self.working_dir)
def resolve_environment(self): def resolve_environment(self):
@ -199,11 +208,12 @@ class ServiceLoader(object):
self.service_dict['environment'] = env self.service_dict['environment'] = env
def resolve_extends(self, service_dict): def resolve_extends(self):
if 'extends' not in service_dict: if 'extends' not in self.service_dict:
return service_dict return self.service_dict
extends_options = self.validate_extends_options(service_dict['name'], service_dict['extends']) extends_options = self.service_dict['extends']
service_name = self.service_dict['name']
if 'file' in extends_options: if 'file' in extends_options:
extends_from_filename = extends_options['file'] extends_from_filename = extends_options['file']
@ -212,7 +222,7 @@ class ServiceLoader(object):
other_config_path = self.filename other_config_path = self.filename
other_working_dir = os.path.dirname(other_config_path) other_working_dir = os.path.dirname(other_config_path)
other_already_seen = self.already_seen + [self.signature(service_dict['name'])] other_already_seen = self.already_seen + [self.signature(service_name)]
base_service = extends_options['service'] base_service = extends_options['service']
other_config = load_yaml(other_config_path) other_config = load_yaml(other_config_path)
@ -227,7 +237,7 @@ class ServiceLoader(object):
other_loader = ServiceLoader( other_loader = ServiceLoader(
working_dir=other_working_dir, working_dir=other_working_dir,
filename=other_config_path, filename=other_config_path,
service_name=service_dict['name'], service_name=service_name,
service_dict=other_service_dict, service_dict=other_service_dict,
already_seen=other_already_seen, already_seen=other_already_seen,
) )
@ -240,21 +250,11 @@ class ServiceLoader(object):
service=extends_options['service'], service=extends_options['service'],
) )
return merge_service_dicts(other_service_dict, service_dict) return merge_service_dicts(other_service_dict, self.service_dict)
def signature(self, name): def signature(self, name):
return (self.filename, name) return (self.filename, name)
def validate_extends_options(self, service_name, extends_options):
error_prefix = "Invalid 'extends' configuration for %s:" % service_name
if 'file' not in extends_options and self.filename is None:
raise ConfigurationError(
"%s you need to specify a 'file', e.g. 'file: something.yml'" % error_prefix
)
return extends_options
def validate_extended_service_dict(service_dict, filename, service): def validate_extended_service_dict(service_dict, filename, service):
error_prefix = "Cannot extend service '%s' in %s:" % (service, filename) error_prefix = "Cannot extend service '%s' in %s:" % (service, filename)

View File

@ -66,6 +66,19 @@ def validate_top_level_object(func):
return func_wrapper return func_wrapper
def validate_extends_file_path(service_name, extends_options, filename):
"""
The service to be extended must either be defined in the config key 'file',
or within 'filename'.
"""
error_prefix = "Invalid 'extends' configuration for %s:" % service_name
if 'file' not in extends_options and filename is None:
raise ConfigurationError(
"%s you need to specify a 'file', e.g. 'file: something.yml'" % error_prefix
)
def get_unsupported_config_msg(service_name, error_key): def get_unsupported_config_msg(service_name, error_key):
msg = "Unsupported config option for '{}' service: '{}'".format(service_name, error_key) msg = "Unsupported config option for '{}' service: '{}'".format(service_name, error_key)
if error_key in DOCKER_CONFIG_HINTS: if error_key in DOCKER_CONFIG_HINTS: