Merge #425 config: Validate variant regular expressions
This commit is contained in:
commit
bb933c83ae
@ -38,6 +38,7 @@ When a new config option is added, the schema must be updated (see the
|
|||||||
import os.path
|
import os.path
|
||||||
import platform
|
import platform
|
||||||
import jsonschema
|
import jsonschema
|
||||||
|
import re
|
||||||
|
|
||||||
from . import util
|
from . import util
|
||||||
|
|
||||||
@ -174,7 +175,9 @@ def validate(config):
|
|||||||
"""
|
"""
|
||||||
schema = _make_schema()
|
schema = _make_schema()
|
||||||
DefaultValidator = _extend_with_default(jsonschema.Draft4Validator)
|
DefaultValidator = _extend_with_default(jsonschema.Draft4Validator)
|
||||||
validator = DefaultValidator(schema, {'array': (tuple, list)})
|
validator = DefaultValidator(schema,
|
||||||
|
{'array': (tuple, list),
|
||||||
|
'regex': (str, unicode)})
|
||||||
errors = []
|
errors = []
|
||||||
for error in validator.iter_errors(config):
|
for error in validator.iter_errors(config):
|
||||||
if isinstance(error, ConfigDeprecation):
|
if isinstance(error, ConfigDeprecation):
|
||||||
@ -220,8 +223,13 @@ UNKNOWN_SUGGEST = 'Unrecognized config option: {0}. Did you mean {1}?'
|
|||||||
|
|
||||||
def _extend_with_default(validator_class):
|
def _extend_with_default(validator_class):
|
||||||
validate_properties = validator_class.VALIDATORS["properties"]
|
validate_properties = validator_class.VALIDATORS["properties"]
|
||||||
|
validate_type = validator_class.VALIDATORS['type']
|
||||||
|
|
||||||
def set_defaults(validator, properties, instance, schema):
|
def set_defaults(validator, properties, instance, schema):
|
||||||
|
"""
|
||||||
|
Assign default values to options that have them defined and are not
|
||||||
|
specified.
|
||||||
|
"""
|
||||||
for property, subschema in properties.iteritems():
|
for property, subschema in properties.iteritems():
|
||||||
if "default" in subschema and property not in instance:
|
if "default" in subschema and property not in instance:
|
||||||
instance.setdefault(property, subschema["default"])
|
instance.setdefault(property, subschema["default"])
|
||||||
@ -230,13 +238,32 @@ def _extend_with_default(validator_class):
|
|||||||
yield error
|
yield error
|
||||||
|
|
||||||
def error_on_deprecated(validator, properties, instance, schema):
|
def error_on_deprecated(validator, properties, instance, schema):
|
||||||
|
"""Unconditionally raise deprecation error if encountered."""
|
||||||
yield ConfigDeprecation(
|
yield ConfigDeprecation(
|
||||||
'use %s instead' % properties
|
'use %s instead' % properties
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_regex_type(validator, properties, instance, schema):
|
||||||
|
"""
|
||||||
|
Extend standard type validation to check correctness in regular
|
||||||
|
expressions.
|
||||||
|
"""
|
||||||
|
if properties == 'regex':
|
||||||
|
try:
|
||||||
|
re.compile(instance)
|
||||||
|
except re.error as exc:
|
||||||
|
yield jsonschema.ValidationError(
|
||||||
|
'incorrect regular expression: %s' % str(exc),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Not a regular expression, delegate to original validator.
|
||||||
|
for error in validate_type(validator, properties, instance, schema):
|
||||||
|
yield error
|
||||||
|
|
||||||
return jsonschema.validators.extend(
|
return jsonschema.validators.extend(
|
||||||
validator_class, {"properties": set_defaults,
|
validator_class, {"properties": set_defaults,
|
||||||
"deprecated": error_on_deprecated},
|
"deprecated": error_on_deprecated,
|
||||||
|
"type": validate_regex_type},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -258,25 +285,9 @@ def _make_schema():
|
|||||||
"additionalProperties": False,
|
"additionalProperties": False,
|
||||||
},
|
},
|
||||||
|
|
||||||
"package_mapping": {
|
"package_mapping": _variant_arch_mapping(
|
||||||
"type": "array",
|
{"$ref": "#/definitions/list_of_strings"}
|
||||||
"items": {
|
),
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"patternProperties": {
|
|
||||||
".+": {"$ref": "#/definitions/list_of_strings"},
|
|
||||||
},
|
|
||||||
"additionalProperties": False,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"additionalItems": False,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"scm_dict": {
|
"scm_dict": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -618,6 +629,9 @@ def _make_schema():
|
|||||||
"live_media": {
|
"live_media": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
|
# Warning: this pattern is a variant uid regex, but the
|
||||||
|
# format does not let us validate it as there is no regular
|
||||||
|
# expression to describe all regular expressions.
|
||||||
".+": {
|
".+": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@ -695,6 +709,9 @@ def _make_schema():
|
|||||||
"image_build": {
|
"image_build": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
|
# Warning: this pattern is a variant uid regex, but the
|
||||||
|
# format does not let us validate it as there is no regular
|
||||||
|
# expression to describe all regular expressions.
|
||||||
".+": {
|
".+": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@ -764,6 +781,9 @@ def _make_schema():
|
|||||||
"osbs": {
|
"osbs": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
|
# Warning: this pattern is a variant uid regex, but the
|
||||||
|
# format does not let us validate it as there is no regular
|
||||||
|
# expression to describe all regular expressions.
|
||||||
".+": {
|
".+": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -839,7 +859,7 @@ def _variant_arch_mapping(value):
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": [
|
"items": [
|
||||||
{"type": "string"},
|
{"type": "regex"},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"patternProperties": {".+": value},
|
"patternProperties": {".+": value},
|
||||||
|
@ -379,5 +379,16 @@ class TestSuggestions(unittest.TestCase):
|
|||||||
[checks.UNKNOWN_SUGGEST.format('product_pid', 'product_id')])
|
[checks.UNKNOWN_SUGGEST.format('product_pid', 'product_id')])
|
||||||
|
|
||||||
|
|
||||||
|
class TestRegexValidation(unittest.TestCase):
|
||||||
|
def test_incorrect_regular_expression(self):
|
||||||
|
cfg = load_config(PKGSET_REPOS,
|
||||||
|
multilib=[('^*$', {'*': []})])
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
checks.validate(cfg),
|
||||||
|
['Failed validation in multilib.0.0: incorrect regular '
|
||||||
|
'expression: nothing to repeat'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Loading…
Reference in New Issue
Block a user