3
+ − 1
#
+ − 2
# Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+ − 3
# All rights reserved.
+ − 4
# This component and the accompanying materials are made available
+ − 5
# under the terms of the License "Eclipse Public License v1.0"
+ − 6
# which accompanies this distribution, and is available
+ − 7
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ − 8
#
+ − 9
# Initial Contributors:
+ − 10
# Nokia Corporation - initial contribution.
+ − 11
#
+ − 12
# Contributors:
+ − 13
#
+ − 14
# Description:
+ − 15
# Creates CBR tool compatible cache files from SBSv2 .whatlog variant output
+ − 16
#
+ − 17
+ − 18
+ − 19
import sys
+ − 20
import os
+ − 21
from optparse import OptionParser
+ − 22
import xml.parsers.expat
+ − 23
import re
+ − 24
+ − 25
+ − 26
# Global dictionary of ComponentReleasable objects, keyed on bld.inf file
+ − 27
BuildReleasables = {}
+ − 28
+ − 29
# Provide a means to form "traditional" ABLD-like build platforms and variants from SBSv2 configurations
+ − 30
ConfigMatch = re.compile(r'^(?P<PLATFORM>\w+)_(?P<VARIANT>\w+)(\.((?P<PLATFORMADD>smp)|\w+))*')
+ − 31
+ − 32
WinscwTreeMatch = re.compile(r'[\\|\/]epoc32[\\|\/]release[\\|\/]winscw[\\|\/](?P<VARIANT>(urel|udeb))[\\|\/]', re.IGNORECASE)
+ − 33
WinDriveMatch = re.compile(r'[A-Za-z]:')
+ − 34
+ − 35
# $self->{abldcache}->{'<bld.inf location> export -what'} =
+ − 36
# $self->{abldcache}->{'<bld.inf location> <phase> <platform> <variant> -what'} =
+ − 37
# $self->{abldcache}->{'plats'} =
+ − 38
CacheGroupPrefix = "$self->{abldcache}->{\'"
+ − 39
CacheGroupSuffix = "\'} =\n"
+ − 40
CacheExportGroup = CacheGroupPrefix+"%s export -what"+CacheGroupSuffix
+ − 41
CacheBuildOutputGroup = CacheGroupPrefix+"%s %s %s %s -what"+CacheGroupSuffix
+ − 42
CachePlatsGroup = CacheGroupPrefix+"plats"+CacheGroupSuffix
+ − 43
CacheListOpen = "\t[\n"
+ − 44
CacheListItem = "\t\'%s\'"
+ − 45
CacheListItemPair = "\t[\'%s\', \'%s\']"
+ − 46
CacheListClose = "\t];\n\n"
+ − 47
+ − 48
+ − 49
class ComponentReleasable(object):
+ − 50
"""Wraps up a bld.inf file in terms of its packagable releasable output."""
+ − 51
+ − 52
# If EPOCROOT is set, provide a means to confirm that potentially publishable releasables live under EPOCROOT/epoc32
+ − 53
ReleaseTreeMatch = None
+ − 54
if os.environ.has_key("EPOCROOT"):
+ − 55
ReleaseTreeMatch = re.compile(r'\"*'+os.path.abspath(os.path.join(os.environ["EPOCROOT"],"epoc32")).replace('\\',r'\/').replace('\/',r'[\\|\/]+')+r'[\\|\/]+', re.IGNORECASE)
+ − 56
+ − 57
def __init__(self, aBldInfFile, aVerbose=False):
+ − 58
self.__BldInfFile = aBldInfFile
+ − 59
self.__Verbose = aVerbose
+ − 60
self.__Exports = {}
+ − 61
self.__BuildOutput = {}
+ − 62
self.__Platforms = {}
+ − 63
+ − 64
def __IsReleasableItem(self, aBuildItem):
+ − 65
if self.ReleaseTreeMatch and self.ReleaseTreeMatch.match(aBuildItem):
+ − 66
return True
+ − 67
+ − 68
if self.__Verbose:
+ − 69
print "Discarding: \'%s\' from \'%s\' as not in the release tree." % (aBuildItem, self.__BldInfFile)
+ − 70
return False
+ − 71
+ − 72
def __StoreBuildItem(self, aPlatform, aVariant, aBuildItem):
+ − 73
if not self.__BuildOutput.has_key(aPlatform):
+ − 74
self.__BuildOutput[aPlatform] = {}
+ − 75
if aPlatform != "ALL":
+ − 76
self.__Platforms[aPlatform.upper()] = 1
+ − 77
if not self.__BuildOutput[aPlatform].has_key(aVariant):
+ − 78
self.__BuildOutput[aPlatform][aVariant] = {}
+ − 79
+ − 80
if aBuildItem:
+ − 81
self.__BuildOutput[aPlatform][aVariant][aBuildItem] = 1
+ − 82
+ − 83
def AddExport(self, aDestination, aSource):
+ − 84
if not self.__IsReleasableItem(aDestination):
+ − 85
return
+ − 86
self.__Exports[aDestination] = aSource
+ − 87
+ − 88
def AddBuildOutput(self, aBuildItem, aPlatform="ALL", aVariant="ALL"):
+ − 89
if not self.__IsReleasableItem(aBuildItem):
+ − 90
return
+ − 91
if aPlatform != "ALL" and aVariant == "ALL":
+ − 92
self.__StoreBuildItem(aPlatform, "urel", aBuildItem)
+ − 93
self.__StoreBuildItem(aPlatform, "udeb", aBuildItem)
+ − 94
else:
+ − 95
self.__StoreBuildItem(aPlatform, aVariant, aBuildItem)
+ − 96
+ − 97
def Finalise(self):
+ − 98
# Re-visit the stored build items and, in the context of all build platforms having been processed for the
+ − 99
# component, copy platform-generic "ALL" output to the concrete build platform outputs
+ − 100
if self.__BuildOutput.has_key("ALL"):
+ − 101
allItems = self.__BuildOutput["ALL"]["ALL"].keys()
+ − 102
for platform in self.__BuildOutput.keys():
+ − 103
for variant in self.__BuildOutput[platform].keys():
+ − 104
for allItem in allItems:
+ − 105
self.__StoreBuildItem(platform, variant, allItem)
+ − 106
del self.__BuildOutput["ALL"]
+ − 107
+ − 108
def GetBldInf(self):
+ − 109
return self.__BldInfFile
+ − 110
+ − 111
def GetExports(self):
+ − 112
return self.__Exports
+ − 113
+ − 114
def GetBuildOutput(self):
+ − 115
return self.__BuildOutput
+ − 116
+ − 117
def GetPlatforms(self):
+ − 118
return self.__Platforms
+ − 119
+ − 120
def HasReleasables(self):
+ − 121
return (self.__BuildOutput or self.__Exports)
+ − 122
+ − 123
+ − 124
def error(aMessage):
+ − 125
sys.stderr.write("ERROR: sbsv2cache.py : %s\n" % aMessage)
+ − 126
sys.exit(1)
+ − 127
+ − 128
def processReleasableElement(aContext, aName, aValue, aVerbose):
+ − 129
bldinf = aContext["bldinf"]
+ − 130
mmp = aContext["mmp"]
+ − 131
config = aContext["config"]
+ − 132
+ − 133
platform = ""
+ − 134
variant = ""
+ − 135
configMatchResults = ConfigMatch.match(config)
+ − 136
if configMatchResults:
+ − 137
platform = configMatchResults.group('PLATFORM')
+ − 138
variant = configMatchResults.group('VARIANT')
+ − 139
if configMatchResults.group('PLATFORMADD'):
+ − 140
platform += configMatchResults.group('PLATFORMADD')
+ − 141
+ − 142
if not BuildReleasables.has_key(bldinf):
+ − 143
BuildReleasables[bldinf] = ComponentReleasable(bldinf, aVerbose)
+ − 144
+ − 145
componentReleasable = BuildReleasables[bldinf]
+ − 146
+ − 147
if aName == "export" :
+ − 148
componentReleasable.AddExport(aValue["destination"], aValue["source"])
+ − 149
elif aName == "member":
+ − 150
componentReleasable.AddExport(aValue.keys()[0], aContext["zipfile"])
+ − 151
elif aName == "build":
+ − 152
componentReleasable.AddBuildOutput(aValue.keys()[0], platform, variant)
+ − 153
elif aName == "resource" or aName == "bitmap":
+ − 154
item = aValue.keys()[0]
+ − 155
# Identify winscw urel/udeb specific resources, and store accordingly
+ − 156
winscwTreeMatchResult = WinscwTreeMatch.search(item)
+ − 157
if platform == "winscw" and winscwTreeMatchResult:
+ − 158
componentReleasable.AddBuildOutput(item, platform, winscwTreeMatchResult.group("VARIANT").lower())
+ − 159
else:
+ − 160
componentReleasable.AddBuildOutput(item, platform)
+ − 161
elif aName == "stringtable":
+ − 162
componentReleasable.AddBuildOutput(aValue.keys()[0])
+ − 163
+ − 164
def parseLog(aLog, aVerbose):
+ − 165
if not os.path.exists(aLog):
+ − 166
error("Log file %s does not exist." % aLog)
+ − 167
+ − 168
parser = xml.parsers.expat.ParserCreate()
+ − 169
parser.buffer_text = True
+ − 170
+ − 171
elementContext = {}
+ − 172
currentElement = []
+ − 173
+ − 174
def start_element(name, attributes):
+ − 175
if name == "whatlog" or name == "archive":
+ − 176
elementContext.update(attributes)
+ − 177
elif elementContext.has_key("bldinf"):
+ − 178
if name == "export":
+ − 179
# Exports are all attributes, so deal with them directly
+ − 180
processReleasableElement(elementContext, name, attributes, aVerbose)
+ − 181
else:
+ − 182
# Other elements wrap values, get these later
+ − 183
currentElement.append(name)
+ − 184
+ − 185
def end_element(name):
+ − 186
if name == "whatlog":
+ − 187
elementContext.clear()
+ − 188
elif name == "archive":
+ − 189
del elementContext["zipfile"]
+ − 190
+ − 191
def char_data(data):
+ − 192
if elementContext.has_key("bldinf") and currentElement:
+ − 193
processReleasableElement(elementContext, currentElement.pop(), {str(data):1}, aVerbose)
+ − 194
+ − 195
parser.StartElementHandler = start_element
+ − 196
parser.EndElementHandler = end_element
+ − 197
parser.CharacterDataHandler = char_data
+ − 198
+ − 199
try:
+ − 200
if aVerbose:
+ − 201
print "Parsing: " + aLog
+ − 202
+ − 203
parser.ParseFile(open(aLog, "r"))
+ − 204
except xml.parsers.expat.ExpatError, e:
+ − 205
error("Failure parsing log file \'%s\' (line %s)" % (aLog, e.lineno))
+ − 206
+ − 207
def normFileForCache(aFile):
+ − 208
normedFile = WinDriveMatch.sub("",aFile)
+ − 209
normedFile = normedFile.replace("/", "\\")
+ − 210
normedFile = normedFile.replace("\\", "\\\\")
+ − 211
normedFile = normedFile.replace("\\\\\\\\", "\\\\")
+ − 212
normedFile = normedFile.replace("\"", "")
+ − 213
return normedFile
+ − 214
+ − 215
def dumpCacheFileList(aCacheFileObject, aItems, aPairs=False):
+ − 216
numItems = len(aItems)
+ − 217
suffix = ",\n"
+ − 218
+ − 219
aCacheFileObject.write(CacheListOpen)
+ − 220
for item in aItems:
+ − 221
if aItems.index(item) == numItems-1:
+ − 222
suffix = "\n"
+ − 223
if aPairs:
+ − 224
aCacheFileObject.write((CacheListItemPair % (normFileForCache(item[0]), normFileForCache(item[1]))) + suffix)
+ − 225
else:
+ − 226
aCacheFileObject.write((CacheListItem % normFileForCache(item)) + suffix)
+ − 227
aCacheFileObject.write(CacheListClose)
+ − 228
+ − 229
def createCacheFile(aComponentReleasable, aOutputPath, aSourceExports, aVerbose):
+ − 230
if not aComponentReleasable.HasReleasables():
+ − 231
return
+ − 232
+ − 233
cacheFileDir = os.path.normpath(\
+ − 234
os.path.join(aOutputPath, \
+ − 235
WinDriveMatch.sub("",os.path.dirname(aComponentReleasable.GetBldInf())).lstrip(r'/').lstrip(r'\\')))
+ − 236
cacheFile = os.path.join(cacheFileDir, "cache")
+ − 237
+ − 238
bldInfLoc = WinDriveMatch.sub("",os.path.dirname(aComponentReleasable.GetBldInf())).replace("/", "\\")
+ − 239
+ − 240
if aVerbose:
+ − 241
print "Creating: " + cacheFile
+ − 242
+ − 243
if not os.path.exists(cacheFileDir):
+ − 244
os.makedirs(cacheFileDir)
+ − 245
+ − 246
try:
+ − 247
cacheFileObject = open(cacheFile, 'w')
+ − 248
+ − 249
exports = aComponentReleasable.GetExports()
+ − 250
if exports:
+ − 251
cacheFileObject.write(CacheExportGroup % bldInfLoc)
+ − 252
if aSourceExports:
+ − 253
dumpCacheFileList(cacheFileObject, exports.items(), True)
+ − 254
else:
+ − 255
dumpCacheFileList(cacheFileObject, exports.keys())
+ − 256
+ − 257
buildOutput = aComponentReleasable.GetBuildOutput()
+ − 258
if buildOutput:
+ − 259
for plat in buildOutput.keys():
+ − 260
# Most cache output is represented as if performed for the "abld target" phase, but tools platforms
+ − 261
# are presented as if performed by "abld build", and so must additionally replicate any exports
+ − 262
# performed for the component in their variant output
+ − 263
phase = "target"
+ − 264
additionalOutput = []
+ − 265
if plat == "tools" or plat == "tools2":
+ − 266
phase = "build"
+ − 267
if exports:
+ − 268
additionalOutput = exports.keys()
+ − 269
+ − 270
for variant in buildOutput[plat].keys():
+ − 271
cacheFileObject.write(CacheBuildOutputGroup % (bldInfLoc, phase, plat, variant))
+ − 272
dumpCacheFileList(cacheFileObject, buildOutput[plat][variant].keys() + additionalOutput)
+ − 273
+ − 274
cacheFileObject.write(CachePlatsGroup)
+ − 275
dumpCacheFileList(cacheFileObject, aComponentReleasable.GetPlatforms().keys())
+ − 276
+ − 277
cacheFileObject.close()
+ − 278
except IOError:
+ − 279
error("Failure creating cache file %s." % cacheFile)
+ − 280
+ − 281
+ − 282
def main():
+ − 283
parser = OptionParser(prog="sbsv2cache.py")
+ − 284
parser.add_option("-l", "--log", action="append", dest="logs", help="log file to parse for <whatlog/> wrapped content.")
+ − 285
parser.add_option("-o", "--outputpath", action="store", dest="outputpath", help="root location to generate cache files.")
+ − 286
parser.add_option("-s", "--sourceexports", action="store_true", default=False, dest="sourceexports", help="generate cache files where each element in the export array is a ['destination', 'source'] array rather than just a 'destination' element.")
+ − 287
parser.add_option("-v", "--verbose", action="store_true", default=False, dest="verbose", help="provide more information as things happen.")
+ − 288
+ − 289
(options, leftover_args) = parser.parse_args(sys.argv[1:])
+ − 290
+ − 291
if leftover_args or not options.logs or not options.outputpath:
+ − 292
parser.print_help()
+ − 293
sys.exit(1)
+ − 294
+ − 295
print "sbsv2cache: started"
+ − 296
+ − 297
# Parse build logs to populate the BuildReleasables dictionary
+ − 298
for log in options.logs:
+ − 299
parseLog(os.path.abspath(log), options.verbose)
+ − 300
+ − 301
# Finalise components in BuildReleasables and create cache files as we go
+ − 302
for component in BuildReleasables.keys():
+ − 303
BuildReleasables[component].Finalise()
+ − 304
createCacheFile(BuildReleasables[component], os.path.abspath(options.outputpath), options.sourceexports, options.verbose)
+ − 305
+ − 306
print "sbsv2cache: finished"
+ − 307
+ − 308
if __name__ == "__main__":
+ − 309
main()
+ − 310
+ − 311