diff options
author | Kevin Rocard <kevinx.rocard@intel.com> | 2013-06-10 19:05:46 +0200 |
---|---|---|
committer | David Wagner <david.wagner@intel.com> | 2014-02-12 17:04:02 +0100 |
commit | 1dff2e64afb47af468cc211efa229627367789b7 (patch) | |
tree | ae67109745402189b765d1ca70fac1ea4bec575c /tools/coverage.py | |
parent | 02726ec37a9686572f825520a04700061ffe5d06 (diff) | |
download | external_parameter-framework-1dff2e64afb47af468cc211efa229627367789b7.zip external_parameter-framework-1dff2e64afb47af468cc211efa229627367789b7.tar.gz external_parameter-framework-1dff2e64afb47af468cc211efa229627367789b7.tar.bz2 |
[coverage] Move coverage generator in it's own folder
BZ: 115218
The coverage report generated script was in the tools folder.
Other files will be used for coverage reports.
Create a coverage folder in order to contain all coverage report
utilities.
Change-Id: I23ed75fb109cd4a5f6804398ef17d99e046fd49d
Signed-off-by: Kevin Rocard <kevinx.rocard@intel.com>
Reviewed-on: http://android.intel.com:8080/114667
Reviewed-by: Denneulin, Guillaume <guillaume.denneulin@intel.com>
Reviewed-by: Gonzalve, Sebastien <sebastien.gonzalve@intel.com>
Reviewed-by: cactus <cactus@intel.com>
Tested-by: Dixon, CharlesX <charlesx.dixon@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
Diffstat (limited to 'tools/coverage.py')
-rwxr-xr-x | tools/coverage.py | 1048 |
1 files changed, 0 insertions, 1048 deletions
diff --git a/tools/coverage.py b/tools/coverage.py deleted file mode 100755 index df79b5b..0000000 --- a/tools/coverage.py +++ /dev/null @@ -1,1048 +0,0 @@ -#!/usr/bin/env python3 - -# INTEL CONFIDENTIAL -# Copyright 2013 Intel -# Corporation All Rights Reserved. -# -# The source code contained or described herein and all documents related to -# the source code ("Material") are owned by Intel Corporation or its suppliers -# or licensors. Title to the Material remains with Intel Corporation or its -# suppliers and licensors. The Material contains trade secrets and proprietary -# and confidential information of Intel or its suppliers and licensors. The -# Material is protected by worldwide copyright and trade secret laws and -# treaty provisions. No part of the Material may be used, copied, reproduced, -# modified, published, uploaded, posted, transmitted, distributed, or -# disclosed in any way without Intels prior express written permission. -# -# No license under any patent, copyright, trade secret or other intellectual -# property right is granted to or conferred upon you by disclosure or delivery -# of the Materials, either expressly, by implication, inducement, estoppel or -# otherwise. Any license under such intellectual property rights must be -# express and approved by Intel in writing. - -""" -Generate a coverage report by parsing parameter framework log. - -The coverage report contains the: - - domain - - configuration - - rule - - criterion -basic coverage statistics. -""" - -import xml.dom.minidom -import sys -import re -import logging - -FORMAT = '%(levelname)s: %(message)s' -logging.basicConfig(stream=sys.stderr, level=logging.WARNING, format=FORMAT) -logger = logging.getLogger("Coverage") - -class CustomError(Exception): - pass - -class ChildError(CustomError): - def __init__(self, parent, child): - self.parent = parent - self.child = child - -class ChildNotFoundError(ChildError): - def __str__(self): - return "Unable to find the child %s in %s" % (self.child, self.parent) - -class DuplicatedChildError(ChildError): - def __str__(self): - return "Add existing child %s in %s." % (self.child, self.parent) - -class Element(): - """Root class for all coverage elements""" - tag = "element" - - def __init__(self, name): - - self.parent = None - self.children = [] - - self.nbUse = 0 - - self.name = name - - self.debug("New element") - - - def __str__(self): - return "%s (%s)" % (self.name, self.tag) - - def __eq__(self, compared): - return (self.name == compared.name) and (self.children == compared.children) - - def getName(self, default=""): - return self.name or default - - def hasChildren(self): - return bool(self.children) - - def getChildren(self): - return self.children - - def _getDescendants(self): - for child in self.children: - yield child - for descendant in child._getDescendants() : - yield descendant - - def getChildFromName(self, childName): - - for child in self.children : - - if child.getName() == childName : - return child - - self.debug("Child %s not found" % childName, logging.ERROR) - - self.debug("Child list :") - - for child in self.children : - self.debug(" - %s" % child) - - raise ChildNotFoundError(self, childName) - - - def addChild(self, child): - self.debug("new child: " + child.name) - self.children.append(child) - child._adoptedBy(self) - - def _adoptedBy(self, parent): - assert(not self.parent) - self.parent = parent - - def _getElementNames(self, elementList): - return (substate.name for substate in elementList) - - def _description(self, withCoverage, withNbUse): - description = self.name - - if withNbUse or withCoverage : - description += " has been used " + str(self.nbUse) + " time" - - if withCoverage : - description += self._coverageFormating(self._getCoverage()) - - return description - - - def _getCoverage(self): - """Return the coverage of the element between 0 and 1 - - If the element has no coverage dependency (usually child) return 0 or 1. - otherwise the element coverage is the dependency coverage average""" - coverageDependanceElements = list(self._getCoverageDependanceElements()) - - nbcoverageDependence = len(coverageDependanceElements) - - if nbcoverageDependence == 0: - if self.nbUse == 0: - return 0 - else: - return 1 - - coverageDependenceValues = (depElement._getCoverage() - for depElement in coverageDependanceElements) - - return sum(coverageDependenceValues) / nbcoverageDependence - - def _getCoverageDependanceElements(self): - return self.children - - def _coverageFormating(self, coverage): - # If no coverage provided - if not coverage : - return "" - - # Calculate coverage - return " (%s coverage)" % self._number2percent(coverage) - - @staticmethod - def _number2percent(number): - """Format a number to a integer % string - - example: _number2percent(0.6666) -> "67%" - """ - return "{0:.0f}%".format(100 * number) - - - def _dumpDescription(self, withCoverage, withNbUse): - - self.debug("yelding description") - yield RankedLine(self._description(withCoverage, withNbUse), lineSuffix="") - - for dumped in self._dumpPropagate(withCoverage, withNbUse) : - yield dumped - - def _dumpPropagate(self, withCoverage, withNbUse): - - for child in self.children : - for dumpedDescription in child._dumpDescription(withCoverage, withNbUse) : - yield dumpedDescription.increasedRank() - - - def dump(self, withCoverage=False, withNbUse=True): - - return "\n".join( - str(dumpedDescription) for dumpedDescription in - self._dumpDescription(withCoverage, withNbUse)) - - def exportToXML(self, domElement=None): - if domElement == None: - domElement = xml.dom.minidom.Element(self.tag) - - self._XMLaddAttributes(domElement) - - for child in self.children : - domElement.appendChild(child.exportToXML()) - - return domElement - - def _XMLaddAttributes(self, domElement): - attributes = self._getXMLAttributes() - - coverage = self._getCoverage() - if coverage != None : - attributes["Coverage"] = self._number2percent(coverage) - - for key, value in attributes.items(): - domElement.setAttribute(key, value) - - def _getXMLAttributes(self): - return { - "Name": self.name, - "NbUse": str(self.nbUse) - } - - def _incNbUse(self): - self.nbUse += 1 - - def childUsed(self, child): - self._incNbUse() - # Propagate to parent - self._tellParentThatChildUsed() - - def _tellParentThatChildUsed(self): - if self.parent : - self.parent.childUsed(self) - - - def parentUsed(self): - self._incNbUse() - # Propagate to children - for child in self.children : - child.parentUsed() - - def hasBeenUsed(self): - return self.nbUse > 0 - - def operationOnChild(self, path, operation): - - if path: - return self._operationPropagate(path, operation) - else : - self.debug("operating on self") - return operation(self) - - def _operationPropagate(self, path, operation): - - childName = path.pop(0) - child = self.getChildFromName(childName) - - return child.operationOnChild(path, operation) - - - - def debug(self, stringOrFunction, level=logging.DEBUG): - """Print a debug line on stderr in tree form - - If the debug line is expensive to generate, provide callable - object, it will be called if log is enable for this level. - This callable object should return the logline string. - """ - if logger.isEnabledFor(level): - - # TODO: use buildin callable if python >= 3.2 - if hasattr(stringOrFunction, "__call__"): - string = stringOrFunction() - else: - string = stringOrFunction - - rankedLine = DebugRankedLine("%s: %s" % (self, string)) - self._logDebug(rankedLine, level) - - def _logDebug(self, rankedLine, level): - - if self.parent: - self.parent._logDebug(rankedLine.increasedRank(), level) - else : - logger.log(level, str(rankedLine)) - - - - -class FromDomElement(Element): - def __init__(self, DomElement): - self._initFromDom(DomElement) - super().__init__(self.name) - - - def _initFromDom(self, DomElement): - self.name = DomElement.getAttribute("Name") - - - -class DomElementLocation(): - def __init__(self, classConstructor, path=None): - self.classConstructor = classConstructor - if path : - self.path = path - else : - self.path = [] - - self.path.append(classConstructor.tag) - - -class DomPopulatedElement(Element): - """Default child populate - - Look for each dom element with tag specified in self.tag - and instantiate it with the dom element - """ - childClasses = [] - - def populate(self, dom): - - for childDomElementLocation in self.childClasses : - - self.debug("Looking for child %s in path %s" % ( - childDomElementLocation.path[-1], childDomElementLocation.path)) - - for childDomElement in self._findChildFromTagPath(dom, childDomElementLocation.path) : - - childElement = childDomElementLocation.classConstructor(childDomElement) - self.addChild(childElement) - - childElement.populate(childDomElement) - - def _findChildFromTagPath(self, dom, path): - if not path : - yield dom - else : - # Copy list - path = list(path) - - tag = path.pop(0) - - # Find element with tag - self.debug("Going to find elements with tag %s in %s" % (tag, dom)) - self.debug(lambda: "Nb of solutions: %s" % len(dom.getElementsByTagName(tag))) - - for elementByTag in dom.getElementsByTagName(tag) : - - self.debug("Found element: %s" % elementByTag) - - # If the same tag is found - if elementByTag in dom.childNodes : - - # Yield next level - for element in self._findChildFromTagPath(elementByTag, path) : - yield element - - -class Rule(Element): - - def usedIfApplicable(self, criteria): - childApplicability = (child.usedIfApplicable(criteria) - for child in self.children) - - isApplicable = self._isApplicable(criteria, childApplicability) - - if isApplicable : - self._incNbUse() - - self.debug("Rule applicability: %s" % isApplicable) - assert(isApplicable == True or isApplicable == False) - - return isApplicable - - - def _isApplicable(self, criteria, childApplicability): - """Return the rule applicability depending on children applicability. - - If at least one child is applicable, return true""" - # Lazy evaluation as in the PFW - return all(childApplicability) - - -class CriterionRule(FromDomElement, DomPopulatedElement, Rule): - tag = "SelectionCriterionRule" - childClasses = [] - isApplicableOperations = { - "Includes" : lambda criterion, value: criterion.stateIncludes(value), - "Excludes" : lambda criterion, value: not criterion.stateIncludes(value), - "Is" : lambda criterion, value: criterion.stateIs(value), - "IsNot" : lambda criterion, value: not criterion.stateIs(value) - } - - def _initFromDom(self, DomElement): - self.selectionCriterion = DomElement.getAttribute("SelectionCriterion") - self.matchesWhen = DomElement.getAttribute("MatchesWhen") - self.value = DomElement.getAttribute("Value") - self.name = "%s %s %s" % (self.selectionCriterion, self.matchesWhen, self.value) - - applicableOperationWithoutValue = self.isApplicableOperations[self.matchesWhen] - self.isApplicableOperation = lambda criterion: applicableOperationWithoutValue(criterion, self.value) - - def _isApplicable(self, criteria, childApplicability): - - return criteria.operationOnChild([self.selectionCriterion], - self.isApplicableOperation) - - -class CompoundRule(FromDomElement, DomPopulatedElement, Rule): - """CompoundRule can be of type ALL or ANY""" - tag = "CompoundRule" - # Declare childClasses but define it at first class instantiation - childClasses = None - - def __init__(self, dom): - # Define childClasses at first class instantiation - if self.childClasses == None : - self.childClasses = [DomElementLocation(CriterionRule), - DomElementLocation(CompoundRule)] - super().__init__(dom) - - def _initFromDom(self, DomElement): - - type = DomElement.getAttribute("Type") - self.ofTypeAll = {"All" : True, "Any" : False}[type] - self.name = type - - def _isApplicable(self, criteria, childApplicability): - if self.ofTypeAll : - applicability = super()._isApplicable(criteria, childApplicability) - else: - # Lazy evaluation as in the PFW - applicability = any(childApplicability) - - return applicability - -class RootRule(DomPopulatedElement, Rule): - tag = "RootRule" - childClasses = [DomElementLocation(CompoundRule)] - - def populate(self, dom): - super().populate(dom) - self.debug("Children: %s" % self.children) - # A configuration can only have one or no rule - assert(len(self.children) <= 1) - - def _getCoverageDependanceElements(self): - return self._getDescendants() - - -class CriteronStates(Element): - """Root of configuration application criterion state""" - tag = "CriterionStates" - - def parentUsed(self, criteria): - """Add criteria to child if not exist, if exist increase it's nbUse""" - self._incNbUse() - - matches = [child for child in self.children if child == criteria] - - assert(len(matches) <= 1) - - if matches : - self.debug("Criteria state has already been encounter") - currentcriteria = matches[0] - else : - self.debug("Criteria state has never been encounter, saving it") - currentcriteria = criteria - self.addChild(criteria) - - currentcriteria.parentUsed() - - - -class Configuration(FromDomElement, DomPopulatedElement): - tag = "Configuration" - childClasses = [] - - class IneligibleConfigurationAppliedError(CustomError): - - def __init__(self, configuration, criteria): - self.configuration = configuration - self.criteria = criteria - - def __str__(self): - - return ("Applying ineligible %s, " - "rule:\n%s\n" - "Criteria current state:\n%s" % ( - self.configuration, - self.configuration.rootRule.dump(withCoverage=False, withNbUse=False), - self.criteria.dump(withCoverage=False, withNbUse=False) - )) - - def __init__(self, DomElement): - super().__init__(DomElement) - - self.rootRule = RootRule("RootRule") - self.addChild(self.rootRule) - - self.criteronStates = CriteronStates("CriterionStates") - self.addChild(self.criteronStates) - - def populate(self, dom): - # Delegate to rootRule - self.rootRule.populate(dom) - - def _getCoverage(self): - # Delegate to rootRule - return self.rootRule._getCoverage() - - def used(self, criteria): - - self._incNbUse() - - # Propagate use to parents - self._tellParentThatChildUsed() - - # Propagate to criterion coverage - self.criteronStates.parentUsed(criteria.export()) - - # Propagate to rules - if not self.rootRule.usedIfApplicable(criteria) : - - self.debug("Applied but rule does not match current " - "criteria (parent: %s) " % self.parent.name, - logging.ERROR) - - raise self.IneligibleConfigurationAppliedError(self, criteria.export()) - - def _dumpPropagate(self, withCoverage, withNbUse): - self.debug("Going to ask %s for description" % self.rootRule) - for dumpedDescription in self.rootRule._dumpDescription( - withCoverage=withCoverage, - withNbUse=withNbUse) : - yield dumpedDescription.increasedRank() - - self.debug("Going to ask %s for description" % self.criteronStates) - for dumpedDescription in self.criteronStates._dumpDescription( - withCoverage=False, - withNbUse=withNbUse) : - yield dumpedDescription.increasedRank() - - -class Domain(FromDomElement, DomPopulatedElement): - tag = "ConfigurableDomain" - childClasses = [DomElementLocation(Configuration, ["Configurations"])] - - -class Domains(DomPopulatedElement): - tag = "Domains" - childClasses = [DomElementLocation(Domain, ["ConfigurableDomains"])] - - -class RankedLine(): - def __init__(self, string, - stringPrefix="|-- ", - rankString="| ", - linePrefix="", - lineSuffix="\n"): - self.string = string - self.rank = 0 - self.stringPrefix = stringPrefix - self.rankString = rankString - self.linePrefix = linePrefix - self.lineSuffix = lineSuffix - - def increasedRank(self): - self.rank += 1 - return self - - def __str__(self): - return self.linePrefix + \ - self.rank * self.rankString + \ - self.stringPrefix + \ - self.string + \ - self.lineSuffix - -class DebugRankedLine(RankedLine): - - def __init__(self, string, lineSuffix=""): - super().__init__(string, - stringPrefix="", - rankString=" ", - linePrefix="", - lineSuffix=lineSuffix) - - -class CriterionState(Element): - tag = "CriterionState" - def used(self): - self._incNbUse() - - -class Criterion(Element): - tag = "Criterion" - inclusivenessTranslate = {True: "Inclusive", False: "Exclusive"} - - class ChangeRequestToNonAccessibleState(CustomError): - def __init__(self, requestedState, detail): - self.requestedState = requestedState - self.detail = detail - - def __str__(self): - return ("Change request to non accessible state %s. Detail: %s" % - (self.requestedState, self.detail)) - - def __init__(self, name, isInclusif, - stateNamesList, currentStateNamesList, - ignoreIntegrity=False): - super().__init__(name) - self.isInclusif = isInclusif - - for state in stateNamesList : - self.addChild(CriterionState(state)) - - self.currentState = [] - self.initStateNamesList = list(currentStateNamesList) - self.changeState(self.initStateNamesList, ignoreIntegrity) - - def reset(self): - # Set current state as provided at initialisation - self.changeState(self.initStateNamesList, ignoreIntegrity=True) - - def changeState(self, subStateNames, ignoreIntegrity=False): - self.debug("Changing state from: %s to: %s" % ( - list(self._getElementNames(self.currentState)), - subStateNames)) - - if not ignoreIntegrity and not self.isIntegre(subStateNames): - raise self.ChangeRequestToNonAccessibleState(subStateNames, - "An exclusive criterion must have a non empty state") - - newCurrentState = [] - for subStateName in subStateNames : - subState = self.getChildFromName(subStateName) - subState.used() - newCurrentState.append(subState) - - self.currentState = newCurrentState - - self._incNbUse() - self._tellParentThatChildUsed() - - def isIntegre(self, subStateNames): - return self.isInclusif or len(subStateNames) == 1 - - def childUsed(self, child): - self.currentState = child - super().childUsed(child) - - def export(self): - subStateNames = self._getElementNames(self.currentState) - return Criterion(self.name, self.isInclusif, subStateNames, subStateNames, - ignoreIntegrity=True) - - def stateIncludes(self, subStateName): - subStateCurrentNames = list(self._getElementNames(self.currentState)) - - self.debug("Testing if %s is included in %s" % (subStateName, subStateCurrentNames)) - - isIncluded = subStateName in subStateCurrentNames - self.debug("IsIncluded: %s" % isIncluded) - - return isIncluded - - - def stateIs(self, subStateNames): - if len(self.currentState) != 1 : - return False - else : - return self.stateIncludes(subStateNames) - - def _getXMLAttributes(self): - attributes = super()._getXMLAttributes() - attributes["Type"] = self.inclusivenessTranslate[self.isInclusif] - return attributes - - -class Criteria(Element): - tag = "Criteria" - - class DuplicatedCriterionError(DuplicatedChildError): - pass - - def export(self): - self.debug("Exporting criteria") - assert(self.children) - - exported = Criteria(self.name) - for child in self.children : - exported.addChild(child.export()) - return exported - - def addChild(self, child): - if child in self.children: - raise self.DuplicatedCriterionError(self, child) - super().addChild(child) - -class ConfigAppliedWithoutCriteriaError(CustomError): - def __init__(self, configurationName, domainName): - self.configurationName = configurationName - self.domainName = domainName - def __str__(self): - return ('Applying configuration "%s" from domain "%s" before declaring criteria' % - (self.configurationName, self.domainName)) - -class ParsePFWlog(): - MATCH = "match" - ACTION = "action" - - def __init__(self, domains, criteria, ErrorsToIgnore=()): - - self.domains = domains; - self.criteria = criteria; - self.ErrorsToIgnore = ErrorsToIgnore - - configApplicationRegext = r""".*Applying configuration "(.*)" from domain "([^"]*)""" - matchConfigApplicationLine = re.compile(configApplicationRegext).match - - criterionCreationRegext = ", ".join([ - r""".*Criterion name: (.*)""", - r"""type kind: (.*)""", - r"""current state: (.*)""", - r"""states: {(.*)}""" - ]) - matchCriterionCreationLine = re.compile(criterionCreationRegext).match - - changingCriterionRegext = r""".*Selection criterion changed event: Criterion name: (.*), current state: ([^\n\r]*)""" - matchChangingCriterionLine = re.compile(changingCriterionRegext).match - - self.lineLogTypes = [ - { - self.MATCH: matchConfigApplicationLine, - self.ACTION: self._configApplication - }, { - self.MATCH: matchCriterionCreationLine, - self.ACTION: self._criterionCreation - }, { - self.MATCH: matchChangingCriterionLine, - self.ACTION: self._changingCriterion - } - ] - - @staticmethod - def _formatCriterionList(liststring, separator): - list = liststring.split(separator) - if len(list) == 1 and list[0] == "<none>": - list = [] - return list - - def _criterionCreation(self, matchCriterionCreation): - # Unpack - criterionName, criterionType, currentCriterionStates, criterionStates = matchCriterionCreation.group(1, 2, 3, 4) - - criterionStateList = self._formatCriterionList(criterionStates, ", ") - - criterionIsInclusif = {"exclusive" : False, "inclusive" : True}[criterionType] - - currentcriterionStateList = self._formatCriterionList(currentCriterionStates, "|") - - logger.info("Creating criterion: " + criterionName + - " (" + criterionType + ") " + - " with current state: " + str(currentcriterionStateList) + - ", possible states:" + str(criterionStateList)) - - try: - self.criteria.addChild(Criterion( - criterionName, - criterionIsInclusif, - criterionStateList, - currentcriterionStateList - )) - except self.criteria.DuplicatedCriterionError as ex: - logger.debug(ex) - logger.warning("Reseting criterion %s. Did you reset the PFW ?" % criterionName) - self.criteria.operationOnChild( - [criterionName], - lambda criterion: criterion.reset() - ) - - - - def _changingCriterion(self, matchChangingCriterion): - # Unpack - criterionName, newCriterionSubStateNames = matchChangingCriterion.group(1, 2) - - newCriterionState = self._formatCriterionList(newCriterionSubStateNames, "|") - - logger.info("Changing criterion %s to %s" % (criterionName , newCriterionState)) - - path = [criterionName] - changeCriterionOperation = lambda criterion : criterion.changeState(newCriterionState) - self.criteria.operationOnChild(path, changeCriterionOperation) - - def _configApplication(self, matchConfig): - # Unpack - configurationName, domainName = matchConfig.group(1, 2) - - # Check that at least one criterion exist - if not self.criteria.hasChildren() : - logger.error("Applying configuration before declaring criteria") - logger.info("Is the log starting at PFW boot ?") - raise ConfigAppliedWithoutCriteriaError(configurationName, domainName) - - # Change criterion state - path = [domainName, configurationName] - usedOperation = lambda element : element.used(self.criteria) - - logger.info("Applying configuration %s from domain %s" % ( - configurationName, domainName)) - - self.domains.operationOnChild(path, usedOperation) - - - def _digest(self, lineLogType, lineLog): - - match = lineLogType[self.MATCH](lineLog) - if match : - lineLogType[self.ACTION](match) - return True - return False - - - def parsePFWlog(self, lines): - for lineNb, lineLog in enumerate(lines): - - logger.debug("Parsing line :%s" % lineLog.rstrip()) - - digested = (self._digest(lineLogType, lineLog) - for lineLogType in self.lineLogTypes) - - try: - success = any(digested) - - # Catch some exception in order to print the current parsing line, - # then raise the exception again if not continue of error - except CustomError as ex: - logger.error('Error raised while parsing line %s: "%s"' % - (lineNb, repr(lineLog))) - - # If exception is a subclass of ErrorsToIgnore, log it and continue - # otherwise raise it again. - if not issubclass(type(ex), self.ErrorsToIgnore): - raise ex - else: - logger.error('Ignoring exception:"%s", ' - 'can not guarantee database integrity' % ex) - else: - if not success: - logger.debug("Line does not match, dropped") - - -class Root(Element): - tag = "CoverageReport" - def __init__(self, name, dom): - super().__init__(name) - # Create domain tree - self.domains = Domains("Domains") - self.domains.populate(dom) - self.addChild(self.domains) - # Create criterion list - self.criteria = Criteria("CriterionRoot") - self.addChild(self.criteria) - - def exportToXML(self): - """Export tree to an xml document""" - impl = xml.dom.minidom.getDOMImplementation() - newdoc = impl.createDocument(namespaceURI=None, qualifiedName=self.tag, doctype=None) - super().exportToXML(newdoc.documentElement) - - return newdoc - -# ============================ -# Command line argument parser -# ============================ - - -class ArgumentParser: - """class that parse command line arguments with argparse library - - Result of parsing are the class attributes. - """ - levelTranslate = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG] - - def __init__(self): - - try: - # As argparse is only in the stdlib since python 3.2, - # testing its availability - import argparse - - except ImportError: - logger.warning("Unable to import argparse " - "(parser for command-line options and arguments), " - "using default argument values:") - - logger.warning(" - InputFile: stdin") - self.inputFile = sys.stdin - - logger.warning(" - OutputFile: stdout") - self.outputFile = sys.stdout - - try: - self.domainsFile = sys.argv[1] - except IndexError as ex: - logger.fatal("No domain file provided (first argument)") - raise ex - else: - logger.warning(" - Domain file: " + self.domainsFile) - - logger.warning(" - Output format: xml") - self.XMLreport = True - - logger.warning(" - Debug level: error") - self.debugLevel = logging.ERROR - else : - - myArgParser = argparse.ArgumentParser(description='Generate PFW report') - - myArgParser.add_argument( - 'domainsFile', - type=argparse.FileType('r'), - help="the PFW domain XML file" - ) - myArgParser.add_argument( - 'pfwlog', nargs='?', - type=argparse.FileType('r'), default=sys.stdin, - help="the PFW log file, default stdin" - ) - myArgParser.add_argument( - '-o', '--output', - dest="outputFile", - type=argparse.FileType('w'), default=sys.stdout, - help="the coverage report output file, default stdout" - ) - myArgParser.add_argument( - '-v', '--verbose', - dest="debugLevel", default=0, - action='count', - help="print debug warnings from warning (default) to debug (-vv)" - ) - - outputFormatGroupe = myArgParser.add_mutually_exclusive_group(required=False) - - outputFormatGroupe.add_argument( - '--xml', - dest="xmlFlag", - action='store_true', - help=" XML coverage output report" - ) - outputFormatGroupe.add_argument( - '--raw', - dest="rawFlag", - action='store_true', - help="raw coverage output report" - ) - - myArgParser.add_argument( - '--ignore-incoherent-criterion-state', - dest="incoherentCriterionFlag", - action='store_true', - help="ignore criterion transition to incoherent state" - ) - - myArgParser.add_argument( - '--ignore-ineligible-configuration-application', - dest="ineligibleConfigurationApplicationFlag", - action='store_true', - help="ignore application of configuration with a false rule " - "(not applicable configuration)" - ) - - # Process command line arguments - options = myArgParser.parse_args() - - # Mapping to attributes - self.inputFile = options.pfwlog - self.outputFile = options.outputFile - self.domainsFile = options.domainsFile - - # Output report in xml if flag not set - self.XMLreport = not options.rawFlag - - # Setting logger level - levelCapped = min(options.debugLevel, len(self.levelTranslate) - 1) - self.debugLevel = self.levelTranslate[levelCapped] - - # Setting ignore options - errorToIgnore = [] - if options.ineligibleConfigurationApplicationFlag : - errorToIgnore.append(Configuration.IneligibleConfigurationAppliedError) - - if options.incoherentCriterionFlag: - errorToIgnore.append(Criterion.ChangeRequestToNonAccessibleState) - - self.errorToIgnore = tuple(errorToIgnore) - - - -def main(): - - errorDuringLogParsing = -1 - errorDuringArgumentParsing = 1 - - try: - commandLineArguments = ArgumentParser() - except LookupError as ex: - logger.error("Error during argument parsing") - logger.debug(str(ex)) - sys.exit(errorDuringArgumentParsing) - - # Setting logger level - logger.setLevel(commandLineArguments.debugLevel) - logger.info("Log level set to: %s" % - logging.getLevelName(commandLineArguments.debugLevel)) - - # Create tree from XML - dom = xml.dom.minidom.parse(commandLineArguments.domainsFile) - - # Create element tree - root = Root("DomainCoverage", dom) - - # Parse PFW events - parser = ParsePFWlog(root.domains, root.criteria, commandLineArguments.errorToIgnore) - - try: - parser.parsePFWlog(commandLineArguments.inputFile.readlines()) - except CustomError as ex: - logger.fatal("Error during parsing log file %s: %s" % - (commandLineArguments.inputFile, ex)) - sys.exit(errorDuringLogParsing) - - # Output report - outputFile = commandLineArguments.outputFile - - if not commandLineArguments.XMLreport : - outputFile.write("%s\n" % root.dump(withCoverage=True, withNbUse=True)) - else : - outputFile.write(root.exportToXML().toprettyxml()) - - -if __name__ == "__main__" : - """ Execute main if the python interpreter is running this module as the main program """ - main() - |