diff -r 87cfa131b535 -r e7e0ae78773e configurationengine/source/scripts/conesub_validate.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configurationengine/source/scripts/conesub_validate.py Tue Aug 10 14:29:28 2010 +0300 @@ -0,0 +1,298 @@ +# +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# + +import sys, os, shutil +import logging +from optparse import OptionParser, OptionGroup +import cone_common +from cone.report import report_util +from cone.public import api, exceptions, utils, plugin, parsecontext +import cone.validation.parsecontext +import cone.validation.schemavalidation +import cone.validation.implmlvalidation +import cone.validation.confmlvalidation +from cone.validation.problem_type_filter import ProblemTypeFilter + +ROOT_PATH = os.path.abspath(os.path.dirname(__file__)) + +VERSION = '1.0' + +logger = logging.getLogger('cone') + +REPORT_SHORTCUTS = { + 'xml': report_util.ReportShortcut( + os.path.join(ROOT_PATH, 'validation_report_template.xml'), + 'validation_report.xml', + "Create a validation report of xml type."), + + 'html': report_util.ReportShortcut( + os.path.join(ROOT_PATH, 'validation_report_template.html'), + 'validation_report.html', + "Create a validation report of html type."), +} + +def main(): + """ Validate a configuration, or individual confml/implml files. """ + shortcut_container = report_util.ReportShortcutContainer(REPORT_SHORTCUTS, + 'html') + + parser = OptionParser(version="ConE validate %s" % VERSION) + + parser.add_options(cone_common.COMMON_OPTIONS) + + parser.add_option("-c", "--configuration", + dest="configuration", + help="Defines the name of the configuration for the action", + metavar="CONFIG") + + parser.add_option("-p", "--project", + dest="project", + default=".", + help="defines the location of current project. Default is the "\ + "current working directory.", + metavar="STORAGE") + + group = OptionGroup(parser, 'Validate options', + 'The validate action is intended for performing validation on a '\ + 'configuration or individual files. ') + + group.add_option('--confml-file', + action="append", + help='Validate only the given single ConfML file.', + metavar="FILE", + default=None) + + group.add_option('--implml-file', + action="append", + help='Validate only the given single ImplML file.', + metavar="FILE", + default=None) + + group.add_option("--template", + help="Template used in report generation. "\ + "Example: --template=report_template.html.", + metavar="FILE", + default=None) + + group.add_option("--report-type", + help="The type of the report to generate. This is a convenience "\ + "switch for setting the used template. If --template is given, this option has no effect. "\ + "Possible values: "\ + + shortcut_container.get_shortcut_help_text(), + metavar="TYPE",\ + default=None) + + group.add_option("--report", + help="Specifies the location of the validation report. "\ + "Example --report=report.html.", + metavar="FILE", + default=None) + + group.add_option("--dump-schema-files", + help="Dump the XML schema files used for validation into the specified directory.", + metavar="DIR", + default=None) + + group.add_option("--exclude-filter", + action="append", + help="Exclude validation problems by given filter. "\ + "Examples: --exclude-filter=schema, --exclude-filter=schema.implml, --exclude-filter=schema.confml, --exclude-filter=schema.implml.ruleml", + default=None) + + group.add_option("--include-filter", + action="append", + help="Include validation problems by given filter."\ + "Examples: --include-filter=schema.implml, --include-filter=schema.implml.ruleml", + default=None) + + parser.add_option_group(group) + (options, _) = parser.parse_args() + + cone_common.handle_common_options(options) + + if not shortcut_container.is_valid_shortcut(options.report_type): + parser.error("Invalid report type: %s" % options.report_type) + + if options.dump_schema_files: + dump_dir = options.dump_schema_files + print "Dumping XML schema files to '%s'" % dump_dir + + cone.validation.schemavalidation.dump_schema_files(dump_dir) + return + + pt_filter = ProblemTypeFilter(includes = options.include_filter or [], + excludes = options.exclude_filter or []) + + problems = [] + if options.confml_file or options.implml_file: + if options.confml_file: + + func = cone.validation.schemavalidation.validate_confml_data + for file in options.confml_file: + problems.extend(validate_file(file, func)) + if options.implml_file: + func = cone.validation.schemavalidation.validate_implml_data + for file in options.implml_file: + problems.extend(validate_file(file, func)) + else: + problems = validate_configuration(options.project, options.configuration, pt_filter) + + if problems is not None: + filters = {'filter_by_severity':filter_by_severity} + problems = pt_filter.filter(problems) + + print "Total %d problem(s) after filtering" % len(problems) + + print "Generating report..." + problems.sort(key=lambda p: (p.severity, p.file, p.line)) + template, report = shortcut_container.determine_template_and_report( + options.report_type, + options.template, + options.report, + 'validation_report') + report_util.generate_report(template, report, {'problems': problems},extra_filters=filters) + +def extend_without_duplicates(source, target): + for item in source: + if item not in target: + target.append(item) + +def validate_file(filename, validator_func): + if not os.path.isfile(filename): + print "'%s' does not exist or is not a file!" % filename + return + else: + print "Validating file '%s'" % filename + + f = open(filename, 'rb') + try: data = f.read() + finally: f.close() + + problems = [] + try: + validator_func(data) + except exceptions.ParseError, e: + problems.append(api.Problem.from_exception(e)) + print "Found %d problem(s)" % len(problems) + + for p in problems: + p.file = filename + return problems + +def validate_configuration(project_path, config_path, problem_type_filter): + print "Project: %s" % project_path + try: + project = api.Project(api.Storage.open(project_path, 'r')) + except exceptions.StorageException: + print "No such project." + return + + confml_parse_context = cone.validation.parsecontext.ValidationParseContext() + parsecontext.set_confml_context(confml_parse_context) + + if config_path is None: + config_path = project.get_storage().get_active_configuration() + if config_path is None: + print "Project does not have an active configuration, please specify the configuration using --configuration." + return + print "Configuration: %s" % config_path + + try: + config = project.get_configuration(config_path) + except exceptions.NotFound: + print "No such configuration in project." + return + + result = [] + + + print "Finding ConfML files in configuration..." + configs = config._traverse(type=api.Configuration) + print "%d ConfML file(s)" % len(configs) + print "%d problem(s) while parsing" % len(confml_parse_context.problems) + result.extend(confml_parse_context.problems) + + # Schema-validate ConfML files if not filtered out + if problem_type_filter.match('schema.confml'): + print "Performing XML schema validation on ConfML files..." + schema_problems = cone.validation.schemavalidation.validate_confml_file(config, config_path) + for conf in configs: + path = conf.get_full_path() + problems = cone.validation.schemavalidation.validate_confml_file(config, path) + schema_problems.extend(problems) + print "%d problem(s)" % len(schema_problems) + + # Add the schema problems with duplicates removed, since XML parse + # errors might have already been recorded in the ConfML parsing phase + extend_without_duplicates(source=schema_problems, target=result) + + + # Validate the ConfML model if not filtered out + validator_classes = cone.validation.confmlvalidation.get_validator_classes(problem_type_filter) + if validator_classes: + print "Validating ConfML model..." + model_problems = cone.validation.confmlvalidation.validate_configuration(config, validator_classes).problems + print "%d problem(s)" % len(model_problems) + result.extend(model_problems) + + + print "Finding ImplML files in configuration..." + impls = [] + for file in config.get_layer().list_implml(): + if plugin.ImplFactory.is_supported_impl_file(file): + impls.append(file) + print "Found %d supported files" % len(impls) + + # Schema-validate ImplML files if not filtered out + if problem_type_filter.match('schema.implml'): + print "Performing XML schema validation on ImplML files..." + schema_problems = [] + for impl in impls: + probs = cone.validation.schemavalidation.validate_implml_file(config, impl) + schema_problems.extend(probs) + print "%d problem(s)" % len(schema_problems) + result.extend(schema_problems) + + # Validate the ImplML model if not filtered out + if problem_type_filter.match('model.implml'): + print "Parsing implementations..." + implml_parse_context = cone.validation.parsecontext.ValidationParseContext() + parsecontext.set_implml_context(implml_parse_context) + impl_set = plugin.create_impl_set(impls, config) + + # Add the model-level problems with duplicates removed, since XML parse + # errors might have already been recorded in the schema validation phase + extend_without_duplicates(source=implml_parse_context.problems, target=result) + + + validator_classes = cone.validation.implmlvalidation.get_validator_classes(problem_type_filter) + if validator_classes: + print "Validating implementations..." + impl_problems = cone.validation.implmlvalidation.validate_impl_set(impl_set, config, validator_classes) + print "%d problem(s)" % len(impl_problems) + result.extend(impl_problems) + + return result + + +def filter_by_severity(problems, severity): + """ + Filter problems by severity + """ + return [p for p in problems if p.severity == severity] + +if __name__ == "__main__": + main()