1*c33452fbSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*c33452fbSAndroid Build Coastguard Worker 3*c33452fbSAndroid Build Coastguard Worker# Copyright (c) 2011-2014, Intel Corporation 4*c33452fbSAndroid Build Coastguard Worker# All rights reserved. 5*c33452fbSAndroid Build Coastguard Worker# 6*c33452fbSAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without modification, 7*c33452fbSAndroid Build Coastguard Worker# are permitted provided that the following conditions are met: 8*c33452fbSAndroid Build Coastguard Worker# 9*c33452fbSAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright notice, this 10*c33452fbSAndroid Build Coastguard Worker# list of conditions and the following disclaimer. 11*c33452fbSAndroid Build Coastguard Worker# 12*c33452fbSAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright notice, 13*c33452fbSAndroid Build Coastguard Worker# this list of conditions and the following disclaimer in the documentation and/or 14*c33452fbSAndroid Build Coastguard Worker# other materials provided with the distribution. 15*c33452fbSAndroid Build Coastguard Worker# 16*c33452fbSAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the names of its contributors 17*c33452fbSAndroid Build Coastguard Worker# may be used to endorse or promote products derived from this software without 18*c33452fbSAndroid Build Coastguard Worker# specific prior written permission. 19*c33452fbSAndroid Build Coastguard Worker# 20*c33452fbSAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21*c33452fbSAndroid Build Coastguard Worker# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22*c33452fbSAndroid Build Coastguard Worker# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23*c33452fbSAndroid Build Coastguard Worker# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24*c33452fbSAndroid Build Coastguard Worker# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25*c33452fbSAndroid Build Coastguard Worker# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26*c33452fbSAndroid Build Coastguard Worker# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27*c33452fbSAndroid Build Coastguard Worker# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28*c33452fbSAndroid Build Coastguard Worker# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29*c33452fbSAndroid Build Coastguard Worker# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*c33452fbSAndroid Build Coastguard Worker 31*c33452fbSAndroid Build Coastguard Worker 32*c33452fbSAndroid Build Coastguard Worker""" 33*c33452fbSAndroid Build Coastguard WorkerGenerate a coverage report by parsing parameter framework log. 34*c33452fbSAndroid Build Coastguard Worker 35*c33452fbSAndroid Build Coastguard WorkerThe coverage report contains the: 36*c33452fbSAndroid Build Coastguard Worker - domain 37*c33452fbSAndroid Build Coastguard Worker - configuration 38*c33452fbSAndroid Build Coastguard Worker - rule 39*c33452fbSAndroid Build Coastguard Worker - criterion 40*c33452fbSAndroid Build Coastguard Workerbasic coverage statistics. 41*c33452fbSAndroid Build Coastguard Worker""" 42*c33452fbSAndroid Build Coastguard Worker 43*c33452fbSAndroid Build Coastguard Workerimport xml.dom.minidom 44*c33452fbSAndroid Build Coastguard Workerimport sys 45*c33452fbSAndroid Build Coastguard Workerimport re 46*c33452fbSAndroid Build Coastguard Workerimport logging 47*c33452fbSAndroid Build Coastguard Worker 48*c33452fbSAndroid Build Coastguard WorkerFORMAT = '%(levelname)s: %(message)s' 49*c33452fbSAndroid Build Coastguard Workerlogging.basicConfig(stream=sys.stderr, level=logging.WARNING, format=FORMAT) 50*c33452fbSAndroid Build Coastguard Workerlogger = logging.getLogger("Coverage") 51*c33452fbSAndroid Build Coastguard Worker 52*c33452fbSAndroid Build Coastguard Workerclass CustomError(Exception): 53*c33452fbSAndroid Build Coastguard Worker pass 54*c33452fbSAndroid Build Coastguard Worker 55*c33452fbSAndroid Build Coastguard Workerclass ChildError(CustomError): 56*c33452fbSAndroid Build Coastguard Worker def __init__(self, parent, child): 57*c33452fbSAndroid Build Coastguard Worker self.parent = parent 58*c33452fbSAndroid Build Coastguard Worker self.child = child 59*c33452fbSAndroid Build Coastguard Worker 60*c33452fbSAndroid Build Coastguard Workerclass ChildNotFoundError(ChildError): 61*c33452fbSAndroid Build Coastguard Worker def __str__(self): 62*c33452fbSAndroid Build Coastguard Worker return 'Unable to find the child "%s" in "%s"' % (self.child, self.parent) 63*c33452fbSAndroid Build Coastguard Worker 64*c33452fbSAndroid Build Coastguard Workerclass DuplicatedChildError(ChildError): 65*c33452fbSAndroid Build Coastguard Worker def __str__(self): 66*c33452fbSAndroid Build Coastguard Worker return 'Add existing child "%s" in "%s".' % (self.child, self.parent) 67*c33452fbSAndroid Build Coastguard Worker 68*c33452fbSAndroid Build Coastguard Workerclass Element(): 69*c33452fbSAndroid Build Coastguard Worker """Root class for all coverage elements""" 70*c33452fbSAndroid Build Coastguard Worker tag = "element" 71*c33452fbSAndroid Build Coastguard Worker 72*c33452fbSAndroid Build Coastguard Worker def __init__(self, name): 73*c33452fbSAndroid Build Coastguard Worker 74*c33452fbSAndroid Build Coastguard Worker self.parent = None 75*c33452fbSAndroid Build Coastguard Worker self.children = [] 76*c33452fbSAndroid Build Coastguard Worker 77*c33452fbSAndroid Build Coastguard Worker self.nbUse = 0 78*c33452fbSAndroid Build Coastguard Worker 79*c33452fbSAndroid Build Coastguard Worker self.name = name 80*c33452fbSAndroid Build Coastguard Worker 81*c33452fbSAndroid Build Coastguard Worker self.debug("New element") 82*c33452fbSAndroid Build Coastguard Worker 83*c33452fbSAndroid Build Coastguard Worker 84*c33452fbSAndroid Build Coastguard Worker def __str__(self): 85*c33452fbSAndroid Build Coastguard Worker return "%s (%s)" % (self.name, self.tag) 86*c33452fbSAndroid Build Coastguard Worker 87*c33452fbSAndroid Build Coastguard Worker def __eq__(self, compared): 88*c33452fbSAndroid Build Coastguard Worker return (self.name == compared.name) and (self.children == compared.children) 89*c33452fbSAndroid Build Coastguard Worker 90*c33452fbSAndroid Build Coastguard Worker def getName(self, default=""): 91*c33452fbSAndroid Build Coastguard Worker return self.name or default 92*c33452fbSAndroid Build Coastguard Worker 93*c33452fbSAndroid Build Coastguard Worker def hasChildren(self): 94*c33452fbSAndroid Build Coastguard Worker return bool(self.children) 95*c33452fbSAndroid Build Coastguard Worker 96*c33452fbSAndroid Build Coastguard Worker def getChildren(self): 97*c33452fbSAndroid Build Coastguard Worker return self.children 98*c33452fbSAndroid Build Coastguard Worker 99*c33452fbSAndroid Build Coastguard Worker def _getDescendants(self): 100*c33452fbSAndroid Build Coastguard Worker for child in self.children: 101*c33452fbSAndroid Build Coastguard Worker yield child 102*c33452fbSAndroid Build Coastguard Worker for descendant in child._getDescendants(): 103*c33452fbSAndroid Build Coastguard Worker yield descendant 104*c33452fbSAndroid Build Coastguard Worker 105*c33452fbSAndroid Build Coastguard Worker def getChildFromName(self, childName): 106*c33452fbSAndroid Build Coastguard Worker 107*c33452fbSAndroid Build Coastguard Worker for child in self.children: 108*c33452fbSAndroid Build Coastguard Worker 109*c33452fbSAndroid Build Coastguard Worker if child.getName() == childName: 110*c33452fbSAndroid Build Coastguard Worker return child 111*c33452fbSAndroid Build Coastguard Worker 112*c33452fbSAndroid Build Coastguard Worker self.debug('Child "%s" not found' % childName, logging.ERROR) 113*c33452fbSAndroid Build Coastguard Worker 114*c33452fbSAndroid Build Coastguard Worker self.debug("Child list :") 115*c33452fbSAndroid Build Coastguard Worker 116*c33452fbSAndroid Build Coastguard Worker for child in self.children: 117*c33452fbSAndroid Build Coastguard Worker self.debug(" - %s" % child) 118*c33452fbSAndroid Build Coastguard Worker 119*c33452fbSAndroid Build Coastguard Worker raise ChildNotFoundError(self, childName) 120*c33452fbSAndroid Build Coastguard Worker 121*c33452fbSAndroid Build Coastguard Worker 122*c33452fbSAndroid Build Coastguard Worker def addChild(self, child): 123*c33452fbSAndroid Build Coastguard Worker self.debug("new child: " + child.name) 124*c33452fbSAndroid Build Coastguard Worker self.children.append(child) 125*c33452fbSAndroid Build Coastguard Worker child._adoptedBy(self) 126*c33452fbSAndroid Build Coastguard Worker 127*c33452fbSAndroid Build Coastguard Worker def _adoptedBy(self, parent): 128*c33452fbSAndroid Build Coastguard Worker assert(not self.parent) 129*c33452fbSAndroid Build Coastguard Worker self.parent = parent 130*c33452fbSAndroid Build Coastguard Worker 131*c33452fbSAndroid Build Coastguard Worker def _getElementNames(self, elementList): 132*c33452fbSAndroid Build Coastguard Worker return (substate.name for substate in elementList) 133*c33452fbSAndroid Build Coastguard Worker 134*c33452fbSAndroid Build Coastguard Worker def _description(self, withCoverage, withNbUse): 135*c33452fbSAndroid Build Coastguard Worker description = self.name 136*c33452fbSAndroid Build Coastguard Worker 137*c33452fbSAndroid Build Coastguard Worker if withNbUse or withCoverage: 138*c33452fbSAndroid Build Coastguard Worker description += " has been used " + str(self.nbUse) + " time" 139*c33452fbSAndroid Build Coastguard Worker 140*c33452fbSAndroid Build Coastguard Worker if withCoverage: 141*c33452fbSAndroid Build Coastguard Worker description += self._coverageFormating(self._getCoverage()) 142*c33452fbSAndroid Build Coastguard Worker 143*c33452fbSAndroid Build Coastguard Worker return description 144*c33452fbSAndroid Build Coastguard Worker 145*c33452fbSAndroid Build Coastguard Worker 146*c33452fbSAndroid Build Coastguard Worker def _getCoverage(self): 147*c33452fbSAndroid Build Coastguard Worker """Return the coverage of the element between 0 and 1 148*c33452fbSAndroid Build Coastguard Worker 149*c33452fbSAndroid Build Coastguard Worker If the element has no coverage dependency (usually child) return 0 or 1. 150*c33452fbSAndroid Build Coastguard Worker otherwise the element coverage is the dependency coverage average""" 151*c33452fbSAndroid Build Coastguard Worker coverageDependanceElements = list(self._getCoverageDependanceElements()) 152*c33452fbSAndroid Build Coastguard Worker 153*c33452fbSAndroid Build Coastguard Worker nbcoverageDependence = len(coverageDependanceElements) 154*c33452fbSAndroid Build Coastguard Worker 155*c33452fbSAndroid Build Coastguard Worker if nbcoverageDependence == 0: 156*c33452fbSAndroid Build Coastguard Worker if self.nbUse == 0: 157*c33452fbSAndroid Build Coastguard Worker return 0 158*c33452fbSAndroid Build Coastguard Worker else: 159*c33452fbSAndroid Build Coastguard Worker return 1 160*c33452fbSAndroid Build Coastguard Worker 161*c33452fbSAndroid Build Coastguard Worker coverageDependenceValues = (depElement._getCoverage() 162*c33452fbSAndroid Build Coastguard Worker for depElement in coverageDependanceElements) 163*c33452fbSAndroid Build Coastguard Worker 164*c33452fbSAndroid Build Coastguard Worker return sum(coverageDependenceValues) / nbcoverageDependence 165*c33452fbSAndroid Build Coastguard Worker 166*c33452fbSAndroid Build Coastguard Worker def _getCoverageDependanceElements(self): 167*c33452fbSAndroid Build Coastguard Worker return self.children 168*c33452fbSAndroid Build Coastguard Worker 169*c33452fbSAndroid Build Coastguard Worker def _coverageFormating(self, coverage): 170*c33452fbSAndroid Build Coastguard Worker # If no coverage provided 171*c33452fbSAndroid Build Coastguard Worker if not coverage: 172*c33452fbSAndroid Build Coastguard Worker return "" 173*c33452fbSAndroid Build Coastguard Worker 174*c33452fbSAndroid Build Coastguard Worker # Calculate coverage 175*c33452fbSAndroid Build Coastguard Worker return " (%s coverage)" % self._number2percent(coverage) 176*c33452fbSAndroid Build Coastguard Worker 177*c33452fbSAndroid Build Coastguard Worker @staticmethod 178*c33452fbSAndroid Build Coastguard Worker def _number2percent(number): 179*c33452fbSAndroid Build Coastguard Worker """Format a number to a integer % string 180*c33452fbSAndroid Build Coastguard Worker 181*c33452fbSAndroid Build Coastguard Worker example: _number2percent(0.6666) -> "67%" 182*c33452fbSAndroid Build Coastguard Worker """ 183*c33452fbSAndroid Build Coastguard Worker return "{0:.0f}%".format(100 * number) 184*c33452fbSAndroid Build Coastguard Worker 185*c33452fbSAndroid Build Coastguard Worker 186*c33452fbSAndroid Build Coastguard Worker def _dumpDescription(self, withCoverage, withNbUse): 187*c33452fbSAndroid Build Coastguard Worker 188*c33452fbSAndroid Build Coastguard Worker self.debug("yelding description") 189*c33452fbSAndroid Build Coastguard Worker yield RankedLine(self._description(withCoverage, withNbUse), lineSuffix="") 190*c33452fbSAndroid Build Coastguard Worker 191*c33452fbSAndroid Build Coastguard Worker for dumped in self._dumpPropagate(withCoverage, withNbUse): 192*c33452fbSAndroid Build Coastguard Worker yield dumped 193*c33452fbSAndroid Build Coastguard Worker 194*c33452fbSAndroid Build Coastguard Worker def _dumpPropagate(self, withCoverage, withNbUse): 195*c33452fbSAndroid Build Coastguard Worker 196*c33452fbSAndroid Build Coastguard Worker for child in self.children: 197*c33452fbSAndroid Build Coastguard Worker for dumpedDescription in child._dumpDescription(withCoverage, withNbUse): 198*c33452fbSAndroid Build Coastguard Worker yield dumpedDescription.increasedRank() 199*c33452fbSAndroid Build Coastguard Worker 200*c33452fbSAndroid Build Coastguard Worker 201*c33452fbSAndroid Build Coastguard Worker def dump(self, withCoverage=False, withNbUse=True): 202*c33452fbSAndroid Build Coastguard Worker 203*c33452fbSAndroid Build Coastguard Worker return "\n".join(str(dumpedDescription) for dumpedDescription in 204*c33452fbSAndroid Build Coastguard Worker self._dumpDescription(withCoverage, withNbUse)) 205*c33452fbSAndroid Build Coastguard Worker 206*c33452fbSAndroid Build Coastguard Worker def exportToXML(self, document, domElement=None): 207*c33452fbSAndroid Build Coastguard Worker if domElement == None: 208*c33452fbSAndroid Build Coastguard Worker domElement = document.createElement(self.tag) 209*c33452fbSAndroid Build Coastguard Worker 210*c33452fbSAndroid Build Coastguard Worker self._XMLaddAttributes(domElement) 211*c33452fbSAndroid Build Coastguard Worker 212*c33452fbSAndroid Build Coastguard Worker for child in self.children: 213*c33452fbSAndroid Build Coastguard Worker domElement.appendChild(child.exportToXML(document)) 214*c33452fbSAndroid Build Coastguard Worker 215*c33452fbSAndroid Build Coastguard Worker return domElement 216*c33452fbSAndroid Build Coastguard Worker 217*c33452fbSAndroid Build Coastguard Worker def _XMLaddAttributes(self, domElement): 218*c33452fbSAndroid Build Coastguard Worker attributes = self._getXMLAttributes() 219*c33452fbSAndroid Build Coastguard Worker 220*c33452fbSAndroid Build Coastguard Worker coverage = self._getCoverage() 221*c33452fbSAndroid Build Coastguard Worker if coverage != None: 222*c33452fbSAndroid Build Coastguard Worker attributes["Coverage"] = self._number2percent(coverage) 223*c33452fbSAndroid Build Coastguard Worker 224*c33452fbSAndroid Build Coastguard Worker for key, value in attributes.items(): 225*c33452fbSAndroid Build Coastguard Worker domElement.setAttribute(key, value) 226*c33452fbSAndroid Build Coastguard Worker 227*c33452fbSAndroid Build Coastguard Worker def _getXMLAttributes(self): 228*c33452fbSAndroid Build Coastguard Worker return {"Name": self.name, 229*c33452fbSAndroid Build Coastguard Worker "NbUse": str(self.nbUse) 230*c33452fbSAndroid Build Coastguard Worker } 231*c33452fbSAndroid Build Coastguard Worker 232*c33452fbSAndroid Build Coastguard Worker def _incNbUse(self): 233*c33452fbSAndroid Build Coastguard Worker self.nbUse += 1 234*c33452fbSAndroid Build Coastguard Worker 235*c33452fbSAndroid Build Coastguard Worker def childUsed(self, child): 236*c33452fbSAndroid Build Coastguard Worker self._incNbUse() 237*c33452fbSAndroid Build Coastguard Worker # Propagate to parent 238*c33452fbSAndroid Build Coastguard Worker self._tellParentThatChildUsed() 239*c33452fbSAndroid Build Coastguard Worker 240*c33452fbSAndroid Build Coastguard Worker def _tellParentThatChildUsed(self): 241*c33452fbSAndroid Build Coastguard Worker if self.parent: 242*c33452fbSAndroid Build Coastguard Worker self.parent.childUsed(self) 243*c33452fbSAndroid Build Coastguard Worker 244*c33452fbSAndroid Build Coastguard Worker 245*c33452fbSAndroid Build Coastguard Worker def parentUsed(self): 246*c33452fbSAndroid Build Coastguard Worker self._incNbUse() 247*c33452fbSAndroid Build Coastguard Worker # Propagate to children 248*c33452fbSAndroid Build Coastguard Worker for child in self.children: 249*c33452fbSAndroid Build Coastguard Worker child.parentUsed() 250*c33452fbSAndroid Build Coastguard Worker 251*c33452fbSAndroid Build Coastguard Worker def hasBeenUsed(self): 252*c33452fbSAndroid Build Coastguard Worker return self.nbUse > 0 253*c33452fbSAndroid Build Coastguard Worker 254*c33452fbSAndroid Build Coastguard Worker def operationOnChild(self, path, operation): 255*c33452fbSAndroid Build Coastguard Worker 256*c33452fbSAndroid Build Coastguard Worker if path: 257*c33452fbSAndroid Build Coastguard Worker return self._operationPropagate(path, operation) 258*c33452fbSAndroid Build Coastguard Worker else: 259*c33452fbSAndroid Build Coastguard Worker self.debug("operating on self") 260*c33452fbSAndroid Build Coastguard Worker return operation(self) 261*c33452fbSAndroid Build Coastguard Worker 262*c33452fbSAndroid Build Coastguard Worker def _operationPropagate(self, path, operation): 263*c33452fbSAndroid Build Coastguard Worker 264*c33452fbSAndroid Build Coastguard Worker childName = path.pop(0) 265*c33452fbSAndroid Build Coastguard Worker child = self.getChildFromName(childName) 266*c33452fbSAndroid Build Coastguard Worker 267*c33452fbSAndroid Build Coastguard Worker return child.operationOnChild(path, operation) 268*c33452fbSAndroid Build Coastguard Worker 269*c33452fbSAndroid Build Coastguard Worker 270*c33452fbSAndroid Build Coastguard Worker 271*c33452fbSAndroid Build Coastguard Worker def debug(self, stringOrFunction, level=logging.DEBUG): 272*c33452fbSAndroid Build Coastguard Worker """Print a debug line on stderr in tree form 273*c33452fbSAndroid Build Coastguard Worker 274*c33452fbSAndroid Build Coastguard Worker If the debug line is expensive to generate, provide callable 275*c33452fbSAndroid Build Coastguard Worker object, it will be called if log is enable for this level. 276*c33452fbSAndroid Build Coastguard Worker This callable object should return the logline string. 277*c33452fbSAndroid Build Coastguard Worker """ 278*c33452fbSAndroid Build Coastguard Worker if logger.isEnabledFor(level): 279*c33452fbSAndroid Build Coastguard Worker 280*c33452fbSAndroid Build Coastguard Worker # TODO: use buildin callable if python >= 3.2 281*c33452fbSAndroid Build Coastguard Worker if hasattr(stringOrFunction, "__call__"): 282*c33452fbSAndroid Build Coastguard Worker string = stringOrFunction() 283*c33452fbSAndroid Build Coastguard Worker else: 284*c33452fbSAndroid Build Coastguard Worker string = stringOrFunction 285*c33452fbSAndroid Build Coastguard Worker 286*c33452fbSAndroid Build Coastguard Worker rankedLine = DebugRankedLine("%s: %s" % (self, string)) 287*c33452fbSAndroid Build Coastguard Worker self._logDebug(rankedLine, level) 288*c33452fbSAndroid Build Coastguard Worker 289*c33452fbSAndroid Build Coastguard Worker def _logDebug(self, rankedLine, level): 290*c33452fbSAndroid Build Coastguard Worker 291*c33452fbSAndroid Build Coastguard Worker if self.parent: 292*c33452fbSAndroid Build Coastguard Worker self.parent._logDebug(rankedLine.increasedRank(), level) 293*c33452fbSAndroid Build Coastguard Worker else: 294*c33452fbSAndroid Build Coastguard Worker logger.log(level, str(rankedLine)) 295*c33452fbSAndroid Build Coastguard Worker 296*c33452fbSAndroid Build Coastguard Worker 297*c33452fbSAndroid Build Coastguard Worker 298*c33452fbSAndroid Build Coastguard Worker 299*c33452fbSAndroid Build Coastguard Workerclass FromDomElement(Element): 300*c33452fbSAndroid Build Coastguard Worker def __init__(self, DomElement): 301*c33452fbSAndroid Build Coastguard Worker self._initFromDom(DomElement) 302*c33452fbSAndroid Build Coastguard Worker super().__init__(self.name) 303*c33452fbSAndroid Build Coastguard Worker 304*c33452fbSAndroid Build Coastguard Worker 305*c33452fbSAndroid Build Coastguard Worker def _initFromDom(self, DomElement): 306*c33452fbSAndroid Build Coastguard Worker self.name = DomElement.getAttribute("Name") 307*c33452fbSAndroid Build Coastguard Worker 308*c33452fbSAndroid Build Coastguard Worker 309*c33452fbSAndroid Build Coastguard Worker 310*c33452fbSAndroid Build Coastguard Workerclass DomElementLocation(): 311*c33452fbSAndroid Build Coastguard Worker def __init__(self, classConstructor, path=None): 312*c33452fbSAndroid Build Coastguard Worker self.classConstructor = classConstructor 313*c33452fbSAndroid Build Coastguard Worker if path: 314*c33452fbSAndroid Build Coastguard Worker self.path = path 315*c33452fbSAndroid Build Coastguard Worker else: 316*c33452fbSAndroid Build Coastguard Worker self.path = [] 317*c33452fbSAndroid Build Coastguard Worker 318*c33452fbSAndroid Build Coastguard Worker self.path.append(classConstructor.tag) 319*c33452fbSAndroid Build Coastguard Worker 320*c33452fbSAndroid Build Coastguard Worker 321*c33452fbSAndroid Build Coastguard Workerclass DomPopulatedElement(Element): 322*c33452fbSAndroid Build Coastguard Worker """Default child populate 323*c33452fbSAndroid Build Coastguard Worker 324*c33452fbSAndroid Build Coastguard Worker Look for each dom element with tag specified in self.tag 325*c33452fbSAndroid Build Coastguard Worker and instantiate it with the dom element 326*c33452fbSAndroid Build Coastguard Worker """ 327*c33452fbSAndroid Build Coastguard Worker childClasses = [] 328*c33452fbSAndroid Build Coastguard Worker 329*c33452fbSAndroid Build Coastguard Worker def populate(self, dom): 330*c33452fbSAndroid Build Coastguard Worker 331*c33452fbSAndroid Build Coastguard Worker for childDomElementLocation in self.childClasses: 332*c33452fbSAndroid Build Coastguard Worker 333*c33452fbSAndroid Build Coastguard Worker self.debug("Looking for child %s in path %s" % ( 334*c33452fbSAndroid Build Coastguard Worker childDomElementLocation.path[-1], childDomElementLocation.path)) 335*c33452fbSAndroid Build Coastguard Worker 336*c33452fbSAndroid Build Coastguard Worker for childDomElement in self._findChildFromTagPath(dom, childDomElementLocation.path): 337*c33452fbSAndroid Build Coastguard Worker 338*c33452fbSAndroid Build Coastguard Worker childElement = childDomElementLocation.classConstructor(childDomElement) 339*c33452fbSAndroid Build Coastguard Worker self.addChild(childElement) 340*c33452fbSAndroid Build Coastguard Worker 341*c33452fbSAndroid Build Coastguard Worker childElement.populate(childDomElement) 342*c33452fbSAndroid Build Coastguard Worker 343*c33452fbSAndroid Build Coastguard Worker def _findChildFromTagPath(self, dom, path): 344*c33452fbSAndroid Build Coastguard Worker if not path: 345*c33452fbSAndroid Build Coastguard Worker yield dom 346*c33452fbSAndroid Build Coastguard Worker else: 347*c33452fbSAndroid Build Coastguard Worker # Copy list 348*c33452fbSAndroid Build Coastguard Worker path = list(path) 349*c33452fbSAndroid Build Coastguard Worker 350*c33452fbSAndroid Build Coastguard Worker tag = path.pop(0) 351*c33452fbSAndroid Build Coastguard Worker 352*c33452fbSAndroid Build Coastguard Worker # Find element with tag 353*c33452fbSAndroid Build Coastguard Worker self.debug("Going to find elements with tag %s in %s" % (tag, dom)) 354*c33452fbSAndroid Build Coastguard Worker self.debug(lambda: "Nb of solutions: %s" % len(dom.getElementsByTagName(tag))) 355*c33452fbSAndroid Build Coastguard Worker 356*c33452fbSAndroid Build Coastguard Worker for elementByTag in dom.getElementsByTagName(tag): 357*c33452fbSAndroid Build Coastguard Worker 358*c33452fbSAndroid Build Coastguard Worker self.debug("Found element: %s" % elementByTag) 359*c33452fbSAndroid Build Coastguard Worker 360*c33452fbSAndroid Build Coastguard Worker # If the same tag is found 361*c33452fbSAndroid Build Coastguard Worker if elementByTag in dom.childNodes: 362*c33452fbSAndroid Build Coastguard Worker 363*c33452fbSAndroid Build Coastguard Worker # Yield next level 364*c33452fbSAndroid Build Coastguard Worker for element in self._findChildFromTagPath(elementByTag, path): 365*c33452fbSAndroid Build Coastguard Worker yield element 366*c33452fbSAndroid Build Coastguard Worker 367*c33452fbSAndroid Build Coastguard Worker 368*c33452fbSAndroid Build Coastguard Workerclass Rule(Element): 369*c33452fbSAndroid Build Coastguard Worker 370*c33452fbSAndroid Build Coastguard Worker def usedIfApplicable(self, criteria): 371*c33452fbSAndroid Build Coastguard Worker childApplicability = (child.usedIfApplicable(criteria) 372*c33452fbSAndroid Build Coastguard Worker for child in self.children) 373*c33452fbSAndroid Build Coastguard Worker 374*c33452fbSAndroid Build Coastguard Worker isApplicable = self._isApplicable(criteria, childApplicability) 375*c33452fbSAndroid Build Coastguard Worker 376*c33452fbSAndroid Build Coastguard Worker if isApplicable: 377*c33452fbSAndroid Build Coastguard Worker self._incNbUse() 378*c33452fbSAndroid Build Coastguard Worker 379*c33452fbSAndroid Build Coastguard Worker self.debug("Rule applicability: %s" % isApplicable) 380*c33452fbSAndroid Build Coastguard Worker assert(isApplicable == True or isApplicable == False) 381*c33452fbSAndroid Build Coastguard Worker 382*c33452fbSAndroid Build Coastguard Worker return isApplicable 383*c33452fbSAndroid Build Coastguard Worker 384*c33452fbSAndroid Build Coastguard Worker 385*c33452fbSAndroid Build Coastguard Worker def _isApplicable(self, criteria, childApplicability): 386*c33452fbSAndroid Build Coastguard Worker """Return the rule applicability depending on children applicability. 387*c33452fbSAndroid Build Coastguard Worker 388*c33452fbSAndroid Build Coastguard Worker If at least one child is applicable, return true""" 389*c33452fbSAndroid Build Coastguard Worker # Lazy evaluation as in the PFW 390*c33452fbSAndroid Build Coastguard Worker return all(childApplicability) 391*c33452fbSAndroid Build Coastguard Worker 392*c33452fbSAndroid Build Coastguard Worker 393*c33452fbSAndroid Build Coastguard Workerclass CriterionRule(FromDomElement, DomPopulatedElement, Rule): 394*c33452fbSAndroid Build Coastguard Worker tag = "SelectionCriterionRule" 395*c33452fbSAndroid Build Coastguard Worker childClasses = [] 396*c33452fbSAndroid Build Coastguard Worker isApplicableOperations = { 397*c33452fbSAndroid Build Coastguard Worker "Includes" : lambda criterion, value: criterion.stateIncludes(value), 398*c33452fbSAndroid Build Coastguard Worker "Excludes" : lambda criterion, value: not criterion.stateIncludes(value), 399*c33452fbSAndroid Build Coastguard Worker "Is" : lambda criterion, value: criterion.stateIs(value), 400*c33452fbSAndroid Build Coastguard Worker "IsNot" : lambda criterion, value: not criterion.stateIs(value) 401*c33452fbSAndroid Build Coastguard Worker } 402*c33452fbSAndroid Build Coastguard Worker 403*c33452fbSAndroid Build Coastguard Worker def _initFromDom(self, DomElement): 404*c33452fbSAndroid Build Coastguard Worker self.selectionCriterion = DomElement.getAttribute("SelectionCriterion") 405*c33452fbSAndroid Build Coastguard Worker self.matchesWhen = DomElement.getAttribute("MatchesWhen") 406*c33452fbSAndroid Build Coastguard Worker self.value = DomElement.getAttribute("Value") 407*c33452fbSAndroid Build Coastguard Worker self.name = "%s %s %s" % (self.selectionCriterion, self.matchesWhen, self.value) 408*c33452fbSAndroid Build Coastguard Worker 409*c33452fbSAndroid Build Coastguard Worker applicableOperationWithoutValue = self.isApplicableOperations[self.matchesWhen] 410*c33452fbSAndroid Build Coastguard Worker self.isApplicableOperation = lambda criterion: applicableOperationWithoutValue(criterion, 411*c33452fbSAndroid Build Coastguard Worker self.value) 412*c33452fbSAndroid Build Coastguard Worker 413*c33452fbSAndroid Build Coastguard Worker def _isApplicable(self, criteria, childApplicability): 414*c33452fbSAndroid Build Coastguard Worker 415*c33452fbSAndroid Build Coastguard Worker return criteria.operationOnChild([self.selectionCriterion], self.isApplicableOperation) 416*c33452fbSAndroid Build Coastguard Worker 417*c33452fbSAndroid Build Coastguard Worker 418*c33452fbSAndroid Build Coastguard Workerclass CompoundRule(FromDomElement, DomPopulatedElement, Rule): 419*c33452fbSAndroid Build Coastguard Worker """CompoundRule can be of type ALL or ANY""" 420*c33452fbSAndroid Build Coastguard Worker tag = "CompoundRule" 421*c33452fbSAndroid Build Coastguard Worker # Declare childClasses but define it at first class instantiation 422*c33452fbSAndroid Build Coastguard Worker childClasses = None 423*c33452fbSAndroid Build Coastguard Worker 424*c33452fbSAndroid Build Coastguard Worker def __init__(self, dom): 425*c33452fbSAndroid Build Coastguard Worker # Define childClasses at first class instantiation 426*c33452fbSAndroid Build Coastguard Worker if self.childClasses == None: 427*c33452fbSAndroid Build Coastguard Worker self.childClasses = [DomElementLocation(CriterionRule), 428*c33452fbSAndroid Build Coastguard Worker DomElementLocation(CompoundRule)] 429*c33452fbSAndroid Build Coastguard Worker super().__init__(dom) 430*c33452fbSAndroid Build Coastguard Worker 431*c33452fbSAndroid Build Coastguard Worker def _initFromDom(self, DomElement): 432*c33452fbSAndroid Build Coastguard Worker 433*c33452fbSAndroid Build Coastguard Worker type = DomElement.getAttribute("Type") 434*c33452fbSAndroid Build Coastguard Worker self.ofTypeAll = {"All" : True, "Any" : False}[type] 435*c33452fbSAndroid Build Coastguard Worker self.name = type 436*c33452fbSAndroid Build Coastguard Worker 437*c33452fbSAndroid Build Coastguard Worker def _isApplicable(self, criteria, childApplicability): 438*c33452fbSAndroid Build Coastguard Worker if self.ofTypeAll: 439*c33452fbSAndroid Build Coastguard Worker applicability = super()._isApplicable(criteria, childApplicability) 440*c33452fbSAndroid Build Coastguard Worker else: 441*c33452fbSAndroid Build Coastguard Worker # Lazy evaluation as in the PFW 442*c33452fbSAndroid Build Coastguard Worker applicability = any(childApplicability) 443*c33452fbSAndroid Build Coastguard Worker 444*c33452fbSAndroid Build Coastguard Worker return applicability 445*c33452fbSAndroid Build Coastguard Worker 446*c33452fbSAndroid Build Coastguard Workerclass RootRule(DomPopulatedElement, Rule): 447*c33452fbSAndroid Build Coastguard Worker tag = "RootRule" 448*c33452fbSAndroid Build Coastguard Worker childClasses = [DomElementLocation(CompoundRule)] 449*c33452fbSAndroid Build Coastguard Worker 450*c33452fbSAndroid Build Coastguard Worker def populate(self, dom): 451*c33452fbSAndroid Build Coastguard Worker super().populate(dom) 452*c33452fbSAndroid Build Coastguard Worker self.debug("Children: %s" % self.children) 453*c33452fbSAndroid Build Coastguard Worker # A configuration can only have one or no rule 454*c33452fbSAndroid Build Coastguard Worker assert(len(self.children) <= 1) 455*c33452fbSAndroid Build Coastguard Worker 456*c33452fbSAndroid Build Coastguard Worker def _getCoverageDependanceElements(self): 457*c33452fbSAndroid Build Coastguard Worker return self._getDescendants() 458*c33452fbSAndroid Build Coastguard Worker 459*c33452fbSAndroid Build Coastguard Worker 460*c33452fbSAndroid Build Coastguard Workerclass CriteronStates(Element): 461*c33452fbSAndroid Build Coastguard Worker """Root of configuration application criterion state""" 462*c33452fbSAndroid Build Coastguard Worker tag = "CriterionStates" 463*c33452fbSAndroid Build Coastguard Worker 464*c33452fbSAndroid Build Coastguard Worker def parentUsed(self, criteria): 465*c33452fbSAndroid Build Coastguard Worker """Add criteria to child if not exist, if exist increase it's nbUse""" 466*c33452fbSAndroid Build Coastguard Worker self._incNbUse() 467*c33452fbSAndroid Build Coastguard Worker 468*c33452fbSAndroid Build Coastguard Worker matches = [child for child in self.children if child == criteria] 469*c33452fbSAndroid Build Coastguard Worker 470*c33452fbSAndroid Build Coastguard Worker assert(len(matches) <= 1) 471*c33452fbSAndroid Build Coastguard Worker 472*c33452fbSAndroid Build Coastguard Worker if matches: 473*c33452fbSAndroid Build Coastguard Worker self.debug("Criteria state has already been encounter") 474*c33452fbSAndroid Build Coastguard Worker currentcriteria = matches[0] 475*c33452fbSAndroid Build Coastguard Worker else: 476*c33452fbSAndroid Build Coastguard Worker self.debug("Criteria state has never been encounter, saving it") 477*c33452fbSAndroid Build Coastguard Worker currentcriteria = criteria 478*c33452fbSAndroid Build Coastguard Worker self.addChild(criteria) 479*c33452fbSAndroid Build Coastguard Worker 480*c33452fbSAndroid Build Coastguard Worker currentcriteria.parentUsed() 481*c33452fbSAndroid Build Coastguard Worker 482*c33452fbSAndroid Build Coastguard Worker 483*c33452fbSAndroid Build Coastguard Worker 484*c33452fbSAndroid Build Coastguard Workerclass Configuration(FromDomElement, DomPopulatedElement): 485*c33452fbSAndroid Build Coastguard Worker tag = "Configuration" 486*c33452fbSAndroid Build Coastguard Worker childClasses = [] 487*c33452fbSAndroid Build Coastguard Worker 488*c33452fbSAndroid Build Coastguard Worker class IneligibleConfigurationAppliedError(CustomError): 489*c33452fbSAndroid Build Coastguard Worker 490*c33452fbSAndroid Build Coastguard Worker def __init__(self, configuration, criteria): 491*c33452fbSAndroid Build Coastguard Worker self.configuration = configuration 492*c33452fbSAndroid Build Coastguard Worker self.criteria = criteria 493*c33452fbSAndroid Build Coastguard Worker 494*c33452fbSAndroid Build Coastguard Worker def __str__(self): 495*c33452fbSAndroid Build Coastguard Worker 496*c33452fbSAndroid Build Coastguard Worker return ("Applying ineligible %s, " 497*c33452fbSAndroid Build Coastguard Worker "rule:\n%s\n" 498*c33452fbSAndroid Build Coastguard Worker "Criteria current state:\n%s" % ( 499*c33452fbSAndroid Build Coastguard Worker self.configuration, 500*c33452fbSAndroid Build Coastguard Worker self.configuration.rootRule.dump(withCoverage=False, withNbUse=False), 501*c33452fbSAndroid Build Coastguard Worker self.criteria.dump(withCoverage=False, withNbUse=False) 502*c33452fbSAndroid Build Coastguard Worker )) 503*c33452fbSAndroid Build Coastguard Worker 504*c33452fbSAndroid Build Coastguard Worker def __init__(self, DomElement): 505*c33452fbSAndroid Build Coastguard Worker super().__init__(DomElement) 506*c33452fbSAndroid Build Coastguard Worker 507*c33452fbSAndroid Build Coastguard Worker self.rootRule = RootRule("RootRule") 508*c33452fbSAndroid Build Coastguard Worker self.addChild(self.rootRule) 509*c33452fbSAndroid Build Coastguard Worker 510*c33452fbSAndroid Build Coastguard Worker self.criteronStates = CriteronStates("CriterionStates") 511*c33452fbSAndroid Build Coastguard Worker self.addChild(self.criteronStates) 512*c33452fbSAndroid Build Coastguard Worker 513*c33452fbSAndroid Build Coastguard Worker def populate(self, dom): 514*c33452fbSAndroid Build Coastguard Worker # Delegate to rootRule 515*c33452fbSAndroid Build Coastguard Worker self.rootRule.populate(dom) 516*c33452fbSAndroid Build Coastguard Worker 517*c33452fbSAndroid Build Coastguard Worker def _getCoverage(self): 518*c33452fbSAndroid Build Coastguard Worker # Delegate to rootRule 519*c33452fbSAndroid Build Coastguard Worker return self.rootRule._getCoverage() 520*c33452fbSAndroid Build Coastguard Worker 521*c33452fbSAndroid Build Coastguard Worker def used(self, criteria): 522*c33452fbSAndroid Build Coastguard Worker 523*c33452fbSAndroid Build Coastguard Worker self._incNbUse() 524*c33452fbSAndroid Build Coastguard Worker 525*c33452fbSAndroid Build Coastguard Worker # Propagate use to parents 526*c33452fbSAndroid Build Coastguard Worker self._tellParentThatChildUsed() 527*c33452fbSAndroid Build Coastguard Worker 528*c33452fbSAndroid Build Coastguard Worker # Propagate to criterion coverage 529*c33452fbSAndroid Build Coastguard Worker self.criteronStates.parentUsed(criteria.export()) 530*c33452fbSAndroid Build Coastguard Worker 531*c33452fbSAndroid Build Coastguard Worker # Propagate to rules 532*c33452fbSAndroid Build Coastguard Worker if not self.rootRule.usedIfApplicable(criteria): 533*c33452fbSAndroid Build Coastguard Worker 534*c33452fbSAndroid Build Coastguard Worker self.debug("Applied but rule does not match current " 535*c33452fbSAndroid Build Coastguard Worker "criteria (parent: %s) " % self.parent.name, 536*c33452fbSAndroid Build Coastguard Worker logging.ERROR) 537*c33452fbSAndroid Build Coastguard Worker 538*c33452fbSAndroid Build Coastguard Worker raise self.IneligibleConfigurationAppliedError(self, criteria.export()) 539*c33452fbSAndroid Build Coastguard Worker 540*c33452fbSAndroid Build Coastguard Worker def _dumpPropagate(self, withCoverage, withNbUse): 541*c33452fbSAndroid Build Coastguard Worker self.debug("Going to ask %s for description" % self.rootRule) 542*c33452fbSAndroid Build Coastguard Worker for dumpedDescription in self.rootRule._dumpDescription( 543*c33452fbSAndroid Build Coastguard Worker withCoverage=withCoverage, 544*c33452fbSAndroid Build Coastguard Worker withNbUse=withNbUse): 545*c33452fbSAndroid Build Coastguard Worker yield dumpedDescription.increasedRank() 546*c33452fbSAndroid Build Coastguard Worker 547*c33452fbSAndroid Build Coastguard Worker self.debug("Going to ask %s for description" % self.criteronStates) 548*c33452fbSAndroid Build Coastguard Worker for dumpedDescription in self.criteronStates._dumpDescription( 549*c33452fbSAndroid Build Coastguard Worker withCoverage=False, 550*c33452fbSAndroid Build Coastguard Worker withNbUse=withNbUse): 551*c33452fbSAndroid Build Coastguard Worker yield dumpedDescription.increasedRank() 552*c33452fbSAndroid Build Coastguard Worker 553*c33452fbSAndroid Build Coastguard Worker 554*c33452fbSAndroid Build Coastguard Workerclass Domain(FromDomElement, DomPopulatedElement): 555*c33452fbSAndroid Build Coastguard Worker tag = "ConfigurableDomain" 556*c33452fbSAndroid Build Coastguard Worker childClasses = [DomElementLocation(Configuration, ["Configurations"])] 557*c33452fbSAndroid Build Coastguard Worker 558*c33452fbSAndroid Build Coastguard Worker 559*c33452fbSAndroid Build Coastguard Workerclass Domains(DomPopulatedElement): 560*c33452fbSAndroid Build Coastguard Worker tag = "Domains" 561*c33452fbSAndroid Build Coastguard Worker childClasses = [DomElementLocation(Domain, ["ConfigurableDomains"])] 562*c33452fbSAndroid Build Coastguard Worker 563*c33452fbSAndroid Build Coastguard Worker 564*c33452fbSAndroid Build Coastguard Workerclass RankedLine(): 565*c33452fbSAndroid Build Coastguard Worker def __init__(self, string, 566*c33452fbSAndroid Build Coastguard Worker stringPrefix="|-- ", 567*c33452fbSAndroid Build Coastguard Worker rankString="| ", 568*c33452fbSAndroid Build Coastguard Worker linePrefix="", 569*c33452fbSAndroid Build Coastguard Worker lineSuffix="\n"): 570*c33452fbSAndroid Build Coastguard Worker self.string = string 571*c33452fbSAndroid Build Coastguard Worker self.rank = 0 572*c33452fbSAndroid Build Coastguard Worker self.stringPrefix = stringPrefix 573*c33452fbSAndroid Build Coastguard Worker self.rankString = rankString 574*c33452fbSAndroid Build Coastguard Worker self.linePrefix = linePrefix 575*c33452fbSAndroid Build Coastguard Worker self.lineSuffix = lineSuffix 576*c33452fbSAndroid Build Coastguard Worker 577*c33452fbSAndroid Build Coastguard Worker def increasedRank(self): 578*c33452fbSAndroid Build Coastguard Worker self.rank += 1 579*c33452fbSAndroid Build Coastguard Worker return self 580*c33452fbSAndroid Build Coastguard Worker 581*c33452fbSAndroid Build Coastguard Worker def __str__(self): 582*c33452fbSAndroid Build Coastguard Worker return self.linePrefix + \ 583*c33452fbSAndroid Build Coastguard Worker self.rank * self.rankString + \ 584*c33452fbSAndroid Build Coastguard Worker self.stringPrefix + \ 585*c33452fbSAndroid Build Coastguard Worker self.string + \ 586*c33452fbSAndroid Build Coastguard Worker self.lineSuffix 587*c33452fbSAndroid Build Coastguard Worker 588*c33452fbSAndroid Build Coastguard Workerclass DebugRankedLine(RankedLine): 589*c33452fbSAndroid Build Coastguard Worker 590*c33452fbSAndroid Build Coastguard Worker def __init__(self, string, lineSuffix=""): 591*c33452fbSAndroid Build Coastguard Worker super().__init__(string, 592*c33452fbSAndroid Build Coastguard Worker stringPrefix="", 593*c33452fbSAndroid Build Coastguard Worker rankString=" ", 594*c33452fbSAndroid Build Coastguard Worker linePrefix="", 595*c33452fbSAndroid Build Coastguard Worker lineSuffix=lineSuffix) 596*c33452fbSAndroid Build Coastguard Worker 597*c33452fbSAndroid Build Coastguard Worker 598*c33452fbSAndroid Build Coastguard Workerclass CriterionState(Element): 599*c33452fbSAndroid Build Coastguard Worker tag = "CriterionState" 600*c33452fbSAndroid Build Coastguard Worker def used(self): 601*c33452fbSAndroid Build Coastguard Worker self._incNbUse() 602*c33452fbSAndroid Build Coastguard Worker 603*c33452fbSAndroid Build Coastguard Worker 604*c33452fbSAndroid Build Coastguard Workerclass Criterion(Element): 605*c33452fbSAndroid Build Coastguard Worker tag = "Criterion" 606*c33452fbSAndroid Build Coastguard Worker inclusivenessTranslate = {True: "Inclusive", False: "Exclusive"} 607*c33452fbSAndroid Build Coastguard Worker 608*c33452fbSAndroid Build Coastguard Worker class ChangeRequestToNonAccessibleState(CustomError): 609*c33452fbSAndroid Build Coastguard Worker def __init__(self, requestedState, detail): 610*c33452fbSAndroid Build Coastguard Worker self.requestedState = requestedState 611*c33452fbSAndroid Build Coastguard Worker self.detail = detail 612*c33452fbSAndroid Build Coastguard Worker 613*c33452fbSAndroid Build Coastguard Worker def __str__(self): 614*c33452fbSAndroid Build Coastguard Worker return ("Change request to non accessible state %s. Detail: %s" % 615*c33452fbSAndroid Build Coastguard Worker (self.requestedState, self.detail)) 616*c33452fbSAndroid Build Coastguard Worker 617*c33452fbSAndroid Build Coastguard Worker def __init__(self, name, isInclusif, 618*c33452fbSAndroid Build Coastguard Worker stateNamesList, currentStateNamesList, 619*c33452fbSAndroid Build Coastguard Worker ignoreIntegrity=False): 620*c33452fbSAndroid Build Coastguard Worker super().__init__(name) 621*c33452fbSAndroid Build Coastguard Worker self.isInclusif = isInclusif 622*c33452fbSAndroid Build Coastguard Worker 623*c33452fbSAndroid Build Coastguard Worker for state in stateNamesList: 624*c33452fbSAndroid Build Coastguard Worker self.addChild(CriterionState(state)) 625*c33452fbSAndroid Build Coastguard Worker 626*c33452fbSAndroid Build Coastguard Worker self.currentState = [] 627*c33452fbSAndroid Build Coastguard Worker self.initStateNamesList = list(currentStateNamesList) 628*c33452fbSAndroid Build Coastguard Worker self.changeState(self.initStateNamesList, ignoreIntegrity) 629*c33452fbSAndroid Build Coastguard Worker 630*c33452fbSAndroid Build Coastguard Worker def reset(self): 631*c33452fbSAndroid Build Coastguard Worker # Set current state as provided at initialisation 632*c33452fbSAndroid Build Coastguard Worker self.changeState(self.initStateNamesList, ignoreIntegrity=True) 633*c33452fbSAndroid Build Coastguard Worker 634*c33452fbSAndroid Build Coastguard Worker def changeState(self, subStateNames, ignoreIntegrity=False): 635*c33452fbSAndroid Build Coastguard Worker self.debug("Changing state from: %s to: %s" % ( 636*c33452fbSAndroid Build Coastguard Worker list(self._getElementNames(self.currentState)), 637*c33452fbSAndroid Build Coastguard Worker subStateNames)) 638*c33452fbSAndroid Build Coastguard Worker 639*c33452fbSAndroid Build Coastguard Worker if not ignoreIntegrity and not self.isIntegre(subStateNames): 640*c33452fbSAndroid Build Coastguard Worker raise self.ChangeRequestToNonAccessibleState(subStateNames, 641*c33452fbSAndroid Build Coastguard Worker "An exclusive criterion must have a non \ 642*c33452fbSAndroid Build Coastguard Worker empty state") 643*c33452fbSAndroid Build Coastguard Worker 644*c33452fbSAndroid Build Coastguard Worker newCurrentState = [] 645*c33452fbSAndroid Build Coastguard Worker for subStateName in subStateNames: 646*c33452fbSAndroid Build Coastguard Worker subState = self.getChildFromName(subStateName) 647*c33452fbSAndroid Build Coastguard Worker subState.used() 648*c33452fbSAndroid Build Coastguard Worker newCurrentState.append(subState) 649*c33452fbSAndroid Build Coastguard Worker 650*c33452fbSAndroid Build Coastguard Worker self.currentState = newCurrentState 651*c33452fbSAndroid Build Coastguard Worker 652*c33452fbSAndroid Build Coastguard Worker self._incNbUse() 653*c33452fbSAndroid Build Coastguard Worker self._tellParentThatChildUsed() 654*c33452fbSAndroid Build Coastguard Worker 655*c33452fbSAndroid Build Coastguard Worker def isIntegre(self, subStateNames): 656*c33452fbSAndroid Build Coastguard Worker return self.isInclusif or len(subStateNames) == 1 657*c33452fbSAndroid Build Coastguard Worker 658*c33452fbSAndroid Build Coastguard Worker def childUsed(self, child): 659*c33452fbSAndroid Build Coastguard Worker self.currentState = child 660*c33452fbSAndroid Build Coastguard Worker super().childUsed(child) 661*c33452fbSAndroid Build Coastguard Worker 662*c33452fbSAndroid Build Coastguard Worker def export(self): 663*c33452fbSAndroid Build Coastguard Worker subStateNames = self._getElementNames(self.currentState) 664*c33452fbSAndroid Build Coastguard Worker return Criterion(self.name, self.isInclusif, subStateNames, subStateNames, 665*c33452fbSAndroid Build Coastguard Worker ignoreIntegrity=True) 666*c33452fbSAndroid Build Coastguard Worker 667*c33452fbSAndroid Build Coastguard Worker def stateIncludes(self, subStateName): 668*c33452fbSAndroid Build Coastguard Worker subStateCurrentNames = list(self._getElementNames(self.currentState)) 669*c33452fbSAndroid Build Coastguard Worker 670*c33452fbSAndroid Build Coastguard Worker self.debug("Testing if %s is included in %s" % (subStateName, subStateCurrentNames)) 671*c33452fbSAndroid Build Coastguard Worker 672*c33452fbSAndroid Build Coastguard Worker isIncluded = subStateName in subStateCurrentNames 673*c33452fbSAndroid Build Coastguard Worker self.debug("IsIncluded: %s" % isIncluded) 674*c33452fbSAndroid Build Coastguard Worker 675*c33452fbSAndroid Build Coastguard Worker return isIncluded 676*c33452fbSAndroid Build Coastguard Worker 677*c33452fbSAndroid Build Coastguard Worker 678*c33452fbSAndroid Build Coastguard Worker def stateIs(self, subStateNames): 679*c33452fbSAndroid Build Coastguard Worker if len(self.currentState) != 1: 680*c33452fbSAndroid Build Coastguard Worker return False 681*c33452fbSAndroid Build Coastguard Worker else: 682*c33452fbSAndroid Build Coastguard Worker return self.stateIncludes(subStateNames) 683*c33452fbSAndroid Build Coastguard Worker 684*c33452fbSAndroid Build Coastguard Worker def _getXMLAttributes(self): 685*c33452fbSAndroid Build Coastguard Worker attributes = super()._getXMLAttributes() 686*c33452fbSAndroid Build Coastguard Worker attributes["Type"] = self.inclusivenessTranslate[self.isInclusif] 687*c33452fbSAndroid Build Coastguard Worker return attributes 688*c33452fbSAndroid Build Coastguard Worker 689*c33452fbSAndroid Build Coastguard Worker 690*c33452fbSAndroid Build Coastguard Workerclass Criteria(Element): 691*c33452fbSAndroid Build Coastguard Worker tag = "Criteria" 692*c33452fbSAndroid Build Coastguard Worker 693*c33452fbSAndroid Build Coastguard Worker class DuplicatedCriterionError(DuplicatedChildError): 694*c33452fbSAndroid Build Coastguard Worker pass 695*c33452fbSAndroid Build Coastguard Worker 696*c33452fbSAndroid Build Coastguard Worker def export(self): 697*c33452fbSAndroid Build Coastguard Worker self.debug("Exporting criteria") 698*c33452fbSAndroid Build Coastguard Worker assert(self.children) 699*c33452fbSAndroid Build Coastguard Worker 700*c33452fbSAndroid Build Coastguard Worker exported = Criteria(self.name) 701*c33452fbSAndroid Build Coastguard Worker for child in self.children: 702*c33452fbSAndroid Build Coastguard Worker exported.addChild(child.export()) 703*c33452fbSAndroid Build Coastguard Worker return exported 704*c33452fbSAndroid Build Coastguard Worker 705*c33452fbSAndroid Build Coastguard Worker def addChild(self, child): 706*c33452fbSAndroid Build Coastguard Worker if child in self.children: 707*c33452fbSAndroid Build Coastguard Worker raise self.DuplicatedCriterionError(self, child) 708*c33452fbSAndroid Build Coastguard Worker super().addChild(child) 709*c33452fbSAndroid Build Coastguard Worker 710*c33452fbSAndroid Build Coastguard Workerclass ConfigAppliedWithoutCriteriaError(CustomError): 711*c33452fbSAndroid Build Coastguard Worker def __init__(self, configurationName, domainName): 712*c33452fbSAndroid Build Coastguard Worker self.configurationName = configurationName 713*c33452fbSAndroid Build Coastguard Worker self.domainName = domainName 714*c33452fbSAndroid Build Coastguard Worker def __str__(self): 715*c33452fbSAndroid Build Coastguard Worker return ('Applying configuration "%s" from domain "%s" before declaring criteria' % 716*c33452fbSAndroid Build Coastguard Worker (self.configurationName, self.domainName)) 717*c33452fbSAndroid Build Coastguard Worker 718*c33452fbSAndroid Build Coastguard Workerclass ParsePFWlog(): 719*c33452fbSAndroid Build Coastguard Worker MATCH = "match" 720*c33452fbSAndroid Build Coastguard Worker ACTION = "action" 721*c33452fbSAndroid Build Coastguard Worker 722*c33452fbSAndroid Build Coastguard Worker class ChangeRequestOnUnknownCriterion(CustomError): 723*c33452fbSAndroid Build Coastguard Worker def __init__(self, criterion): 724*c33452fbSAndroid Build Coastguard Worker self.criterion = criterion 725*c33452fbSAndroid Build Coastguard Worker 726*c33452fbSAndroid Build Coastguard Worker def __str__(self): 727*c33452fbSAndroid Build Coastguard Worker return ("Change request on an unknown criterion %s." % 728*c33452fbSAndroid Build Coastguard Worker self.criterion) 729*c33452fbSAndroid Build Coastguard Worker 730*c33452fbSAndroid Build Coastguard Worker def __init__(self, domains, criteria, ErrorsToIgnore=()): 731*c33452fbSAndroid Build Coastguard Worker 732*c33452fbSAndroid Build Coastguard Worker self.domains = domains 733*c33452fbSAndroid Build Coastguard Worker self.criteria = criteria 734*c33452fbSAndroid Build Coastguard Worker self.ErrorsToIgnore = ErrorsToIgnore 735*c33452fbSAndroid Build Coastguard Worker 736*c33452fbSAndroid Build Coastguard Worker configApplicationRegext = r""".*Applying configuration "(.*)" from domain "([^"]*)""" 737*c33452fbSAndroid Build Coastguard Worker matchConfigApplicationLine = re.compile(configApplicationRegext).match 738*c33452fbSAndroid Build Coastguard Worker 739*c33452fbSAndroid Build Coastguard Worker criterionCreationRegext = ", ".join([ 740*c33452fbSAndroid Build Coastguard Worker r""".*Criterion name: (.*)""", 741*c33452fbSAndroid Build Coastguard Worker r"""type kind: (.*)""", 742*c33452fbSAndroid Build Coastguard Worker r"""current state: (.*)""", 743*c33452fbSAndroid Build Coastguard Worker r"""states: {(.*)}""" 744*c33452fbSAndroid Build Coastguard Worker ]) 745*c33452fbSAndroid Build Coastguard Worker matchCriterionCreationLine = re.compile(criterionCreationRegext).match 746*c33452fbSAndroid Build Coastguard Worker 747*c33452fbSAndroid Build Coastguard Worker changingCriterionRegext = r""".*Selection criterion changed event: Criterion name: (.*), \ 748*c33452fbSAndroid Build Coastguard Worker current state: ([^\n\r]*)""" 749*c33452fbSAndroid Build Coastguard Worker matchChangingCriterionLine = re.compile(changingCriterionRegext).match 750*c33452fbSAndroid Build Coastguard Worker 751*c33452fbSAndroid Build Coastguard Worker self.lineLogTypes = [ 752*c33452fbSAndroid Build Coastguard Worker { 753*c33452fbSAndroid Build Coastguard Worker self.MATCH: matchConfigApplicationLine, 754*c33452fbSAndroid Build Coastguard Worker self.ACTION: self._configApplication 755*c33452fbSAndroid Build Coastguard Worker }, { 756*c33452fbSAndroid Build Coastguard Worker self.MATCH: matchCriterionCreationLine, 757*c33452fbSAndroid Build Coastguard Worker self.ACTION: self._criterionCreation 758*c33452fbSAndroid Build Coastguard Worker }, { 759*c33452fbSAndroid Build Coastguard Worker self.MATCH: matchChangingCriterionLine, 760*c33452fbSAndroid Build Coastguard Worker self.ACTION: self._changingCriterion 761*c33452fbSAndroid Build Coastguard Worker } 762*c33452fbSAndroid Build Coastguard Worker ] 763*c33452fbSAndroid Build Coastguard Worker 764*c33452fbSAndroid Build Coastguard Worker @staticmethod 765*c33452fbSAndroid Build Coastguard Worker def _formatCriterionList(liststring, separator): 766*c33452fbSAndroid Build Coastguard Worker list = liststring.split(separator) 767*c33452fbSAndroid Build Coastguard Worker if len(list) == 1 and list[0] == "<none>": 768*c33452fbSAndroid Build Coastguard Worker list = [] 769*c33452fbSAndroid Build Coastguard Worker return list 770*c33452fbSAndroid Build Coastguard Worker 771*c33452fbSAndroid Build Coastguard Worker def _criterionCreation(self, matchCriterionCreation): 772*c33452fbSAndroid Build Coastguard Worker # Unpack 773*c33452fbSAndroid Build Coastguard Worker criterionName, criterionType, currentCriterionStates, criterionStates = matchCriterionCreation.group(1, 2, 3, 4) 774*c33452fbSAndroid Build Coastguard Worker 775*c33452fbSAndroid Build Coastguard Worker criterionStateList = self._formatCriterionList(criterionStates, ", ") 776*c33452fbSAndroid Build Coastguard Worker 777*c33452fbSAndroid Build Coastguard Worker criterionIsInclusif = {"exclusive" : False, "inclusive" : True}[criterionType] 778*c33452fbSAndroid Build Coastguard Worker 779*c33452fbSAndroid Build Coastguard Worker currentcriterionStateList = self._formatCriterionList(currentCriterionStates, "|") 780*c33452fbSAndroid Build Coastguard Worker 781*c33452fbSAndroid Build Coastguard Worker logger.info("Creating criterion: " + criterionName + 782*c33452fbSAndroid Build Coastguard Worker " (" + criterionType + ") " + 783*c33452fbSAndroid Build Coastguard Worker " with current state: " + str(currentcriterionStateList) + 784*c33452fbSAndroid Build Coastguard Worker ", possible states:" + str(criterionStateList)) 785*c33452fbSAndroid Build Coastguard Worker 786*c33452fbSAndroid Build Coastguard Worker try: 787*c33452fbSAndroid Build Coastguard Worker self.criteria.addChild(Criterion( 788*c33452fbSAndroid Build Coastguard Worker criterionName, 789*c33452fbSAndroid Build Coastguard Worker criterionIsInclusif, 790*c33452fbSAndroid Build Coastguard Worker criterionStateList, 791*c33452fbSAndroid Build Coastguard Worker currentcriterionStateList 792*c33452fbSAndroid Build Coastguard Worker )) 793*c33452fbSAndroid Build Coastguard Worker except self.criteria.DuplicatedCriterionError as ex: 794*c33452fbSAndroid Build Coastguard Worker logger.debug(ex) 795*c33452fbSAndroid Build Coastguard Worker logger.warning("Reseting criterion %s. Did you reset the PFW ?" % criterionName) 796*c33452fbSAndroid Build Coastguard Worker self.criteria.operationOnChild( 797*c33452fbSAndroid Build Coastguard Worker [criterionName], 798*c33452fbSAndroid Build Coastguard Worker lambda criterion: criterion.reset() 799*c33452fbSAndroid Build Coastguard Worker ) 800*c33452fbSAndroid Build Coastguard Worker 801*c33452fbSAndroid Build Coastguard Worker 802*c33452fbSAndroid Build Coastguard Worker 803*c33452fbSAndroid Build Coastguard Worker def _changingCriterion(self, matchChangingCriterion): 804*c33452fbSAndroid Build Coastguard Worker # Unpack 805*c33452fbSAndroid Build Coastguard Worker criterionName, newCriterionSubStateNames = matchChangingCriterion.group(1, 2) 806*c33452fbSAndroid Build Coastguard Worker 807*c33452fbSAndroid Build Coastguard Worker newCriterionState = self._formatCriterionList(newCriterionSubStateNames, "|") 808*c33452fbSAndroid Build Coastguard Worker 809*c33452fbSAndroid Build Coastguard Worker logger.info("Changing criterion %s to %s" % (criterionName, newCriterionState)) 810*c33452fbSAndroid Build Coastguard Worker 811*c33452fbSAndroid Build Coastguard Worker path = [criterionName] 812*c33452fbSAndroid Build Coastguard Worker changeCriterionOperation = lambda criterion: criterion.changeState(newCriterionState) 813*c33452fbSAndroid Build Coastguard Worker try: 814*c33452fbSAndroid Build Coastguard Worker self.criteria.operationOnChild(path, changeCriterionOperation) 815*c33452fbSAndroid Build Coastguard Worker except ChildNotFoundError: 816*c33452fbSAndroid Build Coastguard Worker raise self.ChangeRequestOnUnknownCriterion(criterionName) 817*c33452fbSAndroid Build Coastguard Worker 818*c33452fbSAndroid Build Coastguard Worker def _configApplication(self, matchConfig): 819*c33452fbSAndroid Build Coastguard Worker # Unpack 820*c33452fbSAndroid Build Coastguard Worker configurationName, domainName = matchConfig.group(1, 2) 821*c33452fbSAndroid Build Coastguard Worker 822*c33452fbSAndroid Build Coastguard Worker # Check that at least one criterion exist 823*c33452fbSAndroid Build Coastguard Worker if not self.criteria.hasChildren(): 824*c33452fbSAndroid Build Coastguard Worker logger.error("Applying configuration before declaring criteria") 825*c33452fbSAndroid Build Coastguard Worker logger.info("Is the log starting at PFW boot ?") 826*c33452fbSAndroid Build Coastguard Worker raise ConfigAppliedWithoutCriteriaError(configurationName, domainName) 827*c33452fbSAndroid Build Coastguard Worker 828*c33452fbSAndroid Build Coastguard Worker # Change criterion state 829*c33452fbSAndroid Build Coastguard Worker path = [domainName, configurationName] 830*c33452fbSAndroid Build Coastguard Worker usedOperation = lambda element: element.used(self.criteria) 831*c33452fbSAndroid Build Coastguard Worker 832*c33452fbSAndroid Build Coastguard Worker logger.info("Applying configuration %s from domain %s" % ( 833*c33452fbSAndroid Build Coastguard Worker configurationName, domainName)) 834*c33452fbSAndroid Build Coastguard Worker 835*c33452fbSAndroid Build Coastguard Worker self.domains.operationOnChild(path, usedOperation) 836*c33452fbSAndroid Build Coastguard Worker 837*c33452fbSAndroid Build Coastguard Worker 838*c33452fbSAndroid Build Coastguard Worker def _digest(self, lineLogType, lineLog): 839*c33452fbSAndroid Build Coastguard Worker 840*c33452fbSAndroid Build Coastguard Worker match = lineLogType[self.MATCH](lineLog) 841*c33452fbSAndroid Build Coastguard Worker if match: 842*c33452fbSAndroid Build Coastguard Worker lineLogType[self.ACTION](match) 843*c33452fbSAndroid Build Coastguard Worker return True 844*c33452fbSAndroid Build Coastguard Worker return False 845*c33452fbSAndroid Build Coastguard Worker 846*c33452fbSAndroid Build Coastguard Worker 847*c33452fbSAndroid Build Coastguard Worker def parsePFWlog(self, lines): 848*c33452fbSAndroid Build Coastguard Worker for lineNb, lineLog in enumerate(lines, 1): # line number starts at 1 849*c33452fbSAndroid Build Coastguard Worker 850*c33452fbSAndroid Build Coastguard Worker logger.debug("Parsing line :%s" % lineLog.rstrip()) 851*c33452fbSAndroid Build Coastguard Worker 852*c33452fbSAndroid Build Coastguard Worker digested = (self._digest(lineLogType, lineLog) 853*c33452fbSAndroid Build Coastguard Worker for lineLogType in self.lineLogTypes) 854*c33452fbSAndroid Build Coastguard Worker 855*c33452fbSAndroid Build Coastguard Worker try: 856*c33452fbSAndroid Build Coastguard Worker success = any(digested) 857*c33452fbSAndroid Build Coastguard Worker 858*c33452fbSAndroid Build Coastguard Worker # Catch some exception in order to print the current parsing line, 859*c33452fbSAndroid Build Coastguard Worker # then raise the exception again if not continue of error 860*c33452fbSAndroid Build Coastguard Worker except CustomError as ex: 861*c33452fbSAndroid Build Coastguard Worker logger.error('Error raised while parsing line %s: "%s"' % 862*c33452fbSAndroid Build Coastguard Worker (lineNb, repr(lineLog))) 863*c33452fbSAndroid Build Coastguard Worker 864*c33452fbSAndroid Build Coastguard Worker # If exception is a subclass of ErrorsToIgnore, log it and continue 865*c33452fbSAndroid Build Coastguard Worker # otherwise raise it again. 866*c33452fbSAndroid Build Coastguard Worker if not issubclass(type(ex), self.ErrorsToIgnore): 867*c33452fbSAndroid Build Coastguard Worker raise ex 868*c33452fbSAndroid Build Coastguard Worker else: 869*c33452fbSAndroid Build Coastguard Worker logger.error('Ignoring exception:"%s", ' 870*c33452fbSAndroid Build Coastguard Worker 'can not guarantee database integrity' % ex) 871*c33452fbSAndroid Build Coastguard Worker else: 872*c33452fbSAndroid Build Coastguard Worker if not success: 873*c33452fbSAndroid Build Coastguard Worker logger.debug("Line does not match, dropped") 874*c33452fbSAndroid Build Coastguard Worker 875*c33452fbSAndroid Build Coastguard Worker 876*c33452fbSAndroid Build Coastguard Workerclass Root(Element): 877*c33452fbSAndroid Build Coastguard Worker tag = "CoverageReport" 878*c33452fbSAndroid Build Coastguard Worker def __init__(self, name, dom): 879*c33452fbSAndroid Build Coastguard Worker super().__init__(name) 880*c33452fbSAndroid Build Coastguard Worker # Create domain tree 881*c33452fbSAndroid Build Coastguard Worker self.domains = Domains("Domains") 882*c33452fbSAndroid Build Coastguard Worker self.domains.populate(dom) 883*c33452fbSAndroid Build Coastguard Worker self.addChild(self.domains) 884*c33452fbSAndroid Build Coastguard Worker # Create criterion list 885*c33452fbSAndroid Build Coastguard Worker self.criteria = Criteria("CriterionRoot") 886*c33452fbSAndroid Build Coastguard Worker self.addChild(self.criteria) 887*c33452fbSAndroid Build Coastguard Worker 888*c33452fbSAndroid Build Coastguard Worker def exportToXML(self): 889*c33452fbSAndroid Build Coastguard Worker """Export tree to an xml document""" 890*c33452fbSAndroid Build Coastguard Worker impl = xml.dom.minidom.getDOMImplementation() 891*c33452fbSAndroid Build Coastguard Worker document = impl.createDocument(namespaceURI=None, qualifiedName=self.tag, doctype=None) 892*c33452fbSAndroid Build Coastguard Worker super().exportToXML(document, document.documentElement) 893*c33452fbSAndroid Build Coastguard Worker 894*c33452fbSAndroid Build Coastguard Worker return document 895*c33452fbSAndroid Build Coastguard Worker 896*c33452fbSAndroid Build Coastguard Worker# ============================ 897*c33452fbSAndroid Build Coastguard Worker# Command line argument parser 898*c33452fbSAndroid Build Coastguard Worker# ============================ 899*c33452fbSAndroid Build Coastguard Worker 900*c33452fbSAndroid Build Coastguard Worker 901*c33452fbSAndroid Build Coastguard Workerclass ArgumentParser: 902*c33452fbSAndroid Build Coastguard Worker """class that parse command line arguments with argparse library 903*c33452fbSAndroid Build Coastguard Worker 904*c33452fbSAndroid Build Coastguard Worker Result of parsing are the class attributes. 905*c33452fbSAndroid Build Coastguard Worker """ 906*c33452fbSAndroid Build Coastguard Worker levelTranslate = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG] 907*c33452fbSAndroid Build Coastguard Worker 908*c33452fbSAndroid Build Coastguard Worker def __init__(self): 909*c33452fbSAndroid Build Coastguard Worker 910*c33452fbSAndroid Build Coastguard Worker try: 911*c33452fbSAndroid Build Coastguard Worker # As argparse is only in the stdlib since python 3.2, 912*c33452fbSAndroid Build Coastguard Worker # testing its availability 913*c33452fbSAndroid Build Coastguard Worker import argparse 914*c33452fbSAndroid Build Coastguard Worker 915*c33452fbSAndroid Build Coastguard Worker except ImportError: 916*c33452fbSAndroid Build Coastguard Worker logger.warning("Unable to import argparse " 917*c33452fbSAndroid Build Coastguard Worker "(parser for command-line options and arguments), " 918*c33452fbSAndroid Build Coastguard Worker "using default argument values:") 919*c33452fbSAndroid Build Coastguard Worker 920*c33452fbSAndroid Build Coastguard Worker logger.warning(" - InputFile: stdin") 921*c33452fbSAndroid Build Coastguard Worker self.inputFile = sys.stdin 922*c33452fbSAndroid Build Coastguard Worker 923*c33452fbSAndroid Build Coastguard Worker logger.warning(" - OutputFile: stdout") 924*c33452fbSAndroid Build Coastguard Worker self.outputFile = sys.stdout 925*c33452fbSAndroid Build Coastguard Worker 926*c33452fbSAndroid Build Coastguard Worker try: 927*c33452fbSAndroid Build Coastguard Worker self.domainsFile = sys.argv[1] 928*c33452fbSAndroid Build Coastguard Worker except IndexError as ex: 929*c33452fbSAndroid Build Coastguard Worker logger.fatal("No domain file provided (first argument)") 930*c33452fbSAndroid Build Coastguard Worker raise ex 931*c33452fbSAndroid Build Coastguard Worker else: 932*c33452fbSAndroid Build Coastguard Worker logger.warning(" - Domain file: " + self.domainsFile) 933*c33452fbSAndroid Build Coastguard Worker 934*c33452fbSAndroid Build Coastguard Worker logger.warning(" - Output format: xml") 935*c33452fbSAndroid Build Coastguard Worker self.XMLreport = True 936*c33452fbSAndroid Build Coastguard Worker 937*c33452fbSAndroid Build Coastguard Worker logger.warning(" - Debug level: error") 938*c33452fbSAndroid Build Coastguard Worker self.debugLevel = logging.ERROR 939*c33452fbSAndroid Build Coastguard Worker else: 940*c33452fbSAndroid Build Coastguard Worker 941*c33452fbSAndroid Build Coastguard Worker myArgParser = argparse.ArgumentParser(description='Generate PFW report') 942*c33452fbSAndroid Build Coastguard Worker 943*c33452fbSAndroid Build Coastguard Worker myArgParser.add_argument( 944*c33452fbSAndroid Build Coastguard Worker 'domainsFile', 945*c33452fbSAndroid Build Coastguard Worker type=argparse.FileType('r'), 946*c33452fbSAndroid Build Coastguard Worker help="the PFW domain XML file" 947*c33452fbSAndroid Build Coastguard Worker ) 948*c33452fbSAndroid Build Coastguard Worker myArgParser.add_argument( 949*c33452fbSAndroid Build Coastguard Worker 'pfwlog', nargs='?', 950*c33452fbSAndroid Build Coastguard Worker type=argparse.FileType('r'), default=sys.stdin, 951*c33452fbSAndroid Build Coastguard Worker help="the PFW log file, default stdin" 952*c33452fbSAndroid Build Coastguard Worker ) 953*c33452fbSAndroid Build Coastguard Worker myArgParser.add_argument( 954*c33452fbSAndroid Build Coastguard Worker '-o', '--output', 955*c33452fbSAndroid Build Coastguard Worker dest="outputFile", 956*c33452fbSAndroid Build Coastguard Worker type=argparse.FileType('w'), default=sys.stdout, 957*c33452fbSAndroid Build Coastguard Worker help="the coverage report output file, default stdout" 958*c33452fbSAndroid Build Coastguard Worker ) 959*c33452fbSAndroid Build Coastguard Worker myArgParser.add_argument( 960*c33452fbSAndroid Build Coastguard Worker '-v', '--verbose', 961*c33452fbSAndroid Build Coastguard Worker dest="debugLevel", default=0, 962*c33452fbSAndroid Build Coastguard Worker action='count', 963*c33452fbSAndroid Build Coastguard Worker help="print debug warnings from warning (default) to debug (-vv)" 964*c33452fbSAndroid Build Coastguard Worker ) 965*c33452fbSAndroid Build Coastguard Worker 966*c33452fbSAndroid Build Coastguard Worker outputFormatGroupe = myArgParser.add_mutually_exclusive_group(required=False) 967*c33452fbSAndroid Build Coastguard Worker 968*c33452fbSAndroid Build Coastguard Worker outputFormatGroupe.add_argument( 969*c33452fbSAndroid Build Coastguard Worker '--xml', 970*c33452fbSAndroid Build Coastguard Worker dest="xmlFlag", 971*c33452fbSAndroid Build Coastguard Worker action='store_true', 972*c33452fbSAndroid Build Coastguard Worker help=" XML coverage output report" 973*c33452fbSAndroid Build Coastguard Worker ) 974*c33452fbSAndroid Build Coastguard Worker outputFormatGroupe.add_argument( 975*c33452fbSAndroid Build Coastguard Worker '--raw', 976*c33452fbSAndroid Build Coastguard Worker dest="rawFlag", 977*c33452fbSAndroid Build Coastguard Worker action='store_true', 978*c33452fbSAndroid Build Coastguard Worker help="raw coverage output report" 979*c33452fbSAndroid Build Coastguard Worker ) 980*c33452fbSAndroid Build Coastguard Worker 981*c33452fbSAndroid Build Coastguard Worker myArgParser.add_argument( 982*c33452fbSAndroid Build Coastguard Worker '--ignore-unknown-criterion', 983*c33452fbSAndroid Build Coastguard Worker dest="unknwonCriterionFlag", 984*c33452fbSAndroid Build Coastguard Worker action='store_true', 985*c33452fbSAndroid Build Coastguard Worker help="ignore unknown criterion" 986*c33452fbSAndroid Build Coastguard Worker ) 987*c33452fbSAndroid Build Coastguard Worker 988*c33452fbSAndroid Build Coastguard Worker myArgParser.add_argument( 989*c33452fbSAndroid Build Coastguard Worker '--ignore-incoherent-criterion-state', 990*c33452fbSAndroid Build Coastguard Worker dest="incoherentCriterionFlag", 991*c33452fbSAndroid Build Coastguard Worker action='store_true', 992*c33452fbSAndroid Build Coastguard Worker help="ignore criterion transition to incoherent state" 993*c33452fbSAndroid Build Coastguard Worker ) 994*c33452fbSAndroid Build Coastguard Worker 995*c33452fbSAndroid Build Coastguard Worker myArgParser.add_argument( 996*c33452fbSAndroid Build Coastguard Worker '--ignore-ineligible-configuration-application', 997*c33452fbSAndroid Build Coastguard Worker dest="ineligibleConfigurationApplicationFlag", 998*c33452fbSAndroid Build Coastguard Worker action='store_true', 999*c33452fbSAndroid Build Coastguard Worker help="ignore application of configuration with a false rule " 1000*c33452fbSAndroid Build Coastguard Worker "(not applicable configuration)" 1001*c33452fbSAndroid Build Coastguard Worker ) 1002*c33452fbSAndroid Build Coastguard Worker 1003*c33452fbSAndroid Build Coastguard Worker # Process command line arguments 1004*c33452fbSAndroid Build Coastguard Worker options = myArgParser.parse_args() 1005*c33452fbSAndroid Build Coastguard Worker 1006*c33452fbSAndroid Build Coastguard Worker # Mapping to attributes 1007*c33452fbSAndroid Build Coastguard Worker self.inputFile = options.pfwlog 1008*c33452fbSAndroid Build Coastguard Worker self.outputFile = options.outputFile 1009*c33452fbSAndroid Build Coastguard Worker self.domainsFile = options.domainsFile 1010*c33452fbSAndroid Build Coastguard Worker 1011*c33452fbSAndroid Build Coastguard Worker # Output report in xml if flag not set 1012*c33452fbSAndroid Build Coastguard Worker self.XMLreport = not options.rawFlag 1013*c33452fbSAndroid Build Coastguard Worker 1014*c33452fbSAndroid Build Coastguard Worker # Setting logger level 1015*c33452fbSAndroid Build Coastguard Worker levelCapped = min(options.debugLevel, len(self.levelTranslate) - 1) 1016*c33452fbSAndroid Build Coastguard Worker self.debugLevel = self.levelTranslate[levelCapped] 1017*c33452fbSAndroid Build Coastguard Worker 1018*c33452fbSAndroid Build Coastguard Worker # Setting ignore options 1019*c33452fbSAndroid Build Coastguard Worker errorToIgnore = [] 1020*c33452fbSAndroid Build Coastguard Worker if options.ineligibleConfigurationApplicationFlag: 1021*c33452fbSAndroid Build Coastguard Worker errorToIgnore.append(Configuration.IneligibleConfigurationAppliedError) 1022*c33452fbSAndroid Build Coastguard Worker 1023*c33452fbSAndroid Build Coastguard Worker if options.incoherentCriterionFlag: 1024*c33452fbSAndroid Build Coastguard Worker errorToIgnore.append(Criterion.ChangeRequestToNonAccessibleState) 1025*c33452fbSAndroid Build Coastguard Worker 1026*c33452fbSAndroid Build Coastguard Worker if options.unknwonCriterionFlag: 1027*c33452fbSAndroid Build Coastguard Worker errorToIgnore.append(ParsePFWlog.ChangeRequestOnUnknownCriterion) 1028*c33452fbSAndroid Build Coastguard Worker 1029*c33452fbSAndroid Build Coastguard Worker self.errorToIgnore = tuple(errorToIgnore) 1030*c33452fbSAndroid Build Coastguard Worker 1031*c33452fbSAndroid Build Coastguard Worker 1032*c33452fbSAndroid Build Coastguard Worker 1033*c33452fbSAndroid Build Coastguard Workerdef main(): 1034*c33452fbSAndroid Build Coastguard Worker 1035*c33452fbSAndroid Build Coastguard Worker errorDuringLogParsing = -1 1036*c33452fbSAndroid Build Coastguard Worker errorDuringArgumentParsing = 1 1037*c33452fbSAndroid Build Coastguard Worker 1038*c33452fbSAndroid Build Coastguard Worker try: 1039*c33452fbSAndroid Build Coastguard Worker commandLineArguments = ArgumentParser() 1040*c33452fbSAndroid Build Coastguard Worker except LookupError as ex: 1041*c33452fbSAndroid Build Coastguard Worker logger.error("Error during argument parsing") 1042*c33452fbSAndroid Build Coastguard Worker logger.debug(str(ex)) 1043*c33452fbSAndroid Build Coastguard Worker sys.exit(errorDuringArgumentParsing) 1044*c33452fbSAndroid Build Coastguard Worker 1045*c33452fbSAndroid Build Coastguard Worker # Setting logger level 1046*c33452fbSAndroid Build Coastguard Worker logger.setLevel(commandLineArguments.debugLevel) 1047*c33452fbSAndroid Build Coastguard Worker logger.info("Log level set to: %s" % 1048*c33452fbSAndroid Build Coastguard Worker logging.getLevelName(commandLineArguments.debugLevel)) 1049*c33452fbSAndroid Build Coastguard Worker 1050*c33452fbSAndroid Build Coastguard Worker # Create tree from XML 1051*c33452fbSAndroid Build Coastguard Worker dom = xml.dom.minidom.parse(commandLineArguments.domainsFile) 1052*c33452fbSAndroid Build Coastguard Worker 1053*c33452fbSAndroid Build Coastguard Worker # Create element tree 1054*c33452fbSAndroid Build Coastguard Worker root = Root("DomainCoverage", dom) 1055*c33452fbSAndroid Build Coastguard Worker 1056*c33452fbSAndroid Build Coastguard Worker # Parse PFW events 1057*c33452fbSAndroid Build Coastguard Worker parser = ParsePFWlog(root.domains, root.criteria, commandLineArguments.errorToIgnore) 1058*c33452fbSAndroid Build Coastguard Worker 1059*c33452fbSAndroid Build Coastguard Worker try: 1060*c33452fbSAndroid Build Coastguard Worker parser.parsePFWlog(commandLineArguments.inputFile.readlines()) 1061*c33452fbSAndroid Build Coastguard Worker except CustomError as ex: 1062*c33452fbSAndroid Build Coastguard Worker logger.fatal("Error during parsing log file %s: %s" % 1063*c33452fbSAndroid Build Coastguard Worker (commandLineArguments.inputFile, ex)) 1064*c33452fbSAndroid Build Coastguard Worker sys.exit(errorDuringLogParsing) 1065*c33452fbSAndroid Build Coastguard Worker 1066*c33452fbSAndroid Build Coastguard Worker # Output report 1067*c33452fbSAndroid Build Coastguard Worker outputFile = commandLineArguments.outputFile 1068*c33452fbSAndroid Build Coastguard Worker 1069*c33452fbSAndroid Build Coastguard Worker if not commandLineArguments.XMLreport: 1070*c33452fbSAndroid Build Coastguard Worker outputFile.write("%s\n" % root.dump(withCoverage=True, withNbUse=True)) 1071*c33452fbSAndroid Build Coastguard Worker else: 1072*c33452fbSAndroid Build Coastguard Worker outputFile.write(root.exportToXML().toprettyxml()) 1073*c33452fbSAndroid Build Coastguard Worker 1074*c33452fbSAndroid Build Coastguard Worker 1075*c33452fbSAndroid Build Coastguard Workerif __name__ == "__main__": 1076*c33452fbSAndroid Build Coastguard Worker """ Execute main if the python interpreter is running this module as the main program """ 1077*c33452fbSAndroid Build Coastguard Worker main() 1078*c33452fbSAndroid Build Coastguard Worker 1079