--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmtestenv/mmtesttools/Build/buildutils/MbcUtils.py Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,352 @@
+# Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# Tools to parse mbc files
+# NOTE: There is unit etc test code for this in testMbcUtils.py
+# Any changes to this file should be checked with "python testMbcUtils.py"
+# Also note that the test code coverage is not 100%
+#
+
+import re
+import types
+import os
+
+class InvalidInput(Exception):
+ """Raised for invalid data in files"""
+
+ def __init__(self, badInput):
+ self.__badInput = badInput
+
+ def __str__(self):
+ return "InvalidInput(%s)" % self.__badInput
+
+class Unimplemented(Exception):
+ """Raised for features we don't cover"""
+
+ def __init__(self, msg):
+ self.__msg = msg
+
+ def __str__(self):
+ return "Unimplemented(%s)" % self.__msg
+
+class InvalidArg(Exception):
+ """Raised for invalid data in argument"""
+
+ def __init__(self, badArg):
+ self.__badArg = badArg
+
+ def __str__(self):
+ return "InvalidArg(%s)" % self.__badArg
+
+class MissingFile(Exception):
+ "Raised when we expect a file and it does not exist"
+
+ def __init__(self, badFname):
+ self.__badFname = badFname
+
+ def __str__(self):
+ return "MissingFile(%s)" % self.__badFname
+
+class _MbcParser(object):
+ """Parse an mbc file, given by name. Return as tuple of the given categories, coupled with the filename."""
+
+ # __slots__ = ["__fname", "__result", "__state"]
+
+ __nullState = -1
+ __dirsSectionState = 1 # assumed to be same as tuple index
+ __optionDirsSectionState = 2 # assumed to be same as tuple index
+ __commandSectionState = 3 # assumed to be same as tuple index
+
+ def __init__(self, fname):
+ self.__fname = fname
+ self.__dirname = os.path.dirname(fname)
+ self.__result = None
+ self.__state = _MbcParser.__nullState
+ self.__executed = False
+
+ def execute(self):
+ "Call to generate the result"
+ self.__reset(self.__fname) # initialize __result etc
+ self.__openAndParse()
+ self.__executed = True
+
+ def __call__(self):
+ if not self.__executed:
+ self.execute()
+ return self.__result
+
+ def __reset(self, fname=None):
+ self.__result = (fname,[],[],[])
+
+ def __openAndParse(self):
+ "Open file and then parse line-by-line"
+ # note deliberately use old version to avoid 2.4 issue. Going foreard, "with" seems to be the correct approach
+ # could perhaps write this better using a parser module, or more extensive use of re, but this is not seen as module specific
+ inputFile = open(self.__fname)
+ try:
+ for line in inputFile:
+ self.__parseLine(line)
+ finally:
+ inputFile.close()
+
+ def __parseLine(self,line):
+ # initially we want the bit of the line up to the first // or \n
+ # TODO should be able to do in one re?
+ lookforeoln = re.match(r"(.*)$", line) # lose any \n
+ if lookforeoln:
+ line = lookforeoln.group(1)
+ lookforcomment = re.match(r"(.*)//.*", line)
+ if lookforcomment:
+ line = lookforcomment.group(1)
+ line.strip() # remove spaces at start and end
+ if not line:
+ # skip blank line
+ return;
+ if line == "SECTION_DIRS":
+ self.__state = _MbcParser.__dirsSectionState
+ elif line == "SECTION_OPTIONALDIRS":
+ self.__state = _MbcParser.__optionDirsSectionState
+ elif line == "SECTION_COMMANDS":
+ self.__state = _MbcParser.__commandSectionState
+ else:
+ # for dirs or optionDirs section we are after a single string to treat as directory. don't check here
+ if ((self.__state == _MbcParser.__dirsSectionState) or
+ (self.__state == _MbcParser.__optionDirsSectionState)):
+ matchre = re.match(r'[_\-a-z0-9\\/\.]+$', line, re.IGNORECASE)
+ if matchre:
+ # we have a match - add to the tuple
+ matchresult = line # no need to decode. whole thing is the line
+ if matchresult[0] != "\\":
+ # relative path - need to add folder name
+ matchresult = os.path.abspath(os.path.join(self.__dirname, matchresult))
+ self.__result[self.__state].append(matchresult)
+ else:
+ raise InvalidInput (line)
+ elif self.__state == _MbcParser.__commandSectionState:
+ matchre = re.match(r'oneoff\s+([_\-a-z0-9\\/\.]+)\s+(.+)$', line, re.IGNORECASE)
+ if matchre:
+ # append tuple of (directory, command). Comes as (group(1),group(2)) but have to
+ # convert relative directory we get to absolute if required
+ matchDir = matchre.group(1)
+ if matchDir[0] != "\\":
+ # relative path- need to add folder name
+ matchDir = os.path.abspath(os.path.join(self.__dirname, matchDir))
+ self.__result[self.__state].append((matchDir,matchre.group(2)))
+ else:
+ raise InvalidInput (line)
+
+class _MbcListHandle(object):
+ """Handle a list or tuple of filenames, recursively list of tuples as produced by _MbcParser"""
+
+ def __init__(self, fnameList):
+ """Assume fnameList is a container. Always generate a list"""
+ self.__fnameList = fnameList
+ self.__result = []
+ self.__executed = False
+
+ def execute(self):
+ for fname in self.__fnameList:
+ parser = MbcParser(fname)
+ parser.execute()
+ self.__result.append(parser())
+ self.__exectuted = True
+
+ def __call__(self):
+ if not self.__exectuted:
+ self.execute()
+ return self.__result
+
+class MbcParser(object):
+ """Given a list of or a filename, return equivalent structure with each filename replaced by tuple of content
+
+ tuple elements are:
+ 0 - filename
+ 1 - main directories
+ 2 - optional directories
+ 3 - oneoff"""
+
+ def __init__(self, fnameOrList):
+ self.__fnameOrList = fnameOrList
+ self.__result = None
+ self.__executed = False
+
+ def execute(self):
+ fnameOrList = self.__fnameOrList
+ if isinstance(fnameOrList, list) or isinstance(fnameOrList, tuple):
+ parser = _MbcListHandle(fnameOrList)
+ parser.execute()
+ self.__result = parser()
+ elif isinstance(fnameOrList, types.StringTypes):
+ parser = _MbcParser(fnameOrList)
+ parser.execute()
+ self.__result = parser()
+ else:
+ raise InvalidArg(fnameOrList)
+
+ def __call__(self):
+ if not self.__executed:
+ self.execute()
+ return self.__result
+
+class GetFolderList(object):
+ """Given output of MbcParser(), produces list of tuples in the format:
+
+ 0 - Element is folder if True (only thing currently supported)
+ 1 - folder
+ 2 - comment to use in generated file including original filename
+
+ If folder is optional, will only be added if exists - actually if nameToCheck exists in folder.
+ If folder is not optional, and does not exist, this will raise an error.
+ """
+
+ def __init__(self, inputList, nameToCheck="bld.inf"):
+ if isinstance(inputList, tuple):
+ # single element "list" from MbcParser is not always a list!
+ self.__list = [inputList]
+ else:
+ self.__list = inputList
+ self.__nameToCheck = nameToCheck
+ self.__result = []
+ self.__exectuted = False
+
+ def execute(self):
+ self.__result = []
+ self.__genResult()
+ self.__executed = True
+
+ def __genResult(self):
+ "Process whole list"
+ for listEle in self.__list:
+ self.__processEle(listEle)
+
+ def __processEle(self, listEle):
+ "Process single element in input list"
+ (fname, dirs, optDirs, commands) = listEle
+ for dir in dirs:
+ combinedFname = os.path.join(dir, self.__nameToCheck)
+ exists = os.path.exists(combinedFname)
+ if not exists:
+ raise MissingFile(combinedFname)
+ self.__result.append((True, dir, "From %s"%fname))
+ for dir in optDirs:
+ combinedFname = os.path.join(dir, self.__nameToCheck)
+ exists = os.path.exists(combinedFname)
+ if exists:
+ self.__result.append((True, dir, "From %s"%fname))
+ else:
+ self.__result.append((True, None, """Skip "%s" from %s"""%(dir,fname)))
+ if commands:
+ raise Unimplemented("No support for oneoff - %s" % str(commands))
+
+ def __call__(self):
+ if not self.__exectuted:
+ self.execute()
+ return self.__result
+
+## Minimal example configuration file as we have to produce
+## See http://developer.symbian.com/wiki/x/rgD6Bg
+##
+##<SystemDefinition name="BLAH" schema="2.0.0">
+## <systemModel>
+## <layer name="NEW_CUSTOM_LAYER">
+## <collection name="Fake Collection">
+## <component name="examples">
+## <unit bldFile="C:\Symbian\Carbide2\workspace\hello_whirled\group" />
+## <unit bldFile="C:\Symbian\Carbide2\workspace\hello_abld\group" />
+## </component>
+## </collection>
+## </layer>
+## </systemModel>
+##</SystemDefinition>
+
+
+class ConfigFileGenerator(object):
+ """Generate xml config file given output from GetFolderList
+
+ Output corresponds to the example in source
+ folderList is input from GetFolderList
+ outputStream is either filename or assumed to be an open file or StringIO"""
+
+ def __init__(self, folderList, outputStream):
+ self.__folderList = folderList
+ self.__streamParam = outputStream
+ self.__streamIsLocal = False
+ self.__stream = None
+
+ def __initStream(self):
+ "Work out stream to use. Open stream if required"
+
+ if isinstance(self.__streamParam, basestring):
+ # unicode or normal string
+ self.__streamIsLocal = True
+ self.__stream = open(self.__streamParam, "w")
+ else:
+ self.__streamIsLocal = False
+ self.__stream = self.__streamParam
+
+ def __closeStream(self):
+ "If stream is local, close it"
+
+ if self.__streamIsLocal:
+ self.__stream.close()
+
+ self.__stream = None # orphan if needs be
+ self.__streamIsLocal = False
+
+ def write(self):
+ "Called will write output to stream"
+
+ try:
+ self.__initStream()
+ self.__writeHeaderBit()
+ self.__writeFolderList()
+ self.__writeTailBit()
+ except: # TODO not sure we need this - if we ommit is finally clause run?
+ raise
+ finally:
+ self.__closeStream()
+
+ def __writeHeaderBit(self):
+ "Write bit of xml before the folder list"
+ # these names all come from the original. Seems no need to vary
+ # this code is 9.5 based
+ print >> self.__stream, r"""<SystemDefinition name="BLAH" schema="2.0.0">"""
+ print >> self.__stream, r""" <systemModel>"""
+ print >> self.__stream, r""" <layer name="NEW_CUSTOM_LAYER">"""
+ print >> self.__stream, r""" <collection name="Fake Collection">"""
+ print >> self.__stream, r""" <component name="Fake Multimedia">"""
+
+ def __writeTailBit(self):
+ "write bit of xml after the folder list"
+ print >> self.__stream, r""" </component>"""
+ print >> self.__stream, r""" </collection>"""
+ print >> self.__stream, r""" </layer>"""
+ print >> self.__stream, r""" </systemModel>"""
+ print >> self.__stream, r"""</SystemDefinition>"""
+
+ def __writeFolderList(self):
+ for ele in self.__folderList:
+ str = self.__strForListEle(ele)
+ if str:
+ print >> self.__stream, " %s" % str
+
+ def __strForListEle(self, ele):
+ (isFolder, folder, comment) = ele # break down tuple
+ result = None
+ if isFolder:
+ if folder:
+ result = r"""<unit bldFile="%s" /><!-- %s -->""" % (folder,comment)
+ else:
+ result = r"""<!-- %s -->""" % (comment)
+ return result
+