schemas: rework schemas so that they can be included from other files

- Each schema now has a top-level `properties` and `schema` attribute.

- The `properties` is a fragment that can be included in other
  jsonschemas, via Python, not via '$ref'

- Th `schema` is a complete `jsonschema` with `title` and `$schema`
  properties.
This commit is contained in:
Todd Gamblin 2018-08-20 17:04:52 -07:00
parent 83323f4e71
commit c19000038b
11 changed files with 510 additions and 414 deletions

View File

@ -51,7 +51,12 @@
import spack.paths import spack.paths
import spack.architecture import spack.architecture
import spack.schema import spack.schema.compilers
import spack.schema.mirrors
import spack.schema.repos
import spack.schema.packages
import spack.schema.modules
import spack.schema.config
from spack.error import SpackError from spack.error import SpackError
# Hacked yaml for configuration files preserves line numbers. # Hacked yaml for configuration files preserves line numbers.
@ -175,7 +180,7 @@ def write_section(self, section):
try: try:
mkdirp(self.path) mkdirp(self.path)
with open(filename, 'w') as f: with open(filename, 'w') as f:
_validate_section(data, section_schemas[section]) _validate(data, section_schemas[section])
syaml.dump(data, stream=f, default_flow_style=False) syaml.dump(data, stream=f, default_flow_style=False)
except (yaml.YAMLError, IOError) as e: except (yaml.YAMLError, IOError) as e:
raise ConfigFileError( raise ConfigFileError(
@ -216,7 +221,7 @@ def __init__(self, name, data=None):
if data: if data:
for section in data: for section in data:
dsec = data[section] dsec = data[section]
_validate_section({section: dsec}, section_schemas[section]) _validate({section: dsec}, section_schemas[section])
self.sections[section] = _mark_internal( self.sections[section] = _mark_internal(
syaml.syaml_dict({section: dsec}), name) syaml.syaml_dict({section: dsec}), name)
@ -234,7 +239,7 @@ def write_section(self, section):
"""This only validates, as the data is already in memory.""" """This only validates, as the data is already in memory."""
data = self.get_section(section) data = self.get_section(section)
if data is not None: if data is not None:
_validate_section(data, section_schemas[section]) _validate(data, section_schemas[section])
self.sections[section] = _mark_internal(data, self.name) self.sections[section] = _mark_internal(data, self.name)
def __repr__(self): def __repr__(self):
@ -585,7 +590,7 @@ def _validate_section_name(section):
% (section, " ".join(section_schemas.keys()))) % (section, " ".join(section_schemas.keys())))
def _validate_section(data, schema): def _validate(data, schema):
"""Validate data read in from a Spack YAML file. """Validate data read in from a Spack YAML file.
This leverages the line information (start_mark, end_mark) stored This leverages the line information (start_mark, end_mark) stored
@ -593,13 +598,13 @@ def _validate_section(data, schema):
""" """
import jsonschema import jsonschema
if not hasattr(_validate_section, 'validator'): if not hasattr(_validate, 'validator'):
default_setting_validator = _extend_with_default( default_setting_validator = _extend_with_default(
jsonschema.Draft4Validator) jsonschema.Draft4Validator)
_validate_section.validator = default_setting_validator _validate.validator = default_setting_validator
try: try:
_validate_section.validator(schema).validate(data) _validate.validator(schema).validate(data)
except jsonschema.ValidationError as e: except jsonschema.ValidationError as e:
raise ConfigFormatError(e, data) raise ConfigFormatError(e, data)
@ -623,7 +628,7 @@ def _read_config_file(filename, schema):
data = _mark_overrides(syaml.load(f)) data = _mark_overrides(syaml.load(f))
if data: if data:
_validate_section(data, schema) _validate(data, schema)
return data return data
except MarkedYAMLError as e: except MarkedYAMLError as e:

View File

@ -85,7 +85,6 @@ def deactivate():
return return
def root(name): def root(name):
"""Get the root directory for an environment by name.""" """Get the root directory for an environment by name."""
return fs.join_path(env_path, name) return fs.join_path(env_path, name)

View File

