Package sysdef :: Module api |
[hide private]
[frames] | no frames]

# Source Code for Module sysdef.api

      1  #============================================================================
      2  #Name        : api.py
      3  #Part of     : Helium
      4
      5  #Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
      6  #All rights reserved.
      7  #This component and the accompanying materials are made available
      8  #under the terms of the License "Eclipse Public License v1.0"
      9  #which accompanies this distribution, and is available
     10  #at the URL "http://www.eclipse.org/legal/epl-v10.html".
     11  #
     12  #Initial Contributors:
     13  #Nokia Corporation - initial contribution.
     14  #
     15  #Contributors:
     16  #
     17  #Description:
     18  #===============================================================================
     19
     20  """ System Definition file parser.
     21
     22  Priority are not handled yet.
     23  Nested task unitlist are not handled properly yet.
     24
     25  How to use it::
     26
     27      sdf = SystemDefinition(filename)
     28      for name in sdf.layers:
     29          print " + Units in layer %s" % name
     30          for unit in sdf.layers[name].units:
     31              print "     - " +  sdf.units[name].id
     32
     33      for name in sdf.units:
     34          print sdf.units[name].id
     35
     36  """
     37
     38  import logging
     39  import os
     40  import re
     41  import sys
     42  import types
     43
     44  import amara
     45  from xmlhelper import node_scan, recursive_node_scan
     46  from xml.dom import Node
     47
     48  import buildtools
     49
     50  logging.basicConfig(level=logging.INFO)
     51  _logger = logging.getLogger('sysdef.api')
     52
     53
     54 -def filter_out(config_filters, unit_filters):
     55      """ Function that determines if a unit should be included or not.
     56          returns None => could be included, string reason.
     57      """
     58
     59      def hasvalue(filter_list, value):
     60          """ Check if a filter list contains a particular value.
     61              It handles list's item negation using "!".
     62          """
     63          for list_value in filter_list:
     64              if list_value == value:
     65                  return True
     66          return False
     67      for filter_ in unit_filters:
     68          if filter_.startswith("!"):
     69              if hasvalue(config_filters, filter_[1:]):
     70                  return filter
     71          else:
     72              if not hasvalue(config_filters, filter_):
     73                  return filter_
     74      return None
     75
     76
     77 -def extract_filter_list(filters):
     78      """ Convert a comma separated list of filters into a python list.
     79          The method will skip empty filters (empty strings).
     80      """
     81      result = []
     82      for filter_ in [filter_.strip() for filter_ in filters.split(",")]:
     83          if len(filter_) > 0:
     84              result.append(filter_)
     85      return result
     86
     87
     88 -class SysDefElement(object):
     89      """ A generic element of a System Definition. """
     90 -    def __init__(self, sysDef):
     91          """ Initialisation """
     92          self._sysDef = sysDef
     93
     94 -    def _getname(self):
     95          """ Name getter method """
     96          return NotImplementedError()
     97
     98 -    def get_id(self):
     99          """ Use name as default ID. """
    100          return getattr(self, 'name').lower()
    101
    102 -    def __str__(self):
    103          return self.get_id()
    104
    105
    106 -class Unit(SysDefElement):
    107      """ Abstract unit from SDF file. """
    108 -    def __init__(self, node, sysDef):
    109          """ Initialisation """
    110          SysDefElement.__init__(self, sysDef)
    111          self.__xml = node
    112          self.binaries = []
    113
    114 -    def __getid(self):
    115          """ Id getter. """
    116          return self.__xml.unitID
    117
    118 -    def _getname(self):
    119          """ Name getter. """
    120          return self.__xml.name
    121
    122 -    def __getpath(self):
    123          """ Path getter. """
    124          return os.path.join(os.path.sep, self.__xml.bldFile)
    125
    126 -    def __getfilters(self):
    127          """ filter getter. """
    128          filters = []
    129          if hasattr(self.__xml, 'filter'):
    130              filters = extract_filter_list(self.__xml.filter)
    131          return filters
    132
    133      id = property(__getid)
    134      name = property(_getname)
    135      path = property(__getpath)
    136      filters = property(__getfilters)
    137
    138
    139 -class _UnitGroup(SysDefElement):
    140      """ A group of units. """
    141 -    def __init__(self, node, sysDef):
    142          """ Initialisation """
    143          SysDefElement.__init__(self, sysDef)
    144          self._xml = node
    145          self._units = []
    146
    147 -    def __getname(self):
    148          """ Name getter method """
    149          return self._xml.name
    150
    151 -    def __getunits(self):
    152          """ Units getter method """
    153          return self._units
    154
    155      name = property(__getname)
    156      units = property(__getunits)
    157
    158
    159 -class Layer(_UnitGroup):
    160      """ Abstract layer from SDF file. """
    161 -    def __init__(self, node, sysDef):
    162          """ Initialisation """
    163          _UnitGroup.__init__(self, node, sysDef)
    164          self._modules = []
    165          self._module_count = 0
    166          for unitNode in recursive_node_scan(self._xml, 'unit'):
    167              unit = Unit(unitNode, self._sysDef)
    168              self._units.append(unit)
    169              self._sysDef.addElement(unit)
    170
    171          for moduleNode in recursive_node_scan(self._xml, 'module'):
    172              module = Module(moduleNode, self._sysDef)
    173              self._modules.append(module)
    174              self._module_count += 1
    175              # Not added to the model.
    176              #self._sysDef.addElement(module)
    177
    178 -    def __getmodules(self):
    179          """ Module list accessor. """
    180          return self._modules
    181
    182 -    def __getmodulescount(self):
    183          """ Module cound accessor. """
    184          return self._module_count
    185
    186      modules = property(__getmodules)
    187      modules_count = property(__getmodulescount)
    188
    189
    190 -class Module(_UnitGroup):
    191      """ Abstract module from SDF file. """
    192 -    def __init__(self, node, sysDef):
    193          """ Initialisation """
    194          _UnitGroup.__init__(self, node, sysDef)
    195          for unitNode in recursive_node_scan(self._xml, "unit"):
    196              unit = Unit(unitNode, self._sysDef)
    197              self._units.append(unit)
    198
    199
    200 -class UnitList(_UnitGroup):
    201      """ Abstract unitlist from SDF file. """
    202 -    def __init__(self, node, units, sysDef):
    203          """ Initialisation """
    204          _UnitGroup.__init__(self, node, sysDef)
    205          for unitRef in node_scan(self._xml, "unitRef"):
    206              try:
    207                  self._units.append(units[unitRef.unit])
    208              except KeyError, error:
    209                  sys.stderr.write("ERROR: Could not find unit '%s'\n" % unitRef.unit + "\n" + error)
    210
    211
    212 -class BuildLayer(SysDefElement):
    213      """ Abstract buildlayer. """
    214 -    def __init__(self, node, config, sysDef):
    215          """ Initialisation """
    216          SysDefElement.__init__(self, sysDef)
    217          self.__xml = node
    218          self.config = config
    219          self.targetList = []
    220          if hasattr(self.__xml, 'targetList'):
    221              for tlname in re.split(r'\s+', self.__xml.targetList.strip()):
    222                  for target in self._sysDef.targetlists[tlname].targets:
    223                      self.targetList.append(target)
    224
    225 -    def __getcommand(self):
    226          """ Command getter method. """
    227          return self.__xml.command
    228
    229 -    def __getunitParallel(self):
    230          """ Unit Parallel getter method (boolean). """
    231          return (self.__xml.unitParallel.upper() == "Y")
    232
    233      command = property(__getcommand)
    234      unitParallel = property(__getunitParallel)
    235
    236
    237 -class Option(SysDefElement):
    238      """ Represents an option used in abld calls. """
    239 -    def __init__(self, node, sysDef):
    240          """ Initialisation """
    241          SysDefElement.__init__(self, sysDef)
    242          self.__xml = node
    243
    244 -    def __getname(self):
    245          """ Name getter method. """
    246          return self.__xml.name
    247
    248 -    def __getabldOption(self):
    249          """ Abld option getter method. """
    250          return self.__xml.abldOption
    251
    252 -    def __getenable(self):
    253          """ Unit Parallel getter method (boolean). """
    254          return (self.__xml.enable.upper() == 'Y')
    255
    256 -    def __getfilteredOption(self):
    257          """ Filtered abld option getter method. """
    258          if not self.enable:
    259              return ''
    260          return self.abldOption
    261
    262      name = property(__getname)
    263      abldOption = property(__getabldOption)
    264      enable = property(__getenable)
    265      filteredOption = property(__getfilteredOption)
    266
    267
    268 -class SpecialInstruction(SysDefElement):
    269      """ Reads special instruction command. """
    270 -    def __init__(self, node, sysDef):
    271          """ Initialisation """
    272          SysDefElement.__init__(self, sysDef)
    273          self.__xml = node
    274
    275 -    def __getname(self):
    276          """ Name getter method """
    277          return self.__xml.name
    278
    279 -    def __getcommand(self):
    280          """ Command getter method """
    281          return self.__xml.command
    282
    283 -    def __getpath(self):
    284          """ Path getter method """
    285          return self.__xml.cwd
    286
    287      name = property(__getname)
    288      command = property(__getcommand)
    289      path = property(__getpath)
    290
    291
    292 -class Task(SysDefElement):
    293      """ Abstract task node from SDF xml. """
    294 -    def __init__(self, node, config, sysDef):
    295          """ Initialisation """
    296          SysDefElement.__init__(self, sysDef)
    297          self.__xml = node
    298          self._config = config
    299          self.__job = None
    300
    301 -    def units(self):
    302          """ Process unit list from layers """
    303          result = []
    304          for ref in node_scan(self.__xml, "unitListRef"):
    305              units = []
    306              try:
    307                  units = self._config.sdf.unitlists[ref.unitList].units
    308                  for unit in units:
    309                      reason = filter_out(self._config.filters, unit.filters)
    310                      if reason == None:
    311                          result.append(unit)
    312                      else:
    313                          sys.stderr.write("Filter-out: %s (%s)\n" % (unit.id, reason))
    314              except KeyError, error:
    315                  sys.stderr.write("ERROR: Could not find unitList of layer %s\n" % error)
    316          return result
    317
    318 -    def __getjob(self):
    319          """ Return the job contained inside the task. """
    320          for job in node_scan(self.__xml, r"buildLayer|specialInstructions"):
    321              if job.nodeName == 'specialInstructions':
    322                  self.__job = SpecialInstruction(job, self._sysDef)
    323              elif job.nodeName == 'buildLayer':
    324                  self.__job = BuildLayer(job, self._config, self._sysDef)
    325          return self.__job
    326
    327      job = property(__getjob)
    328
    329
    330 -class Configuration(SysDefElement):
    331      """ Abstract configuration from SDF file. """
    332 -    def __init__(self, node, sysDef):
    333          """ Initialisation """
    334          SysDefElement.__init__(self, sysDef)
    335          self.__xml = node
    336
    337 -    def __getname(self):
    338          """ Name getter method """
    339          return self.__xml.name
    340
    341 -    def __getfilters(self):
    342          """ Filters getter method. """
    343          filters = []
    344          if hasattr(self.__xml, 'filter'):
    345              filters = extract_filter_list(self.__xml.filter)
    346          return filters
    347
    348 -    def __getlayerrefs(self):
    349          """ Layer's references getter method. """
    350          result = []
    351          for ref in node_scan(self.__xml, "layerRef"):
    352              try:
    353                  result.append(self._sysDef.layers[ref.layerName])
    354              except KeyError, error:
    355                  sys.stderr.write("ERROR: Could not find layer '%s'\n" % error)
    356          return result
    357
    358 -    def __getunitlistrefs(self):
    359          """ Unit list references getter method. """
    360          result = []
    361          for ref in node_scan(self.__xml, "unitListRef"):
    362              try:
    363                  result.append(self._sysDef.unitlists[ref.unitList])
    364              except KeyError, error:
    365                  sys.stderr.write("ERROR: Could not find unitList %s\n" % error)
    366          return result
    367
    368 -    def __getunits(self):
    369          """ Return unit from unitList or layer. """
    370          result = []
    371          for ref in node_scan(self.__xml, "unitListRef|layerRef"):
    372              units = []
    373              try:
    374                  if ref.nodeName == 'unitListRef':
    375                      units = self._sysDef.unitlists[ref.unitList].units
    376                  else:
    377                      units = self._sysDef.layers[ref.layerName].units
    378                  for unit in units:
    379                      reason = filter_out(self.filters, unit.filters)
    380                      if reason == None:
    381                          # Get the unit object from the cache if this is a string
    382                          # TODO - remove once unitlist returns list of Unit objects
    383                          if isinstance(unit, types.UnicodeType):
    384                              unit = self._sysDef[unit]
    385                          result.append(unit)
    386                      else:
    387                          sys.stderr.write("Filter-out: %s (%s)\n" % (unit.id, reason))
    388              except KeyError, error:
    389                  sys.stderr.write("ERROR: Could not find unitList or layer %s\n" % error)
    390          return result
    391
    392 -    def __gettasks(self):
    393          """ Tasks getter method. """
    394          result = []
    395          for task in node_scan(self.__xml, "task"):
    396              result.append(Task(task, self, self._sysDef))
    397          return result
    398
    399      name = property(__getname)
    400      filters = property(__getfilters)
    401      layerrefs = property(__getlayerrefs)
    402      unitlistrefs = property(__getunitlistrefs)
    403      units = property(__getunits)
    404      tasks = property(__gettasks)
    405
    406
    407 -class Target(SysDefElement):
    408      """ Abstract target from SDF file. """
    409 -    def __init__(self, node, sysDef):
    410          """ Initialisation """
    411          SysDefElement.__init__(self, sysDef)
    412          self.__xml = node
    413
    414 -    def __getname(self):
    415          """ Name getter method. """
    416          return self.__xml.name
    417
    418 -    def __getabldTarget(self):
    419          """ Abld target getter method. """
    420          return self.__xml.abldTarget
    421
    422      name = property(__getname)
    423      abldTarget = property(__getabldTarget)
    424
    425
    426 -class TargetList(SysDefElement):
    427      """ Abstract targetlist from SDF file. """
    428 -    def __init__(self, node, sysDef):
    429          """ Initialisation """
    430          SysDefElement.__init__(self, sysDef)
    431          self.__xml = node
    432
    433 -    def __getname(self):
    434          """ Name getter method. """
    435          return self.__xml.name
    436
    437 -    def __gettargets(self):
    438          """ Targets getter method. """
    439          result = []
    440          for target in re.split(r'\s+', self.__xml.target):
    441              result.append(self._sysDef.targets[target.strip()])
    442          return result
    443
    444      name = property(__getname)
    445      targets = property(__gettargets)
    446
    447
    448 -class SystemDefinition(object):
    449      """ Logical representation of the System Definition.
    450
    451      The System Definition is defined in terms of a system model and a
    452      build model. The default physical representation of this is the Symbian
    453      XML format. """
    454 -    def __init__(self, filename):
    455          """ Initialisation """
    456          self.__xml = amara.parse(open(filename, "r"))
    457          self._cache = {}
    458          #TODO - why store these as hashes?
    459          self._units = {}
    460          self._layers = {}
    461          self._modules = {}
    462          self._unitlists = {}
    463          self._configurations = {}
    464          self._options = {}
    465          self._targets = {}
    466          self._targetlists = {}
    467          self.__parse()
    468
    469 -    def __getunits(self):
    470          """ Units getter method. """
    471          return self._units
    472
    473 -    def __getmodules(self):
    474          """ Modules getter method. """
    475          return self._modules
    476
    477 -    def __getlayers(self):
    478          """ Layers getter method. """
    479          return self._layers
    480
    481 -    def __getunitlists(self):
    482          """ Unit lists getter method. """
    483          return self._unitlists
    484
    485 -    def __getoptions(self):
    486          """ Options getter method. """
    487          return self._options
    488
    489 -    def __getconfigurations(self):
    490          """ Configurations getter method. """
    491          return self._configurations
    492
    493 -    def __gettargetlists(self):
    494          """ Targets lists getter method. """
    495          return self._targetlists
    496
    497 -    def __gettargets(self):
    498          """ Targets getter method. """
    499          return self._targets
    500
    501      units = property(__getunits)
    502      unitlists = property(__getunitlists)
    503      layers = property(__getlayers)
    504      options = property(__getoptions)
    505      configurations = property(__getconfigurations)
    506      targetlists = property(__gettargetlists)
    507      targets = property(__gettargets)
    508      modules = property(__getmodules)
    509
    510 -    def __parse(self):
    511          if hasattr(self.__xml, u'SystemDefinition'):
    512              for systemdef in self.__xml.SystemDefinition:
    513                  if hasattr(systemdef, u'systemModel'):
    514                      for systemmodel in systemdef.systemModel:
    515                          if hasattr(systemmodel, u'layer'):
    516                              for l in systemmodel.layer:
    517                                  layer = Layer(l, self)
    518                                  self.layers[layer.name] = layer
    519                                  self.addElement(layer)
    520                                  for unit in layer.units:
    521                                      self._units[unit.get_id()] = unit
    522                                  for mod in layer.modules:
    523                                      self._modules[mod.name] = mod
    524
    525                  if hasattr(systemdef, u'build'):
    526                      for build in systemdef.build:
    527                          if hasattr(build, u'unitList'):
    528                              for ul in build.unitList:
    529                                  unitlist = UnitList(ul, self._units, self)
    530                                  self.unitlists[unitlist.name] = unitlist
    531                                  self.addElement(unitlist)
    532
    533                          if hasattr(build, u'configuration'):
    534                              for xml_config in build.configuration:
    535                                  config = Configuration(xml_config, self)
    536                                  self.configurations[config.name] = config
    537                                  self.addElement(config)
    538
    539                          if hasattr(build, u'option'):
    540                              for option_node in build.option:
    541                                  option = Option(option_node, self)
    542                                  if option.name == 'SAVESPACE':
    543                                      continue
    544                                  self.options[option.name] = option
    545                                  self.addElement(option)
    546
    547                          if hasattr(build, u'target'):
    548                              for target_node in build.target:
    549                                  target = Target(target_node, self)
    550                                  self.targets[target.name] = target
    551                                  self.addElement(target)
    552
    553                          if hasattr(build, u'targetList'):
    554                              for targetlist_node in build.targetList:
    555                                  targetlist = TargetList(targetlist_node, self)
    556                                  self.targetlists[targetlist.name] = targetlist
    557                                  self.addElement(targetlist)
    558
    559 -    def addElement(self, element):
    560          """ Adds SysDef element to cache. """
    561          #TODO - handle duplicate names of different types
    562          if not self._cache.has_key(element.get_id()):
    563              self._cache[element.get_id()] = element
    564              _logger.info('Adding SysDef element to cache: %s' % str(element))
    565          else:
    566              _logger.warning("Element already exists: %s" % element.name)
    567
    568 -    def __getitem__(self, key):
    569          """ Item getter method. """
    570          return self._cache[key]
    571
    572 -    def merge_binaries(self, binaries_reader):
    573          """ Merge binaries based on build log and system definition. """
    574          for (unit_name, binaries) in binaries_reader:
    575              unit_name = unit_name.lower()
    576              if self.units.has_key(unit_name):
    577                  for bin in binaries:
    578                      #if bin.find('_stolon_ekern') != -1:
    579                      _logger.debug("Merging: %s" % bin)
    580                  unit = self.units[unit_name]
    581                  unit.binaries = [Binary(bin.lower(), self) for bin in binaries]
    582                  for binary in unit.binaries:
    583                      self.addElement(binary)
    584                      _logger.info('Merging binary: %s' % str(binary))
    585              else:
    586                  _logger.warning('Component found in the build log but not in sysdef: %s' % unit_name)
    587
    588 -    def merge_binary_sizes(self, binary_sizes_reader):
    589          """ Merge binary size base on binary sizes input and system definition. """
    590          for (binary_name, size, rom_type) in binary_sizes_reader:
    591              #if binary_name.find('_stolon_ekern') != -1:
    592
    593              binary_name = binary_name.lower()
    594              _logger.debug("Merging binary size: %s" % binary_name)
    595              if self._cache.has_key(binary_name):
    596                  binary = self._cache[binary_name]
    597                  binary.size = size
    598                  binary.rom_type = rom_type
    599              else:
    600                  _logger.warning('Binary found in the binary sizes input but not in the system definition: %s' % binary_name)
    601
    602
    603 -class Binary(SysDefElement):
    604      """ A binary file that may go into a ROM image. """
    605
    606 -    def __init__(self, name, sysDef):
    607          """ Initialisation """
    608          SysDefElement.__init__(self, sysDef)
    609          self.name = name
    610
    611
    612
    613
    614
    615
    616  #if __name__ == "__main__":
    617  #    sdf = SystemDefinitionFile("Z:/output/build/canonical_system_definition.xml")
    618  #    writer = MakeWriter2("Z:/output/build/makefile")
    619  #    writer.write(sdf)
    620  #    writer.close()
    621  #    print sdf.toMakefile()
    622