configurationengine/source/scripts/conesub_validate.py
changeset 3 e7e0ae78773e
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 import sys, os, shutil
       
    18 import logging
       
    19 from optparse import OptionParser, OptionGroup
       
    20 import cone_common
       
    21 from cone.report import report_util
       
    22 from cone.public import api, exceptions, utils, plugin, parsecontext
       
    23 import cone.validation.parsecontext
       
    24 import cone.validation.schemavalidation
       
    25 import cone.validation.implmlvalidation
       
    26 import cone.validation.confmlvalidation
       
    27 from cone.validation.problem_type_filter import ProblemTypeFilter
       
    28 
       
    29 ROOT_PATH = os.path.abspath(os.path.dirname(__file__))
       
    30 
       
    31 VERSION     = '1.0'
       
    32 
       
    33 logger    = logging.getLogger('cone')
       
    34 
       
    35 REPORT_SHORTCUTS = {
       
    36     'xml': report_util.ReportShortcut(
       
    37         os.path.join(ROOT_PATH, 'validation_report_template.xml'),
       
    38         'validation_report.xml',
       
    39         "Create a validation report of xml type."),
       
    40     
       
    41     'html': report_util.ReportShortcut(
       
    42         os.path.join(ROOT_PATH, 'validation_report_template.html'),
       
    43         'validation_report.html',
       
    44         "Create a validation report of html type."),
       
    45 }
       
    46 
       
    47 def main():
       
    48     """ Validate a configuration, or individual confml/implml files. """
       
    49     shortcut_container = report_util.ReportShortcutContainer(REPORT_SHORTCUTS,
       
    50                                                              'html')
       
    51 
       
    52     parser = OptionParser(version="ConE validate %s" % VERSION)
       
    53     
       
    54     parser.add_options(cone_common.COMMON_OPTIONS)
       
    55     
       
    56     parser.add_option("-c", "--configuration",
       
    57                         dest="configuration",
       
    58                         help="Defines the name of the configuration for the action",
       
    59                         metavar="CONFIG")
       
    60 
       
    61     parser.add_option("-p", "--project",
       
    62                        dest="project",
       
    63                        default=".",
       
    64                        help="defines the location of current project. Default is the "\
       
    65                             "current working directory.",
       
    66                        metavar="STORAGE")
       
    67     
       
    68     group = OptionGroup(parser, 'Validate options',
       
    69                         'The validate action is intended for performing validation on a     '\
       
    70                         'configuration or individual files.                                 ')
       
    71     
       
    72     group.add_option('--confml-file',
       
    73                      action="append",
       
    74                      help='Validate only the given single ConfML file.',
       
    75                      metavar="FILE",
       
    76                      default=None)
       
    77     
       
    78     group.add_option('--implml-file',
       
    79                      action="append",
       
    80                      help='Validate only the given single ImplML file.',
       
    81                      metavar="FILE",
       
    82                      default=None)
       
    83         
       
    84     group.add_option("--template",
       
    85                      help="Template used in report generation. "\
       
    86                           "Example: --template=report_template.html.",
       
    87                      metavar="FILE",
       
    88                      default=None)
       
    89         
       
    90     group.add_option("--report-type",
       
    91                    help="The type of the report to generate. This is a convenience "\
       
    92                         "switch for setting the used template. If --template is given, this option has no effect. "\
       
    93                         "Possible values:                                        "\
       
    94                         + shortcut_container.get_shortcut_help_text(),
       
    95                    metavar="TYPE",\
       
    96                    default=None)    
       
    97     
       
    98     group.add_option("--report",
       
    99                    help="Specifies the location of the validation report. "\
       
   100                         "Example --report=report.html.",
       
   101                    metavar="FILE",
       
   102                    default=None)
       
   103     
       
   104     group.add_option("--dump-schema-files",
       
   105                      help="Dump the XML schema files used for validation into the specified directory.",
       
   106                      metavar="DIR",
       
   107                      default=None)
       
   108 
       
   109     group.add_option("--exclude-filter",
       
   110                      action="append",
       
   111                      help="Exclude validation problems by given filter. "\
       
   112                           "Examples: --exclude-filter=schema, --exclude-filter=schema.implml, --exclude-filter=schema.confml, --exclude-filter=schema.implml.ruleml",
       
   113                      default=None)
       
   114 
       
   115     group.add_option("--include-filter",
       
   116                      action="append",
       
   117                      help="Include validation problems by given filter."\
       
   118                           "Examples: --include-filter=schema.implml, --include-filter=schema.implml.ruleml",
       
   119                      default=None)
       
   120 
       
   121     parser.add_option_group(group)
       
   122     (options, _) = parser.parse_args()
       
   123     
       
   124     cone_common.handle_common_options(options)
       
   125     
       
   126     if not shortcut_container.is_valid_shortcut(options.report_type):
       
   127         parser.error("Invalid report type: %s" % options.report_type)
       
   128             
       
   129     if options.dump_schema_files:
       
   130         dump_dir = options.dump_schema_files
       
   131         print "Dumping XML schema files to '%s'" % dump_dir
       
   132         
       
   133         cone.validation.schemavalidation.dump_schema_files(dump_dir)
       
   134         return
       
   135     
       
   136     pt_filter = ProblemTypeFilter(includes = options.include_filter or [],
       
   137                                excludes = options.exclude_filter or [])
       
   138     
       
   139     problems = []
       
   140     if options.confml_file or options.implml_file:
       
   141         if options.confml_file:
       
   142             
       
   143             func = cone.validation.schemavalidation.validate_confml_data
       
   144             for file in options.confml_file:
       
   145                 problems.extend(validate_file(file, func))
       
   146         if options.implml_file:
       
   147             func = cone.validation.schemavalidation.validate_implml_data
       
   148             for file in options.implml_file:
       
   149                 problems.extend(validate_file(file, func))
       
   150     else:
       
   151         problems = validate_configuration(options.project, options.configuration, pt_filter)
       
   152     
       
   153     if problems is not None:
       
   154         filters = {'filter_by_severity':filter_by_severity}
       
   155         problems = pt_filter.filter(problems)
       
   156         
       
   157         print "Total %d problem(s) after filtering" % len(problems)
       
   158         
       
   159         print "Generating report..."
       
   160         problems.sort(key=lambda p: (p.severity, p.file, p.line))
       
   161         template, report = shortcut_container.determine_template_and_report(
       
   162             options.report_type,
       
   163             options.template,
       
   164             options.report,
       
   165             'validation_report')
       
   166         report_util.generate_report(template, report, {'problems': problems},extra_filters=filters)
       
   167 
       
   168 def extend_without_duplicates(source, target):
       
   169     for item in source:
       
   170         if item not in target:
       
   171             target.append(item)
       
   172 
       
   173 def validate_file(filename, validator_func):
       
   174     if not os.path.isfile(filename):
       
   175         print "'%s' does not exist or is not a file!" % filename
       
   176         return
       
   177     else:
       
   178         print "Validating file '%s'" % filename
       
   179     
       
   180     f = open(filename, 'rb')
       
   181     try:        data = f.read()
       
   182     finally:    f.close()
       
   183     
       
   184     problems = []
       
   185     try:
       
   186         validator_func(data)
       
   187     except exceptions.ParseError, e:
       
   188         problems.append(api.Problem.from_exception(e))
       
   189     print "Found %d problem(s)" % len(problems)
       
   190     
       
   191     for p in problems:
       
   192         p.file = filename
       
   193     return problems
       
   194 
       
   195 def validate_configuration(project_path, config_path, problem_type_filter):
       
   196     print "Project:       %s" % project_path
       
   197     try:
       
   198         project = api.Project(api.Storage.open(project_path, 'r'))
       
   199     except exceptions.StorageException:
       
   200         print "No such project."
       
   201         return
       
   202     
       
   203     confml_parse_context = cone.validation.parsecontext.ValidationParseContext()
       
   204     parsecontext.set_confml_context(confml_parse_context)
       
   205     
       
   206     if config_path is None:
       
   207         config_path = project.get_storage().get_active_configuration()
       
   208         if config_path is None:
       
   209             print "Project does not have an active configuration, please specify the configuration using --configuration."
       
   210             return
       
   211     print "Configuration: %s" % config_path
       
   212     
       
   213     try:
       
   214         config  = project.get_configuration(config_path)
       
   215     except exceptions.NotFound:
       
   216         print "No such configuration in project."
       
   217         return
       
   218     
       
   219     result = []
       
   220     
       
   221     
       
   222     print "Finding ConfML files in configuration..."
       
   223     configs = config._traverse(type=api.Configuration)
       
   224     print "%d ConfML file(s)" % len(configs)
       
   225     print "%d problem(s) while parsing" % len(confml_parse_context.problems)
       
   226     result.extend(confml_parse_context.problems)
       
   227     
       
   228     # Schema-validate ConfML files if not filtered out
       
   229     if problem_type_filter.match('schema.confml'):
       
   230         print "Performing XML schema validation on ConfML files..."
       
   231         schema_problems = cone.validation.schemavalidation.validate_confml_file(config, config_path)
       
   232         for conf in configs:
       
   233             path = conf.get_full_path()
       
   234             problems = cone.validation.schemavalidation.validate_confml_file(config, path)
       
   235             schema_problems.extend(problems)
       
   236         print "%d problem(s)" % len(schema_problems)
       
   237         
       
   238         # Add the schema problems with duplicates removed, since XML parse
       
   239         # errors might have already been recorded in the ConfML parsing phase
       
   240         extend_without_duplicates(source=schema_problems, target=result)
       
   241     
       
   242     
       
   243     # Validate the ConfML model if not filtered out
       
   244     validator_classes = cone.validation.confmlvalidation.get_validator_classes(problem_type_filter)
       
   245     if validator_classes:
       
   246         print "Validating ConfML model..."
       
   247         model_problems = cone.validation.confmlvalidation.validate_configuration(config, validator_classes).problems
       
   248         print "%d problem(s)" % len(model_problems)
       
   249         result.extend(model_problems)
       
   250         
       
   251     
       
   252     print "Finding ImplML files in configuration..."
       
   253     impls = []
       
   254     for file in config.get_layer().list_implml():
       
   255         if plugin.ImplFactory.is_supported_impl_file(file):
       
   256             impls.append(file)
       
   257     print "Found %d supported files" % len(impls)
       
   258     
       
   259     # Schema-validate ImplML files if not filtered out
       
   260     if problem_type_filter.match('schema.implml'):
       
   261         print "Performing XML schema validation on ImplML files..."
       
   262         schema_problems = []
       
   263         for impl in impls:
       
   264             probs = cone.validation.schemavalidation.validate_implml_file(config, impl)
       
   265             schema_problems.extend(probs)
       
   266         print "%d problem(s)" % len(schema_problems)
       
   267         result.extend(schema_problems)
       
   268     
       
   269     # Validate the ImplML model if not filtered out
       
   270     if problem_type_filter.match('model.implml'):
       
   271         print "Parsing implementations..."
       
   272         implml_parse_context = cone.validation.parsecontext.ValidationParseContext()
       
   273         parsecontext.set_implml_context(implml_parse_context)
       
   274         impl_set = plugin.create_impl_set(impls, config)
       
   275         
       
   276         # Add the model-level problems with duplicates removed, since XML parse
       
   277         # errors might have already been recorded in the schema validation phase
       
   278         extend_without_duplicates(source=implml_parse_context.problems, target=result)
       
   279         
       
   280         
       
   281         validator_classes = cone.validation.implmlvalidation.get_validator_classes(problem_type_filter)
       
   282         if validator_classes:
       
   283             print "Validating implementations..."
       
   284             impl_problems = cone.validation.implmlvalidation.validate_impl_set(impl_set, config, validator_classes)
       
   285             print "%d problem(s)" % len(impl_problems)
       
   286             result.extend(impl_problems)
       
   287     
       
   288     return result
       
   289 
       
   290 
       
   291 def filter_by_severity(problems, severity):
       
   292     """
       
   293     Filter problems by severity
       
   294     """
       
   295     return [p for p in problems if p.severity == severity]
       
   296 
       
   297 if __name__ == "__main__":
       
   298     main()