@ -3,12 +3,4 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
"""This module contains jsonschema files for all of Spack's YAML formats. """This module contains jsonschema files for all of Spack's YAML formats."""
"""
from llnl.util.lang import list_modules
# Automatically bring in all sub-modules
__all__ = []
for mod in list_modules(__path__[0]):
__import__('%s.%s' % (__name__, mod))
__all__.append(mod)

View File

@ -10,114 +10,119 @@
""" """
#: Properties for inclusion in other schemas
properties = {
'compilers': {
'type': 'array',
'items': [{
'type': 'object',
'additionalProperties': False,
'properties': {
'compiler': {
'type': 'object',
'additionalProperties': False,
'required': [
'paths', 'spec', 'modules', 'operating_system'],
'properties': {
'paths': {
'type': 'object',
'required': ['cc', 'cxx', 'f77', 'fc'],
'additionalProperties': False,
'properties': {
'cc': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'cxx': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'f77': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'fc': {'anyOf': [{'type': 'string'},
{'type': 'null'}]}}},
'flags': {
'type': 'object',
'additionalProperties': False,
'properties': {
'cflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'cxxflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'fflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'cppflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'ldflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'ldlibs': {'anyOf': [{'type': 'string'},
{'type': 'null'}]}}},
'spec': {'type': 'string'},
'operating_system': {'type': 'string'},
'target': {'type': 'string'},
'alias': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'modules': {'anyOf': [{'type': 'string'},
{'type': 'null'},
{'type': 'array'}]},
'environment': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'set': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {
'anyOf': [{'type': 'string'},
{'type': 'number'}]
}
}
},
'unset': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {'type': 'null'}
}
},
'prepend-path': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {
'anyOf': [{'type': 'string'},
{'type': 'number'}]
}
}
},
'append-path': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {
'anyOf': [{'type': 'string'},
{'type': 'number'}]
}
}
}
}
},
'extra_rpaths': {
'type': 'array',
'default': [],
'items': {'type': 'string'}
}
}
}
}
}]
}
}
#: Full schema with metadata
schema = { schema = {
'$schema': 'http://json-schema.org/schema#', '$schema': 'http://json-schema.org/schema#',
'title': 'Spack compiler configuration file schema', 'title': 'Spack compiler configuration file schema',
'type': 'object', 'type': 'object',
'additionalProperties': False, 'additionalProperties': False,
'properties': { 'properties': properties,
'compilers': {
'type': 'array',
'items': {
'type': 'object',
'additionalProperties': False,
'properties': {
'compiler': {
'type': 'object',
'additionalProperties': False,
'required': [
'paths', 'spec', 'modules', 'operating_system'],
'properties': {
'paths': {
'type': 'object',
'required': ['cc', 'cxx', 'f77', 'fc'],
'additionalProperties': False,
'properties': {
'cc': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'cxx': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'f77': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'fc': {'anyOf': [{'type': 'string'},
{'type': 'null'}]}}},
'flags': {
'type': 'object',
'additionalProperties': False,
'properties': {
'cflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'cxxflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'fflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'cppflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'ldflags': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'ldlibs': {'anyOf': [{'type': 'string'},
{'type': 'null'}]}}},
'spec': {'type': 'string'},
'operating_system': {'type': 'string'},
'target': {'type': 'string'},
'alias': {'anyOf': [{'type': 'string'},
{'type': 'null'}]},
'modules': {'anyOf': [{'type': 'string'},
{'type': 'null'},
{'type': 'array'}]},
'environment': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'set': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {
'anyOf': [{'type': 'string'},
{'type': 'number'}]
}
}
},
'unset': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {'type': 'null'}
}
},
'prepend-path': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {
'anyOf': [{'type': 'string'},
{'type': 'number'}]
}
}
},
'append-path': {
'type': 'object',
'patternProperties': {
# Variable name
r'\w[\w-]*': {
'anyOf': [{'type': 'string'},
{'type': 'number'}]
}
}
}
}
},
'extra_rpaths': {
'type': 'array',
'default': [],
'items': {'type': 'string'}
}
}
}
}
}
}
}
} }

View File

@ -10,56 +10,61 @@
""" """
#: Properties for inclusion in other schemas
properties = {
'config': {
'type': 'object',
'default': {},
'properties': {
'install_tree': {'type': 'string'},
'install_hash_length': {'type': 'integer', 'minimum': 1},
'install_path_scheme': {'type': 'string'},
'build_stage': {
'oneOf': [
{'type': 'string'},
{'type': 'array',
'items': {'type': 'string'}}],
},
'template_dirs': {
'type': 'array',
'items': {'type': 'string'}
},
'module_roots': {
'type': 'object',
'additionalProperties': False,
'properties': {
'tcl': {'type': 'string'},
'lmod': {'type': 'string'},
'dotkit': {'type': 'string'},
},
},
'source_cache': {'type': 'string'},
'misc_cache': {'type': 'string'},
'verify_ssl': {'type': 'boolean'},
'debug': {'type': 'boolean'},
'checksum': {'type': 'boolean'},
'locks': {'type': 'boolean'},
'dirty': {'type': 'boolean'},
'build_language': {'type': 'string'},
'build_jobs': {'type': 'integer', 'minimum': 1},
'ccache': {'type': 'boolean'},
'db_lock_timeout': {'type': 'integer', 'minimum': 1},
'package_lock_timeout': {
'anyOf': [
{'type': 'integer', 'minimum': 1},
{'type': 'null'}
],
},
},
},
}
#: Full schema with metadata
schema = { schema = {
'$schema': 'http://json-schema.org/schema#', '$schema': 'http://json-schema.org/schema#',
'title': 'Spack core configuration file schema', 'title': 'Spack core configuration file schema',
'type': 'object', 'type': 'object',
'additionalProperties': False, 'additionalProperties': False,
'patternProperties': { 'properties': properties,
'config': {
'type': 'object',
'default': {},
'properties': {
'install_tree': {'type': 'string'},
'install_hash_length': {'type': 'integer', 'minimum': 1},
'install_path_scheme': {'type': 'string'},
'build_stage': {
'oneOf': [
{'type': 'string'},
{'type': 'array',
'items': {'type': 'string'}}],
},
'template_dirs': {
'type': 'array',
'items': {'type': 'string'}
},
'module_roots': {
'type': 'object',
'additionalProperties': False,
'properties': {
'tcl': {'type': 'string'},
'lmod': {'type': 'string'},
'dotkit': {'type': 'string'},
},
},
'source_cache': {'type': 'string'},
'misc_cache': {'type': 'string'},
'verify_ssl': {'type': 'boolean'},
'debug': {'type': 'boolean'},
'checksum': {'type': 'boolean'},
'locks': {'type': 'boolean'},
'dirty': {'type': 'boolean'},
'build_language': {'type': 'string'},
'build_jobs': {'type': 'integer', 'minimum': 1},
'ccache': {'type': 'boolean'},
'db_lock_timeout': {'type': 'integer', 'minimum': 1},
'package_lock_timeout': {
'anyOf': [
{'type': 'integer', 'minimum': 1},
{'type': 'null'}
],
},
}
},
},
} }

View File

@ -12,19 +12,22 @@
schema = { schema = {
'$schema': 'http://json-schema.org/schema#', '$schema': 'http://json-schema.org/schema#',
'title': 'Spack Environments user configuration file schema', 'title': 'Spack environment file schema',
'type': 'object', 'type': 'object',
'additionalProperties': False, 'additionalProperties': False,
'properties': { 'patternProperties': {
'env': { '^env|spack$': {
'type': 'object', 'type': 'object',
'default': {}, 'default': {},
'properties': { 'properties': {
'configs': { 'include': {
'type': 'array', 'type': 'array',
'default': [], 'items': {
'items': {'type': 'string'} 'type': 'string'
},
}, },
'specs': { 'specs': {
'type': 'object', 'type': 'object',
'default': {}, 'default': {},

View File

@ -10,20 +10,24 @@
""" """
#: Properties for inclusion in other schemas
properties = {
'mirrors': {
'type': 'object',
'default': {},
'additionalProperties': False,
'patternProperties': {
r'\w[\w-]*': {'type': 'string'},
},
},
}
#: Full schema with metadata
schema = { schema = {
'$schema': 'http://json-schema.org/schema#', '$schema': 'http://json-schema.org/schema#',
'title': 'Spack mirror configuration file schema', 'title': 'Spack mirror configuration file schema',
'type': 'object', 'type': 'object',
'additionalProperties': False, 'additionalProperties': False,
'patternProperties': { 'properties': properties,
r'mirrors': {
'type': 'object',
'default': {},
'additionalProperties': False,
'patternProperties': {
r'\w[\w-]*': {
'type': 'string'},
},
},
},
} }

View File

@ -10,158 +10,170 @@
""" """
schema = { #: Definitions for parts of module schema
'$schema': 'http://json-schema.org/schema#', definitions = {
'title': 'Spack module file configuration file schema', 'array_of_strings': {
'type': 'object', 'type': 'array',
'additionalProperties': False, 'default': [],
'definitions': { 'items': {
'array_of_strings': { 'type': 'string'
'type': 'array',
'default': [],
'items': {
'type': 'string'
}
},
'dictionary_of_strings': {
'type': 'object',
'patternProperties': {
r'\w[\w-]*': { # key
'type': 'string'
}
}
},
'dependency_selection': {
'type': 'string',
'enum': ['none', 'direct', 'all']
},
'module_file_configuration': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'filter': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'environment_blacklist': {
'type': 'array',
'default': [],
'items': {
'type': 'string'
}
}
}
},
'template': {
'type': 'string'
},
'autoload': {
'$ref': '#/definitions/dependency_selection'},
'prerequisites': {
'$ref': '#/definitions/dependency_selection'},
'conflict': {
'$ref': '#/definitions/array_of_strings'},
'load': {
'$ref': '#/definitions/array_of_strings'},
'suffixes': {
'$ref': '#/definitions/dictionary_of_strings'},
'environment': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'set': {
'$ref': '#/definitions/dictionary_of_strings'},
'unset': {
'$ref': '#/definitions/array_of_strings'},
'prepend_path': {
'$ref': '#/definitions/dictionary_of_strings'},
'append_path': {
'$ref': '#/definitions/dictionary_of_strings'}
}
}
}
},
'module_type_configuration': {
'type': 'object',
'default': {},
'anyOf': [
{'properties': {
'verbose': {
'type': 'boolean',
'default': False
},
'hash_length': {
'type': 'integer',
'minimum': 0,
'default': 7
},
'whitelist': {
'$ref': '#/definitions/array_of_strings'},
'blacklist': {
'$ref': '#/definitions/array_of_strings'},
'blacklist_implicits': {
'type': 'boolean',
'default': False
},
'naming_scheme': {
'type': 'string' # Can we be more specific here?
}
}},
{'patternProperties': {
r'\w[\w-]*': {
'$ref': '#/definitions/module_file_configuration'
}
}}
]
} }
}, },
'patternProperties': { 'dictionary_of_strings': {
r'modules': { 'type': 'object',
'type': 'object', 'patternProperties': {
'default': {}, r'\w[\w-]*': { # key
'additionalProperties': False, 'type': 'string'
'properties': {
'prefix_inspections': {
'type': 'object',
'patternProperties': {
# prefix-relative path to be inspected for existence
r'\w[\w-]*': {
'$ref': '#/definitions/array_of_strings'}}},
'enable': {
'type': 'array',
'default': [],
'items': {
'type': 'string',
'enum': ['tcl', 'dotkit', 'lmod']}},
'lmod': {
'allOf': [
# Base configuration
{'$ref': '#/definitions/module_type_configuration'},
{
'core_compilers': {
'$ref': '#/definitions/array_of_strings'
},
'hierarchical_scheme': {
'$ref': '#/definitions/array_of_strings'
}
} # Specific lmod extensions
]},
'tcl': {
'allOf': [
# Base configuration
{'$ref': '#/definitions/module_type_configuration'},
{} # Specific tcl extensions
]},
'dotkit': {
'allOf': [
# Base configuration
{'$ref': '#/definitions/module_type_configuration'},
{} # Specific dotkit extensions
]},
} }
}
},
'dependency_selection': {
'type': 'string',
'enum': ['none', 'direct', 'all']
},
'module_file_configuration': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'filter': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'environment_blacklist': {
'type': 'array',
'default': [],
'items': {
'type': 'string'
}
}
}
},
'template': {
'type': 'string'
},
'autoload': {
'$ref': '#/definitions/dependency_selection'},
'prerequisites': {
'$ref': '#/definitions/dependency_selection'},
'conflict': {
'$ref': '#/definitions/array_of_strings'},
'load': {
'$ref': '#/definitions/array_of_strings'},
'suffixes': {
'$ref': '#/definitions/dictionary_of_strings'},
'environment': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'set': {
'$ref': '#/definitions/dictionary_of_strings'},
'unset': {
'$ref': '#/definitions/array_of_strings'},
'prepend_path': {
'$ref': '#/definitions/dictionary_of_strings'},
'append_path': {
'$ref': '#/definitions/dictionary_of_strings'}
}
}
}
},
'module_type_configuration': {
'type': 'object',
'default': {},
'anyOf': [
{'properties': {
'verbose': {
'type': 'boolean',
'default': False
},
'hash_length': {
'type': 'integer',
'minimum': 0,
'default': 7
},
'whitelist': {
'$ref': '#/definitions/array_of_strings'},
'blacklist': {
'$ref': '#/definitions/array_of_strings'},
'blacklist_implicits': {
'type': 'boolean',
'default': False
},
'naming_scheme': {
'type': 'string' # Can we be more specific here?
}
}},
{'patternProperties': {
r'\w[\w-]*': {
'$ref': '#/definitions/module_file_configuration'
}
}}
]
}
}
# Properties for inclusion into other schemas (requires definitions)
properties = {
'modules': {
'type': 'object',
'default': {},
'additionalProperties': False,
'properties': {
'prefix_inspections': {
'type': 'object',
'patternProperties': {
# prefix-relative path to be inspected for existence
r'\w[\w-]*': {
'$ref': '#/definitions/array_of_strings'}}},
'enable': {
'type': 'array',
'default': [],
'items': {
'type': 'string',
'enum': ['tcl', 'dotkit', 'lmod']}},
'lmod': {
'allOf': [
# Base configuration
{'$ref': '#/definitions/module_type_configuration'},
{
'core_compilers': {
'$ref': '#/definitions/array_of_strings'
},
'hierarchical_scheme': {
'$ref': '#/definitions/array_of_strings'
}
} # Specific lmod extensions
]
},
'tcl': {
'allOf': [
# Base configuration
{'$ref': '#/definitions/module_type_configuration'},
{} # Specific tcl extensions
]
},
'dotkit': {
'allOf': [
# Base configuration
{'$ref': '#/definitions/module_type_configuration'},
{} # Specific dotkit extensions
]
},
}, },
}, },
} }
#: Full schema with metadata
schema = {
'$schema': 'http://json-schema.org/schema#',
'title': 'Spack module file configuration file schema',
'definitions': definitions,
'type': 'object',
'additionalProperties': False,
'properties': properties,
}

View File

@ -10,79 +10,84 @@
""" """
schema = { #: Properties for inclusion in other schemas
'$schema': 'http://json-schema.org/schema#', properties = {
'title': 'Spack package configuration file schema', 'packages': {
'type': 'object', 'type': 'object',
'additionalProperties': False, 'default': {},
'patternProperties': { 'additionalProperties': False,
r'packages': { 'patternProperties': {
'type': 'object', r'\w[\w-]*': { # package name
'default': {}, 'type': 'object',
'additionalProperties': False, 'default': {},
'patternProperties': { 'additionalProperties': False,
r'\w[\w-]*': { # package name 'properties': {
'type': 'object', 'version': {
'default': {}, 'type': 'array',
'additionalProperties': False, 'default': [],
'properties': { # version strings
'version': { 'items': {'anyOf': [{'type': 'string'},
'type': 'array', {'type': 'number'}]}},
'default': [], 'compiler': {
# version strings 'type': 'array',
'items': {'anyOf': [{'type': 'string'}, 'default': [],
{'type': 'number'}]}}, 'items': {'type': 'string'}}, # compiler specs
'compiler': { 'buildable': {
'type': 'array', 'type': 'boolean',
'default': [], 'default': True,
'items': {'type': 'string'}}, # compiler specs },
'buildable': { 'permissions': {
'type': 'boolean', 'type': 'object',
'default': True, 'additionalProperties': False,
}, 'properties': {
'permissions': { 'read': {
'type': 'object', 'type': 'string',
'additionalProperties': False, 'enum': ['user', 'group', 'world'],
'properties': { },
'read': { 'write': {
'type': 'string', 'type': 'string',
'enum': ['user', 'group', 'world'], 'enum': ['user', 'group', 'world'],
}, },
'write': { 'group': {
'type': 'string', 'type': 'string',
'enum': ['user', 'group', 'world'],
},
'group': {
'type': 'string',
},
}, },
}, },
'modules': { },
'type': 'object', 'modules': {
'default': {}, 'type': 'object',
}, 'default': {},
'providers': { },
'type': 'object', 'providers': {
'default': {}, 'type': 'object',
'additionalProperties': False, 'default': {},
'patternProperties': { 'additionalProperties': False,
r'\w[\w-]*': { 'patternProperties': {
'type': 'array', r'\w[\w-]*': {
'default': [], 'type': 'array',
'items': {'type': 'string'}, }, }, }, 'default': [],
'paths': { 'items': {'type': 'string'}, }, }, },
'type': 'object', 'paths': {
'default': {}, 'type': 'object',
}, 'default': {},
'variants': { },
'oneOf': [ 'variants': {
{'type': 'string'}, 'oneOf': [
{'type': 'array', {'type': 'string'},
'items': {'type': 'string'}}], {'type': 'array',
}, 'items': {'type': 'string'}}],
}, },
}, },
}, },
}, },
}, },
} }
#: Full schema with metadata
schema = {
'$schema': 'http://json-schema.org/schema#',
'title': 'Spack package configuration file schema',
'type': 'object',
'additionalProperties': False,
'properties': properties,
}

View File

@ -10,17 +10,21 @@
""" """
#: Properties for inclusion in other schemas
properties = {
'repos': {
'type': 'array',
'default': [],
'items': {'type': 'string'},
},
}
#: Full schema with metadata
schema = { schema = {
'$schema': 'http://json-schema.org/schema#', '$schema': 'http://json-schema.org/schema#',
'title': 'Spack repository configuration file schema', 'title': 'Spack repository configuration file schema',
'type': 'object', 'type': 'object',
'additionalProperties': False, 'additionalProperties': False,
'patternProperties': { 'properties': properties,
r'repos': {
'type': 'array',
'default': [],
'items': {
'type': 'string'},
},
},
} }

View File

@ -7,6 +7,7 @@
import collections import collections
import getpass import getpass
import tempfile import tempfile
from six import StringIO
from llnl.util.filesystem import touch, mkdirp from llnl.util.filesystem import touch, mkdirp
@ -15,6 +16,12 @@
import spack.paths import spack.paths
import spack.config import spack.config
import spack.schema.compilers
import spack.schema.config
import spack.schema.packages
import spack.schema.mirrors
import spack.schema.repos
import spack.util.spack_yaml as syaml
from spack.util.path import canonicalize_path from spack.util.path import canonicalize_path
@ -631,7 +638,7 @@ def test_add_command_line_scopes(tmpdir, mutable_config):
spack.config._add_command_line_scopes(mutable_config, [str(tmpdir)]) spack.config._add_command_line_scopes(mutable_config, [str(tmpdir)])
def test_immuntable_scope(tmpdir): def test_immutable_scope(tmpdir):
config_yaml = str(tmpdir.join('config.yaml')) config_yaml = str(tmpdir.join('config.yaml'))
with open(config_yaml, 'w') as f: with open(config_yaml, 'w') as f:
f.write("""\ f.write("""\
@ -645,3 +652,58 @@ def test_immuntable_scope(tmpdir):
with pytest.raises(spack.config.ConfigError): with pytest.raises(spack.config.ConfigError):
scope.write_section('config') scope.write_section('config')
def check_schema(name, file_contents):
"""Check a Spack YAML schema against some data"""
f = StringIO(file_contents)
data = syaml.load(f)
spack.config._validate(data, name)
def test_bad_config_yaml(tmpdir):
with pytest.raises(spack.config.ConfigFormatError):
check_schema(spack.schema.config.schema, """\
config:
verify_ssl: False
module_roots:
fmod: /some/fake/location
""")
def test_bad_mirrors_yaml(tmpdir):
with pytest.raises(spack.config.ConfigFormatError):
check_schema(spack.schema.mirrors.schema, """\
mirrors:
local: True
""")
def test_bad_repos_yaml(tmpdir):
with pytest.raises(spack.config.ConfigFormatError):
check_schema(spack.schema.repos.schema, """\
repos:
True
""")
def test_bad_compilers_yaml(tmpdir):
with pytest.raises(spack.config.ConfigFormatError):
check_schema(spack.schema.compilers.schema, """\
compilers:
key_instead_of_list: 'value'
""")
with pytest.raises(spack.config.ConfigFormatError):
check_schema(spack.schema.compilers.schema, """\
compilers:
- shmompiler:
environment: /bad/value
""")
with pytest.raises(spack.config.ConfigFormatError):
check_schema(spack.schema.compilers.schema, """\
compilers:
- compiler:
fenfironfent: /bad/value
""")