diff --git a/ostack_validator/config_formats/ini.py b/ostack_validator/config_formats/ini.py index fd1013c..b6c49d2 100644 --- a/ostack_validator/config_formats/ini.py +++ b/ostack_validator/config_formats/ini.py @@ -7,12 +7,15 @@ from ostack_validator.config_formats.common import * class IniConfigParser: key_value_re = re.compile("^(\w+)\s*([:=])\s*('.*'|\".*\"|.*)\s*$") - def parse(self, name, io): + def parse(self, name, base_mark, io): if not hasattr(io, 'readlines'): io = StringIO(io) + def mark(line, column=0): + return base_mark.merge(Mark('', line, column)) + errors = [] - current_section_name = ConfigSectionName(Mark(name, 0, 0), Mark(name, 0, 0), '') + current_section_name = ConfigSectionName(mark(0), mark(0), '') current_param_name = None current_param_value = None current_param_delimiter = None @@ -37,52 +40,52 @@ class IniConfigParser: if line[0].isspace(): if current_param_name: - current_param_value.end_mark = Mark(name, line_number, len(line)) + current_param_value.end_mark = mark(line_number, len(line)) current_param_value.text += line.lstrip() continue else: - errors.append(ParseError('Unexpected multiline value continuation', Mark(name, line_number, 0))) + errors.append(ParseError('Unexpected multiline value continuation', mark(line_number))) continue if line[0] == '[': end_index = line.find(']') if end_index == -1: - errors.append(ParseError('Unclosed section', Mark(name, line_number, len(line)))) + errors.append(ParseError('Unclosed section', mark(line_number, len(line)))) end_index = len(line) while line[end_index-1].isspace(): end_index -= 1 if end_index <= 1: - errors.append(ParseError('Missing section name', Mark(name, line_number, 0))) + errors.append(ParseError('Missing section name', mark(line_number))) continue else: i = end_index+1 while i < len(line): if not line[i].isspace(): - errors.append(ParseError('Extra chars after section name', Mark(name, line_number, i))) + errors.append(ParseError('Extra chars after section name', mark(line_number, i))) break i += 1 if current_section_name.text != '' or len(parameters) > 0: - section = ConfigSection(current_section_name.start_mark, Mark(name, line_number, 0), current_section_name, parameters) + section = ConfigSection(current_section_name.start_mark, mark(line_number), current_section_name, parameters) sections.append(section) parameters = [] current_section_name = ConfigSectionName( - Mark(name, line_number, 0), - Mark(name, line_number, end_index), + mark(line_number, 0), + mark(line_number, end_index), line[1:end_index] ) else: m = self.key_value_re.match(line) if m: current_param_name = ConfigParameterName( - Mark(name, line_number, m.start(1)), - Mark(name, line_number, m.end(1)), + mark(line_number, m.start(1)), + mark(line_number, m.end(1)), m.group(1) ) current_param_delimiter = TextElement( - Mark(name, line_number, m.start(2)), - Mark(name, line_number, m.end(2)), + mark(line_number, m.start(2)), + mark(line_number, m.end(2)), m.group(2) ) @@ -94,13 +97,13 @@ class IniConfigParser: value = value[1:-1] current_param_value = ConfigParameterValue( - Mark(name, line_number, m.start(3)), - Mark(name, line_number, m.end(3)), + mark(line_number, m.start(3)), + mark(line_number, m.end(3)), value, quotechar ) else: - errors.append(ParseError('Syntax error', Mark(name, line_number, 0))) + errors.append(ParseError('Syntax error', mark(line_number))) line_number += 1 @@ -109,11 +112,15 @@ class IniConfigParser: parameters.append(param) if current_section_name.text != '' or len(parameters) > 0: - section = ConfigSection(current_section_name.start_mark, Mark(name, line_number, 0), current_section_name, parameters) + section = ConfigSection(current_section_name.start_mark, mark(line_number), current_section_name, parameters) sections.append(section) parameters = [] - config = ComponentConfig(name, Mark(name), sections, errors) + end_mark = base_mark + if len(sections) > 0: + end_mark = base_mark.merge(sections[-1].end_mark) + + config = ComponentConfig(base_mark, end_mark, name, sections, errors) return config diff --git a/ostack_validator/config_formats/test_ini.py b/ostack_validator/config_formats/test_ini.py index 2ecbadc..8d26116 100644 --- a/ostack_validator/config_formats/test_ini.py +++ b/ostack_validator/config_formats/test_ini.py @@ -22,7 +22,7 @@ class IniConfigParserTests(unittest.TestCase): if margin: content = self._strip_margin(content) - return self.parser.parse('test.conf', content) + return self.parser.parse('test.conf', Mark(''), content) def test_parsing(self): config = self.parse("param1 = value1") diff --git a/ostack_validator/inspection.py b/ostack_validator/inspection.py index 55ed5c8..ba1f89b 100644 --- a/ostack_validator/inspection.py +++ b/ostack_validator/inspection.py @@ -41,11 +41,11 @@ class MainConfigValidationInspection(Inspection): for parameter in section.parameters: parameter_schema = schema.get_parameter(name=parameter.name.text, section=section.name.text) if not parameter_schema: - results.append(MarkedIssue(Issue.WARNING, 'Unknown parameter "%s"' % parameter.name.text, main_config.mark.merge(parameter.start_mark))) + results.append(MarkedIssue(Issue.WARNING, 'Unknown parameter "%s"' % parameter.name.text, parameter.start_mark)) continue if parameter.name.text in seen_parameters: - results.append(MarkedIssue(Issue.WARNING, 'Parameter "%s" in section "%s" redeclared' % (parameter.name.text, section_name), main_config.mark.merge(parameter.start_mark))) + results.append(MarkedIssue(Issue.WARNING, 'Parameter "%s" in section "%s" redeclared' % (parameter.name.text, section_name), parameter.start_mark)) else: seen_parameters.add(parameter.name.text) @@ -53,13 +53,13 @@ class MainConfigValidationInspection(Inspection): type_validation_result = type_validator.validate(parameter.value.text) if isinstance(type_validation_result, Issue): self.logger.debug('Got issue for parameter "%s" with value "%s"' % (parameter.name.text, parameter.value.text)) - type_validation_result.mark = main_config.mark.merge(parameter.value.start_mark.merge(type_validation_result.mark)) + type_validation_result.mark = parameter.value.start_mark.merge(type_validation_result.mark) results.append(type_validation_result) else: value = type_validation_result if value == parameter_schema.default: - results.append(MarkedIssue(Issue.INFO, 'Parameter "%s" value equals default' % parameter.name.text, main_config.mark.merge(parameter.start_mark))) + results.append(MarkedIssue(Issue.INFO, 'Parameter "%s" value equals default' % parameter.name.text, parameter.start_mark)) return results diff --git a/ostack_validator/model.py b/ostack_validator/model.py index 1072ea2..040bb37 100644 --- a/ostack_validator/model.py +++ b/ostack_validator/model.py @@ -40,25 +40,13 @@ class OpenstackComponent(object): if not config_name in self.configs: resource = self.openstack.resource_locator.find_resource(self.host.name, self.name, config_name) if resource: - config = self.openstack.config_parser.parse(config_name, resource.get_contents()) - config.mark = Mark(resource.name) + config = self.openstack.config_parser.parse(config_name, Mark(resource.name), resource.get_contents()) self.configs[config_name] = config else: self.configs[config_name] = None return self.configs[config_name] -class ComponentConfig(object): - def __init__(self, name, mark, sections=[], errors=[]): - super(ComponentConfig, self).__init__() - self.name = name - self.mark = mark - self.sections = sections - for section in self.sections: - section.parent = self - - self.errors = errors - class Element(object): def __init__(self, start_mark, end_mark): self.start_mark = start_mark @@ -70,6 +58,16 @@ class Element(object): def __ne__(self, other): return not self == other +class ComponentConfig(Element): + def __init__(self, start_mark, end_mark, name, sections=[], errors=[]): + super(ComponentConfig, self).__init__(start_mark, end_mark) + self.name = name + self.sections = sections + for section in self.sections: + section.parent = self + + self.errors = errors + class TextElement(Element): def __init__(self, start_mark, end_mark, text): super(TextElement, self).__init__(start_mark, end_mark)