diff -r 000000000000 -r bde4ae8d615e os/mm/mmtestenv/mmtesttools/Build/buildutils/MbcUtils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/mm/mmtestenv/mmtesttools/Build/buildutils/MbcUtils.py Fri Jun 15 03:10:57 2012 +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 +## +## +## +## +## +## +## +## +## +## +## +## +## + + +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"""""" + print >> self.__stream, r""" """ + print >> self.__stream, r""" """ + print >> self.__stream, r""" """ + print >> self.__stream, r""" """ + + def __writeTailBit(self): + "write bit of xml after the folder list" + print >> self.__stream, r""" """ + print >> self.__stream, r""" """ + print >> self.__stream, r""" """ + print >> self.__stream, r""" """ + print >> self.__stream, r"""""" + + 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"""""" % (folder,comment) + else: + result = r"""""" % (comment) + return result +