1326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard#!/usr/bin/env python3 2326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 3b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# Copyright (c) 2011-2014, Intel Corporation 4b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# All rights reserved. 5fe753d4ba5d5bf3df7b7f4876280b74fc8647285Kevin Rocard# 6b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# Redistribution and use in source and binary forms, with or without modification, 7b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# are permitted provided that the following conditions are met: 8fe753d4ba5d5bf3df7b7f4876280b74fc8647285Kevin Rocard# 9b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# 1. Redistributions of source code must retain the above copyright notice, this 10b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# list of conditions and the following disclaimer. 11b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# 12b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# 2. Redistributions in binary form must reproduce the above copyright notice, 13b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# this list of conditions and the following disclaimer in the documentation and/or 14b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# other materials provided with the distribution. 15b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# 16b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# 3. Neither the name of the copyright holder nor the names of its contributors 17b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# may be used to endorse or promote products derived from this software without 18b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# specific prior written permission. 19b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# 20b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 24b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30b76c9d6de717a9a1cfd94e7a8eca7ee4a2035cd7David Wagner 31fe753d4ba5d5bf3df7b7f4876280b74fc8647285Kevin Rocard 32326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard""" 33326e39e42a801bff4b61655ebc0e3ff759c208ffKevin RocardGenerate a coverage report by parsing parameter framework log. 34326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 35326e39e42a801bff4b61655ebc0e3ff759c208ffKevin RocardThe coverage report contains the: 36326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard - domain 37326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard - configuration 38326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard - rule 39326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard - criterion 40326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardbasic coverage statistics. 41326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard""" 42326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 43326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardimport xml.dom.minidom 44326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardimport sys 45326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardimport re 46326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardimport logging 47326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 48326e39e42a801bff4b61655ebc0e3ff759c208ffKevin RocardFORMAT = '%(levelname)s: %(message)s' 49326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardlogging.basicConfig(stream=sys.stderr, level=logging.WARNING, format=FORMAT) 50326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardlogger = logging.getLogger("Coverage") 51326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 523aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocardclass CustomError(Exception): 53804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard pass 543aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 553aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocardclass ChildError(CustomError): 56804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, parent, child): 57804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.parent = parent 58804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.child = child 593aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 603aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocardclass ChildNotFoundError(ChildError): 61804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __str__(self): 620bb508d358ebe25d61122bde9905db6661591ba0Kevin Rocard return 'Unable to find the child "%s" in "%s"' % (self.child, self.parent) 633aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 643aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocardclass DuplicatedChildError(ChildError): 65804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __str__(self): 660bb508d358ebe25d61122bde9905db6661591ba0Kevin Rocard return 'Add existing child "%s" in "%s".' % (self.child, self.parent) 67326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 68326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Element(): 69804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Root class for all coverage elements""" 70804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "element" 71326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 72804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, name): 73326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 74804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.parent = None 75804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.children = [] 76326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 77804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.nbUse = 0 78326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 79804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.name = name 80326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 81804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("New element") 82326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 83326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 84804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __str__(self): 85804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return "%s (%s)" % (self.name, self.tag) 86326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 87804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __eq__(self, compared): 88804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return (self.name == compared.name) and (self.children == compared.children) 89326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 90804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def getName(self, default=""): 91804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.name or default 92326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 93804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def hasChildren(self): 94804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return bool(self.children) 95326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 96804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def getChildren(self): 97804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.children 98326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 99804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getDescendants(self): 100804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children: 101804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield child 102804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for descendant in child._getDescendants() : 103804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield descendant 104326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 105804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def getChildFromName(self, childName): 106326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 107804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children : 108326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 109804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if child.getName() == childName : 110804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return child 111326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1120bb508d358ebe25d61122bde9905db6661591ba0Kevin Rocard self.debug('Child "%s" not found' % childName, logging.ERROR) 113326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 114804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Child list :") 115326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 116804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children : 117804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug(" - %s" % child) 118326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 119804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard raise ChildNotFoundError(self, childName) 120326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 121326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 122804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def addChild(self, child): 123804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("new child: " + child.name) 124804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.children.append(child) 125804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard child._adoptedBy(self) 126326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 127804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _adoptedBy(self, parent): 128804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard assert(not self.parent) 129804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.parent = parent 130326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 131804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getElementNames(self, elementList): 132804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return (substate.name for substate in elementList) 133326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 134804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _description(self, withCoverage, withNbUse): 135804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard description = self.name 136326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 137804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if withNbUse or withCoverage : 138804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard description += " has been used " + str(self.nbUse) + " time" 139326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 140804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if withCoverage : 141804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard description += self._coverageFormating(self._getCoverage()) 142326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 143804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return description 144326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 145326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 146804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getCoverage(self): 147804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Return the coverage of the element between 0 and 1 148326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 149804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard If the element has no coverage dependency (usually child) return 0 or 1. 150804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard otherwise the element coverage is the dependency coverage average""" 151804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard coverageDependanceElements = list(self._getCoverageDependanceElements()) 152326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 153804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard nbcoverageDependence = len(coverageDependanceElements) 154326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 155804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if nbcoverageDependence == 0: 156804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if self.nbUse == 0: 157804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return 0 158804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else: 159804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return 1 160326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 161804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard coverageDependenceValues = (depElement._getCoverage() 162804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for depElement in coverageDependanceElements) 163326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 164804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return sum(coverageDependenceValues) / nbcoverageDependence 165326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 166804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getCoverageDependanceElements(self): 167804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.children 168326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 169804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _coverageFormating(self, coverage): 170804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # If no coverage provided 171804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not coverage : 172804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return "" 173326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 174804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Calculate coverage 175804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return " (%s coverage)" % self._number2percent(coverage) 176326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 177804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard @staticmethod 178804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _number2percent(number): 179804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Format a number to a integer % string 180326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 181804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard example: _number2percent(0.6666) -> "67%" 182804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """ 183804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return "{0:.0f}%".format(100 * number) 184326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 185326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 186804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _dumpDescription(self, withCoverage, withNbUse): 187326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 188804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("yelding description") 189804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield RankedLine(self._description(withCoverage, withNbUse), lineSuffix="") 190326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 191804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for dumped in self._dumpPropagate(withCoverage, withNbUse) : 192804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield dumped 193326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 194804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _dumpPropagate(self, withCoverage, withNbUse): 195326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 196804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children : 197804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for dumpedDescription in child._dumpDescription(withCoverage, withNbUse) : 198804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield dumpedDescription.increasedRank() 199326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 200326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 201804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def dump(self, withCoverage=False, withNbUse=True): 202326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 203804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return "\n".join( 204804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard str(dumpedDescription) for dumpedDescription in 205804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._dumpDescription(withCoverage, withNbUse)) 206326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 207794fea64ed11b6c2b2604c3a0daa374c885f09d6Kevin Rocard def exportToXML(self, document, domElement=None): 208804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if domElement == None: 209794fea64ed11b6c2b2604c3a0daa374c885f09d6Kevin Rocard domElement = document.createElement(self.tag) 21002726ec37a9686572f825520a04700061ffe5d06Kevin Rocard 211804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._XMLaddAttributes(domElement) 212326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 213804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children : 214794fea64ed11b6c2b2604c3a0daa374c885f09d6Kevin Rocard domElement.appendChild(child.exportToXML(document)) 215326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 216804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return domElement 217326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 218804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _XMLaddAttributes(self, domElement): 219804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard attributes = self._getXMLAttributes() 220326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 221804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard coverage = self._getCoverage() 222804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if coverage != None : 223804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard attributes["Coverage"] = self._number2percent(coverage) 224326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 225804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for key, value in attributes.items(): 226804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard domElement.setAttribute(key, value) 227326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 228804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getXMLAttributes(self): 229804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return { 230804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "Name": self.name, 231804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "NbUse": str(self.nbUse) 232804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard } 233326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 234804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _incNbUse(self): 235804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.nbUse += 1 236326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 237804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def childUsed(self, child): 238804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._incNbUse() 239804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Propagate to parent 240804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._tellParentThatChildUsed() 241326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 242804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _tellParentThatChildUsed(self): 243804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if self.parent : 244804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.parent.childUsed(self) 245326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 246326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 247804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def parentUsed(self): 248804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._incNbUse() 249804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Propagate to children 250804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children : 251804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard child.parentUsed() 252326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 253804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def hasBeenUsed(self): 254804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.nbUse > 0 255326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 256804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def operationOnChild(self, path, operation): 257326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 258804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if path: 259804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self._operationPropagate(path, operation) 260804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 261804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("operating on self") 262804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return operation(self) 263326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 264804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _operationPropagate(self, path, operation): 265326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 266804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childName = path.pop(0) 267804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard child = self.getChildFromName(childName) 268326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 269804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return child.operationOnChild(path, operation) 270326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 271326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 272326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 273804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def debug(self, stringOrFunction, level=logging.DEBUG): 274804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Print a debug line on stderr in tree form 275326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 276804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard If the debug line is expensive to generate, provide callable 277804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard object, it will be called if log is enable for this level. 278804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard This callable object should return the logline string. 279804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """ 280804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if logger.isEnabledFor(level): 281326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 282804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # TODO: use buildin callable if python >= 3.2 283804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if hasattr(stringOrFunction, "__call__"): 284804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard string = stringOrFunction() 285804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else: 286804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard string = stringOrFunction 287326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 288804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard rankedLine = DebugRankedLine("%s: %s" % (self, string)) 289804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._logDebug(rankedLine, level) 290326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 291804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _logDebug(self, rankedLine, level): 292326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 293804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if self.parent: 294804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.parent._logDebug(rankedLine.increasedRank(), level) 295804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 296804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.log(level, str(rankedLine)) 297326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 298326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 299326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 300326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 301326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass FromDomElement(Element): 302804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, DomElement): 303804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._initFromDom(DomElement) 304804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().__init__(self.name) 305326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 306326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 307804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _initFromDom(self, DomElement): 308804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.name = DomElement.getAttribute("Name") 309326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 310326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 311326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 312326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass DomElementLocation(): 313804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, classConstructor, path=None): 314804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.classConstructor = classConstructor 315804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if path : 316804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.path = path 317804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 318804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.path = [] 319326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 320804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.path.append(classConstructor.tag) 321326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 322326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 323326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass DomPopulatedElement(Element): 324804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Default child populate 325326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 326804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard Look for each dom element with tag specified in self.tag 327804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard and instantiate it with the dom element 328804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """ 329804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childClasses = [] 330326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 331804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def populate(self, dom): 332326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 333804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for childDomElementLocation in self.childClasses : 334326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 335804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Looking for child %s in path %s" % ( 336804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childDomElementLocation.path[-1], childDomElementLocation.path)) 337326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 338804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for childDomElement in self._findChildFromTagPath(dom, childDomElementLocation.path) : 339326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 340804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childElement = childDomElementLocation.classConstructor(childDomElement) 341804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.addChild(childElement) 342326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 343804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childElement.populate(childDomElement) 344326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 345804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _findChildFromTagPath(self, dom, path): 346804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not path : 347804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield dom 348804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 349804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Copy list 350804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard path = list(path) 351326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 352804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = path.pop(0) 353326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 354804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Find element with tag 355804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Going to find elements with tag %s in %s" % (tag, dom)) 356804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug(lambda: "Nb of solutions: %s" % len(dom.getElementsByTagName(tag))) 357326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 358804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for elementByTag in dom.getElementsByTagName(tag) : 359326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 360804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Found element: %s" % elementByTag) 361326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 362804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # If the same tag is found 363804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if elementByTag in dom.childNodes : 364326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 365804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Yield next level 366804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for element in self._findChildFromTagPath(elementByTag, path) : 367804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield element 368326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 369326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 370326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Rule(Element): 371326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 372804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def usedIfApplicable(self, criteria): 373804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childApplicability = (child.usedIfApplicable(criteria) 374804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children) 375326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 376804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard isApplicable = self._isApplicable(criteria, childApplicability) 377326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 378804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if isApplicable : 379804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._incNbUse() 380326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 381804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Rule applicability: %s" % isApplicable) 382804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard assert(isApplicable == True or isApplicable == False) 383326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 384804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return isApplicable 385326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 386326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 387804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _isApplicable(self, criteria, childApplicability): 388804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Return the rule applicability depending on children applicability. 389cf031996ede8428065b6d7648e34720a1874f5faKevin Rocard 390804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard If at least one child is applicable, return true""" 391804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Lazy evaluation as in the PFW 392804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return all(childApplicability) 393326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 394326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 395326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass CriterionRule(FromDomElement, DomPopulatedElement, Rule): 396804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "SelectionCriterionRule" 397804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childClasses = [] 398804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard isApplicableOperations = { 399804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "Includes" : lambda criterion, value: criterion.stateIncludes(value), 400804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "Excludes" : lambda criterion, value: not criterion.stateIncludes(value), 401804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "Is" : lambda criterion, value: criterion.stateIs(value), 402804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "IsNot" : lambda criterion, value: not criterion.stateIs(value) 403804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard } 404326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 405804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _initFromDom(self, DomElement): 406804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.selectionCriterion = DomElement.getAttribute("SelectionCriterion") 407804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.matchesWhen = DomElement.getAttribute("MatchesWhen") 408804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.value = DomElement.getAttribute("Value") 409804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.name = "%s %s %s" % (self.selectionCriterion, self.matchesWhen, self.value) 410326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 411804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard applicableOperationWithoutValue = self.isApplicableOperations[self.matchesWhen] 412804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.isApplicableOperation = lambda criterion: applicableOperationWithoutValue(criterion, self.value) 413326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 414804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _isApplicable(self, criteria, childApplicability): 415326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 416804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return criteria.operationOnChild([self.selectionCriterion], 417804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.isApplicableOperation) 418326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 419326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 420326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass CompoundRule(FromDomElement, DomPopulatedElement, Rule): 421804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """CompoundRule can be of type ALL or ANY""" 422804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "CompoundRule" 423804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Declare childClasses but define it at first class instantiation 424804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childClasses = None 425326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 426804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, dom): 427804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Define childClasses at first class instantiation 428804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if self.childClasses == None : 429804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.childClasses = [DomElementLocation(CriterionRule), 430804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard DomElementLocation(CompoundRule)] 431804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().__init__(dom) 432326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 433804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _initFromDom(self, DomElement): 434326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 435804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard type = DomElement.getAttribute("Type") 436804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.ofTypeAll = {"All" : True, "Any" : False}[type] 437804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.name = type 438326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 439804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _isApplicable(self, criteria, childApplicability): 440804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if self.ofTypeAll : 441804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard applicability = super()._isApplicable(criteria, childApplicability) 442804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else: 443804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Lazy evaluation as in the PFW 444804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard applicability = any(childApplicability) 445326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 446804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return applicability 447326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 448326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass RootRule(DomPopulatedElement, Rule): 449804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "RootRule" 450804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childClasses = [DomElementLocation(CompoundRule)] 451326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 452804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def populate(self, dom): 453804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().populate(dom) 454804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Children: %s" % self.children) 455804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # A configuration can only have one or no rule 456804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard assert(len(self.children) <= 1) 457326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 458804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getCoverageDependanceElements(self): 459804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self._getDescendants() 460326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 461326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 462326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass CriteronStates(Element): 463804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Root of configuration application criterion state""" 464804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "CriterionStates" 465326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 466804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def parentUsed(self, criteria): 467804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Add criteria to child if not exist, if exist increase it's nbUse""" 468804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._incNbUse() 469326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 470804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard matches = [child for child in self.children if child == criteria] 471326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 472804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard assert(len(matches) <= 1) 473326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 474804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if matches : 475804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Criteria state has already been encounter") 476804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard currentcriteria = matches[0] 477804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 478804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Criteria state has never been encounter, saving it") 479804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard currentcriteria = criteria 480804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.addChild(criteria) 481326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 482804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard currentcriteria.parentUsed() 483326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 484326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 485326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 486326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Configuration(FromDomElement, DomPopulatedElement): 487804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "Configuration" 488804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childClasses = [] 489326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 490804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard class IneligibleConfigurationAppliedError(CustomError): 49197dbd35c75ee252a674aff3d66293d55fc0b35a5Kevin Rocard 492804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, configuration, criteria): 493804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.configuration = configuration 494804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteria = criteria 49597dbd35c75ee252a674aff3d66293d55fc0b35a5Kevin Rocard 496804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __str__(self): 49797dbd35c75ee252a674aff3d66293d55fc0b35a5Kevin Rocard 498804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return ("Applying ineligible %s, " 499804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "rule:\n%s\n" 500804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "Criteria current state:\n%s" % ( 501804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.configuration, 502804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.configuration.rootRule.dump(withCoverage=False, withNbUse=False), 503804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteria.dump(withCoverage=False, withNbUse=False) 504804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard )) 50597dbd35c75ee252a674aff3d66293d55fc0b35a5Kevin Rocard 506804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, DomElement): 507804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().__init__(DomElement) 508326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 509804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.rootRule = RootRule("RootRule") 510804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.addChild(self.rootRule) 511326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 512804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteronStates = CriteronStates("CriterionStates") 513804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.addChild(self.criteronStates) 514326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 515804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def populate(self, dom): 516804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Delegate to rootRule 517804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.rootRule.populate(dom) 518326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 519804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getCoverage(self): 520804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Delegate to rootRule 521804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.rootRule._getCoverage() 522326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 523804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def used(self, criteria): 524326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 525804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._incNbUse() 526326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 527804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Propagate use to parents 528804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._tellParentThatChildUsed() 529326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 530804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Propagate to criterion coverage 531804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteronStates.parentUsed(criteria.export()) 532326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 533804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Propagate to rules 534804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not self.rootRule.usedIfApplicable(criteria) : 535326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 536804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Applied but rule does not match current " 5373aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard "criteria (parent: %s) " % self.parent.name, 538804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logging.ERROR) 539326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 540804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard raise self.IneligibleConfigurationAppliedError(self, criteria.export()) 541326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 542804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _dumpPropagate(self, withCoverage, withNbUse): 543804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Going to ask %s for description" % self.rootRule) 544804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for dumpedDescription in self.rootRule._dumpDescription( 545804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard withCoverage=withCoverage, 546804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard withNbUse=withNbUse) : 547804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield dumpedDescription.increasedRank() 548326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 549804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Going to ask %s for description" % self.criteronStates) 550804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for dumpedDescription in self.criteronStates._dumpDescription( 551804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard withCoverage=False, 552804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard withNbUse=withNbUse) : 553804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard yield dumpedDescription.increasedRank() 554326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 555326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 556326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Domain(FromDomElement, DomPopulatedElement): 557804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "ConfigurableDomain" 558804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childClasses = [DomElementLocation(Configuration, ["Configurations"])] 559326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 560326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 561326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Domains(DomPopulatedElement): 562804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "Domains" 563804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard childClasses = [DomElementLocation(Domain, ["ConfigurableDomains"])] 564326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 565326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 566326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass RankedLine(): 567804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, string, 568804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard stringPrefix="|-- ", 569804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard rankString="| ", 570804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard linePrefix="", 571804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard lineSuffix="\n"): 572804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.string = string 573804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.rank = 0 574804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.stringPrefix = stringPrefix 575804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.rankString = rankString 576804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.linePrefix = linePrefix 577804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.lineSuffix = lineSuffix 578804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 579804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def increasedRank(self): 580804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.rank += 1 581804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self 582804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 583804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __str__(self): 584804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.linePrefix + \ 585804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.rank * self.rankString + \ 586804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.stringPrefix + \ 587804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.string + \ 588804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.lineSuffix 589326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 590326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass DebugRankedLine(RankedLine): 591326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 592804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, string, lineSuffix=""): 593804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().__init__(string, 594804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard stringPrefix="", 595804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard rankString=" ", 596804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard linePrefix="", 597804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard lineSuffix=lineSuffix) 598326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 599326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 600326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass CriterionState(Element): 601804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "CriterionState" 602804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def used(self): 603804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._incNbUse() 604326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 605326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 606326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Criterion(Element): 607804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "Criterion" 608804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard inclusivenessTranslate = {True: "Inclusive", False: "Exclusive"} 6093aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 610804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard class ChangeRequestToNonAccessibleState(CustomError): 611804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, requestedState, detail): 612804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.requestedState = requestedState 613804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.detail = detail 614556538e2bda03b54bdd82c5813a5286e90a39f67Kevin Rocard 615804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __str__(self): 616804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return ("Change request to non accessible state %s. Detail: %s" % 617804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard (self.requestedState, self.detail)) 618556538e2bda03b54bdd82c5813a5286e90a39f67Kevin Rocard 619804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, name, isInclusif, 620804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard stateNamesList, currentStateNamesList, 621804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ignoreIntegrity=False): 622804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().__init__(name) 623804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.isInclusif = isInclusif 624326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 625804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for state in stateNamesList : 626804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.addChild(CriterionState(state)) 627326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 628804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.currentState = [] 629804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.initStateNamesList = list(currentStateNamesList) 630804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.changeState(self.initStateNamesList, ignoreIntegrity) 631326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 632804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def reset(self): 633804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Set current state as provided at initialisation 634804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.changeState(self.initStateNamesList, ignoreIntegrity=True) 635326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 636804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def changeState(self, subStateNames, ignoreIntegrity=False): 637804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Changing state from: %s to: %s" % ( 638804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard list(self._getElementNames(self.currentState)), 639804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard subStateNames)) 640326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 641804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not ignoreIntegrity and not self.isIntegre(subStateNames): 642804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard raise self.ChangeRequestToNonAccessibleState(subStateNames, 643804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "An exclusive criterion must have a non empty state") 644326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 645804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard newCurrentState = [] 646804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for subStateName in subStateNames : 647804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard subState = self.getChildFromName(subStateName) 648804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard subState.used() 649804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard newCurrentState.append(subState) 650326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 651804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.currentState = newCurrentState 652326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 653804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._incNbUse() 654804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self._tellParentThatChildUsed() 655326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 656804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def isIntegre(self, subStateNames): 657804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.isInclusif or len(subStateNames) == 1 658556538e2bda03b54bdd82c5813a5286e90a39f67Kevin Rocard 659804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def childUsed(self, child): 660804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.currentState = child 661804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().childUsed(child) 662556538e2bda03b54bdd82c5813a5286e90a39f67Kevin Rocard 663804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def export(self): 664804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard subStateNames = self._getElementNames(self.currentState) 665804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return Criterion(self.name, self.isInclusif, subStateNames, subStateNames, 666804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ignoreIntegrity=True) 667326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 668804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def stateIncludes(self, subStateName): 669804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard subStateCurrentNames = list(self._getElementNames(self.currentState)) 670326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 671804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Testing if %s is included in %s" % (subStateName, subStateCurrentNames)) 672326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 673804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard isIncluded = subStateName in subStateCurrentNames 674804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("IsIncluded: %s" % isIncluded) 675326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 676804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return isIncluded 677326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 678326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 679804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def stateIs(self, subStateNames): 680804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if len(self.currentState) != 1 : 681804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return False 682804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 683804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return self.stateIncludes(subStateNames) 684326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 685804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _getXMLAttributes(self): 686804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard attributes = super()._getXMLAttributes() 687804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard attributes["Type"] = self.inclusivenessTranslate[self.isInclusif] 688804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return attributes 6893aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 690326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 691326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Criteria(Element): 692804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "Criteria" 693326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 694804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard class DuplicatedCriterionError(DuplicatedChildError): 695804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard pass 696d077c557e360615a67d97ee249260a1ef7919f09Kevin Rocard 697804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def export(self): 698804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debug("Exporting criteria") 699804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard assert(self.children) 700326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 701804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard exported = Criteria(self.name) 702804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for child in self.children : 703804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard exported.addChild(child.export()) 704804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return exported 705326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 706804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def addChild(self, child): 707804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if child in self.children: 708804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard raise self.DuplicatedCriterionError(self, child) 709804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().addChild(child) 7103aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 7113aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocardclass ConfigAppliedWithoutCriteriaError(CustomError): 712804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, configurationName, domainName): 713804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.configurationName = configurationName 714804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.domainName = domainName 715804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __str__(self): 716804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return ('Applying configuration "%s" from domain "%s" before declaring criteria' % 717804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard (self.configurationName, self.domainName)) 718326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 719326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass ParsePFWlog(): 720804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard MATCH = "match" 721804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ACTION = "action" 722804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 723ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner class ChangeRequestOnUnknownCriterion(CustomError): 724ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner def __init__(self, criterion): 725ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner self.criterion = criterion 726ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner 727ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner def __str__(self): 728ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner return ("Change request on an unknown criterion %s." % 729ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner self.criterion) 730ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner 731804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, domains, criteria, ErrorsToIgnore=()): 732804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 733804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.domains = domains; 734804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteria = criteria; 735804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.ErrorsToIgnore = ErrorsToIgnore 736326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 737804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard configApplicationRegext = r""".*Applying configuration "(.*)" from domain "([^"]*)""" 738804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard matchConfigApplicationLine = re.compile(configApplicationRegext).match 739804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 740804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionCreationRegext = ", ".join([ 741804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard r""".*Criterion name: (.*)""", 742804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard r"""type kind: (.*)""", 743804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard r"""current state: (.*)""", 744804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard r"""states: {(.*)}""" 745804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ]) 746804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard matchCriterionCreationLine = re.compile(criterionCreationRegext).match 747326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 748804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard changingCriterionRegext = r""".*Selection criterion changed event: Criterion name: (.*), current state: ([^\n\r]*)""" 749804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard matchChangingCriterionLine = re.compile(changingCriterionRegext).match 750326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 751804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.lineLogTypes = [ 752804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard { 753804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.MATCH: matchConfigApplicationLine, 754804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.ACTION: self._configApplication 755804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard }, { 756804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.MATCH: matchCriterionCreationLine, 757804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.ACTION: self._criterionCreation 758804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard }, { 759804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.MATCH: matchChangingCriterionLine, 760804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.ACTION: self._changingCriterion 761804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard } 762804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ] 763326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 764804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard @staticmethod 765804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _formatCriterionList(liststring, separator): 766804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard list = liststring.split(separator) 767804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if len(list) == 1 and list[0] == "<none>": 768804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard list = [] 769804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return list 770804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 771804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _criterionCreation(self, matchCriterionCreation): 772804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Unpack 773804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionName, criterionType, currentCriterionStates, criterionStates = matchCriterionCreation.group(1, 2, 3, 4) 774326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 775804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionStateList = self._formatCriterionList(criterionStates, ", ") 776326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 777804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionIsInclusif = {"exclusive" : False, "inclusive" : True}[criterionType] 778326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 779804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard currentcriterionStateList = self._formatCriterionList(currentCriterionStates, "|") 780326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 781804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.info("Creating criterion: " + criterionName + 782804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard " (" + criterionType + ") " + 783804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard " with current state: " + str(currentcriterionStateList) + 784804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ", possible states:" + str(criterionStateList)) 785326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 786804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard try: 787804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteria.addChild(Criterion( 788804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionName, 789804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionIsInclusif, 790804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionStateList, 791804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard currentcriterionStateList 792804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard )) 793804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard except self.criteria.DuplicatedCriterionError as ex: 794804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.debug(ex) 795804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.warning("Reseting criterion %s. Did you reset the PFW ?" % criterionName) 796804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteria.operationOnChild( 797804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard [criterionName], 798804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard lambda criterion: criterion.reset() 799804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 800ea87422e14735633cb8e28de114a18e22eaa82fbKevin Rocard 801ea87422e14735633cb8e28de114a18e22eaa82fbKevin Rocard 802326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 803804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _changingCriterion(self, matchChangingCriterion): 804804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Unpack 805804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard criterionName, newCriterionSubStateNames = matchChangingCriterion.group(1, 2) 806326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 807804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard newCriterionState = self._formatCriterionList(newCriterionSubStateNames, "|") 808326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 809804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.info("Changing criterion %s to %s" % (criterionName , newCriterionState)) 8103aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 811804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard path = [criterionName] 812804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard changeCriterionOperation = lambda criterion : criterion.changeState(newCriterionState) 813ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner try: 814ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner self.criteria.operationOnChild(path, changeCriterionOperation) 815ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner except ChildNotFoundError: 816ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner raise self.ChangeRequestOnUnknownCriterion(criterionName) 817326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 818804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _configApplication(self, matchConfig): 819804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Unpack 820804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard configurationName, domainName = matchConfig.group(1, 2) 8213aa0db4be952157c2842b91a1606cc0edac9e63dKevin Rocard 822804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Check that at least one criterion exist 823804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not self.criteria.hasChildren() : 824804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.error("Applying configuration before declaring criteria") 825804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.info("Is the log starting at PFW boot ?") 826804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard raise ConfigAppliedWithoutCriteriaError(configurationName, domainName) 827326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 828804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Change criterion state 829804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard path = [domainName, configurationName] 830804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard usedOperation = lambda element : element.used(self.criteria) 831326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 832804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.info("Applying configuration %s from domain %s" % ( 833804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard configurationName, domainName)) 834804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 835804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.domains.operationOnChild(path, usedOperation) 836326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 837326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 838804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def _digest(self, lineLogType, lineLog): 8399050c81c8f9a63aa95e7230705e00585bd0ecec5Kevin Rocard 840804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard match = lineLogType[self.MATCH](lineLog) 841804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if match : 842804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard lineLogType[self.ACTION](match) 843804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return True 844804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard return False 845326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 8469050c81c8f9a63aa95e7230705e00585bd0ecec5Kevin Rocard 847804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def parsePFWlog(self, lines): 8486bd9fcf524e77a1ca7469d6d91c58afd242d388aKevin Rocard for lineNb, lineLog in enumerate(lines, 1): # line number starts at 1 849326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 850804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.debug("Parsing line :%s" % lineLog.rstrip()) 851326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 852804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard digested = (self._digest(lineLogType, lineLog) 853804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard for lineLogType in self.lineLogTypes) 854326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 855804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard try: 856804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard success = any(digested) 8579050c81c8f9a63aa95e7230705e00585bd0ecec5Kevin Rocard 858804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Catch some exception in order to print the current parsing line, 859804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # then raise the exception again if not continue of error 860804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard except CustomError as ex: 861804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.error('Error raised while parsing line %s: "%s"' % 862804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard (lineNb, repr(lineLog))) 8639050c81c8f9a63aa95e7230705e00585bd0ecec5Kevin Rocard 864804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # If exception is a subclass of ErrorsToIgnore, log it and continue 865804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # otherwise raise it again. 866804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not issubclass(type(ex), self.ErrorsToIgnore): 867804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard raise ex 868804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else: 869804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.error('Ignoring exception:"%s", ' 870804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 'can not guarantee database integrity' % ex) 871804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else: 872804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not success: 873804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.debug("Line does not match, dropped") 874326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 875326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 876326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass Root(Element): 877804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard tag = "CoverageReport" 878804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self, name, dom): 879804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard super().__init__(name) 880804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Create domain tree 881804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.domains = Domains("Domains") 882804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.domains.populate(dom) 883804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.addChild(self.domains) 884804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Create criterion list 885804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.criteria = Criteria("CriterionRoot") 886804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.addChild(self.criteria) 887804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 888804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def exportToXML(self): 889804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """Export tree to an xml document""" 890804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard impl = xml.dom.minidom.getDOMImplementation() 891794fea64ed11b6c2b2604c3a0daa374c885f09d6Kevin Rocard document = impl.createDocument(namespaceURI=None, qualifiedName=self.tag, doctype=None) 892794fea64ed11b6c2b2604c3a0daa374c885f09d6Kevin Rocard super().exportToXML(document, document.documentElement) 893804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 894794fea64ed11b6c2b2604c3a0daa374c885f09d6Kevin Rocard return document 895326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 896326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard# ============================ 897326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard# Command line argument parser 898326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard# ============================ 899326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 900326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 901326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardclass ArgumentParser: 902804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """class that parse command line arguments with argparse library 903804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 904804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard Result of parsing are the class attributes. 905804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """ 906804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard levelTranslate = [logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG] 907804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 908804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard def __init__(self): 909804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 910804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard try: 911804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # As argparse is only in the stdlib since python 3.2, 912804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # testing its availability 913804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard import argparse 914804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 915804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard except ImportError: 916804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.warning("Unable to import argparse " 917804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "(parser for command-line options and arguments), " 918804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "using default argument values:") 919804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 920804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.warning(" - InputFile: stdin") 921804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.inputFile = sys.stdin 922804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 923804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.warning(" - OutputFile: stdout") 924804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.outputFile = sys.stdout 925804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 926804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard try: 927804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.domainsFile = sys.argv[1] 928804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard except IndexError as ex: 929804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.fatal("No domain file provided (first argument)") 930804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard raise ex 931804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else: 932804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.warning(" - Domain file: " + self.domainsFile) 933804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 934804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.warning(" - Output format: xml") 935804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.XMLreport = True 936804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 937804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.warning(" - Debug level: error") 938804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debugLevel = logging.ERROR 939804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 940804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 941804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard myArgParser = argparse.ArgumentParser(description='Generate PFW report') 942804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 943804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard myArgParser.add_argument( 944804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 'domainsFile', 945804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard type=argparse.FileType('r'), 946804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help="the PFW domain XML file" 947804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 948804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard myArgParser.add_argument( 949804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 'pfwlog', nargs='?', 950804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard type=argparse.FileType('r'), default=sys.stdin, 951804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help="the PFW log file, default stdin" 952804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 953804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard myArgParser.add_argument( 954804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard '-o', '--output', 955804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard dest="outputFile", 956804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard type=argparse.FileType('w'), default=sys.stdout, 957804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help="the coverage report output file, default stdout" 958804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 959804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard myArgParser.add_argument( 960804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard '-v', '--verbose', 961804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard dest="debugLevel", default=0, 962804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard action='count', 963804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help="print debug warnings from warning (default) to debug (-vv)" 964804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 965804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 966804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard outputFormatGroupe = myArgParser.add_mutually_exclusive_group(required=False) 967804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 968804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard outputFormatGroupe.add_argument( 969804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard '--xml', 970804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard dest="xmlFlag", 971804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard action='store_true', 972804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help=" XML coverage output report" 973804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 974804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard outputFormatGroupe.add_argument( 975804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard '--raw', 976804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard dest="rawFlag", 977804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard action='store_true', 978804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help="raw coverage output report" 979804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 980804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 981804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard myArgParser.add_argument( 982ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner '--ignore-unknown-criterion', 983ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner dest="unknwonCriterionFlag", 984ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner action='store_true', 985ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner help="ignore unknown criterion" 986ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner ) 987ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner 988ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner myArgParser.add_argument( 989804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard '--ignore-incoherent-criterion-state', 990804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard dest="incoherentCriterionFlag", 991804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard action='store_true', 992804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help="ignore criterion transition to incoherent state" 993804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 994804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 995804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard myArgParser.add_argument( 996804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard '--ignore-ineligible-configuration-application', 997804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard dest="ineligibleConfigurationApplicationFlag", 998804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard action='store_true', 999804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard help="ignore application of configuration with a false rule " 1000804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard "(not applicable configuration)" 1001804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard ) 1002804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 1003804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Process command line arguments 1004804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard options = myArgParser.parse_args() 1005804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 1006804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Mapping to attributes 1007804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.inputFile = options.pfwlog 1008804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.outputFile = options.outputFile 1009804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.domainsFile = options.domainsFile 1010804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 1011804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Output report in xml if flag not set 1012804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.XMLreport = not options.rawFlag 1013804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 1014804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Setting logger level 1015804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard levelCapped = min(options.debugLevel, len(self.levelTranslate) - 1) 1016804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.debugLevel = self.levelTranslate[levelCapped] 1017804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 1018804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Setting ignore options 1019804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard errorToIgnore = [] 1020804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if options.ineligibleConfigurationApplicationFlag : 1021804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard errorToIgnore.append(Configuration.IneligibleConfigurationAppliedError) 1022804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 1023804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if options.incoherentCriterionFlag: 102412d9c82b31650d307e3834e435e1f5f54e3832d0David Wagner errorToIgnore.append(Criterion.ChangeRequestToNonAccessibleState) 1025ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner 1026ace56ce368fa42b3eb496382e7387a47fff5f0a6David Wagner if options.unknwonCriterionFlag: 102712d9c82b31650d307e3834e435e1f5f54e3832d0David Wagner errorToIgnore.append(ParsePFWlog.ChangeRequestOnUnknownCriterion) 1028804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard 1029804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard self.errorToIgnore = tuple(errorToIgnore) 10309050c81c8f9a63aa95e7230705e00585bd0ecec5Kevin Rocard 1031326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1032326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1033326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocarddef main(): 1034326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1035804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard errorDuringLogParsing = -1 1036804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard errorDuringArgumentParsing = 1 103753493b2f22bc2d491f7607672e1d07e588677efaKevin Rocard 1038804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard try: 1039804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard commandLineArguments = ArgumentParser() 1040804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard except LookupError as ex: 1041804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.error("Error during argument parsing") 1042804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.debug(str(ex)) 1043804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard sys.exit(errorDuringArgumentParsing) 1044326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1045804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Setting logger level 1046804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.setLevel(commandLineArguments.debugLevel) 1047804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.info("Log level set to: %s" % 1048804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logging.getLevelName(commandLineArguments.debugLevel)) 1049326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1050804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Create tree from XML 1051804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard dom = xml.dom.minidom.parse(commandLineArguments.domainsFile) 1052326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1053804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Create element tree 1054804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard root = Root("DomainCoverage", dom) 1055326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1056804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Parse PFW events 1057804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard parser = ParsePFWlog(root.domains, root.criteria, commandLineArguments.errorToIgnore) 105853493b2f22bc2d491f7607672e1d07e588677efaKevin Rocard 1059804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard try: 1060804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard parser.parsePFWlog(commandLineArguments.inputFile.readlines()) 1061804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard except CustomError as ex: 1062804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard logger.fatal("Error during parsing log file %s: %s" % 1063804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard (commandLineArguments.inputFile, ex)) 1064804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard sys.exit(errorDuringLogParsing) 1065326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1066804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard # Output report 1067804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard outputFile = commandLineArguments.outputFile 1068326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1069804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard if not commandLineArguments.XMLreport : 1070804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard outputFile.write("%s\n" % root.dump(withCoverage=True, withNbUse=True)) 1071804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard else : 1072804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard outputFile.write(root.exportToXML().toprettyxml()) 1073326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1074326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1075326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocardif __name__ == "__main__" : 1076804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard """ Execute main if the python interpreter is running this module as the main program """ 1077804e064dcd02b87e04b9a189422cc14205e8125cKevin Rocard main() 1078326e39e42a801bff4b61655ebc0e3ff759c208ffKevin Rocard 1079