configurationengine/source/scripts/conesub_validate.py
changeset 3 e7e0ae78773e
--- /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()