raptor_api.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. #
  2. # Copyright (c) 2010 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. #
  16. # raptor_api module
  17. #
  18. # Python API for Raptor. External code should interact with Raptor via this
  19. # module only, as it is the only programatic interface considered public. The
  20. # command line --query option is also implemented using this module.
  21. # constants
  22. ALL = 1
  23. # objects
  24. class Reply(object):
  25. """object to return values from API calls.
  26. """
  27. def __init__(self, text="", raptor=None):
  28. self._raptor = raptor
  29. self.text = text
  30. def _getEvaluator(self, meaning):
  31. """ Note: Will pass on Evaluator constructor exceptions """
  32. try:
  33. return self.__evaluator
  34. except AttributeError:
  35. # create an evaluator for the named configuration
  36. tmp = raptor_data.Alias("tmp")
  37. tmp.SetProperty("meaning", meaning)
  38. units = tmp.GenerateBuildUnits(self._raptor.cache)
  39. self.__evaluator = self._raptor.GetEvaluator(None, units[0])
  40. return self.__evaluator
  41. def __str__(self):
  42. name = type(self).__name__.lower()
  43. string = "<" + name
  44. children = []
  45. longend = False
  46. for attribute,value in self.__dict__.items():
  47. if attribute != "text" and not attribute.startswith('_'):
  48. if isinstance(value, Reply):
  49. children.append(value)
  50. elif isinstance(value, list):
  51. for item in value:
  52. if isinstance(item, Reply):
  53. children.append(item)
  54. else:
  55. raise BadReply(str(item)+" is not a Reply object")
  56. else:
  57. if value != None: # skip attributes whose value is None
  58. string += " %s='%s'" % (attribute, value)
  59. if children or self.text:
  60. string += ">"
  61. longend = True
  62. if self.text:
  63. string += self.text
  64. children.sort()
  65. # Note mixing sortable and unsortable lists results in
  66. # sort not working, so if you really need your
  67. # children to come out in the right order, put them in
  68. # a list. This is only for niceness, where it works.
  69. if children:
  70. string += "\n"
  71. for c in children:
  72. clines = str(c).rstrip().split("\n")
  73. string += "".join(map(lambda l:" "+l+"\n",clines))
  74. if longend:
  75. string += "</%s>\n" % name
  76. else:
  77. string += "/>\n"
  78. return string
  79. class BadReply(Exception):
  80. pass
  81. class Alias(Reply):
  82. def __init__(self, name, meaning):
  83. super(Alias,self).__init__()
  84. self.name = name
  85. self.meaning = meaning
  86. def __cmp__(self, other):
  87. """ Add __cmp__ to enable comparisons between two Alias objects based upon name."""
  88. return cmp(self.name, other.name)
  89. class Config(Reply):
  90. def __init__(self, raptor, name, text = None):
  91. """ Constructor to create a Config from a user-supplied name.
  92. possibly including aliases (but not groups)
  93. """
  94. super(Config,self).__init__(text, raptor)
  95. self.query = name
  96. # Work out the real name
  97. names = name.split(".")
  98. if names[0] in self._raptor.cache.aliases:
  99. x = self._raptor.cache.FindNamedAlias(names[0])
  100. if len(names) > 1:
  101. self.meaning = x.meaning + "." + ".".join(names[1:])
  102. else:
  103. self.meaning = x.meaning
  104. elif names[0] in self._raptor.cache.variants:
  105. self.meaning = name
  106. else:
  107. raise BadQuery("'%s' is not an alias or a variant" % names[0])
  108. def resolveOutputPath(self):
  109. """ Get the outputpath """
  110. try:
  111. evaluator = self._getEvaluator(self.meaning)
  112. # This is messy as some configs construct the path inside the FLM
  113. # rather than talking it from the XML: usually because of some
  114. # conditional logic... but maybe some refactoring could avoid that.
  115. releasepath = evaluator.Get("RELEASEPATH")
  116. if not releasepath:
  117. raise BadQuery("could not get RELEASEPATH for config '%s'" % self.fullname)
  118. variantplatform = evaluator.Get("VARIANTPLATFORM")
  119. varianttype = evaluator.Get("VARIANTTYPE")
  120. featurevariantname = evaluator.Get("FEATUREVARIANTNAME")
  121. platform = evaluator.Get("TRADITIONAL_PLATFORM")
  122. if platform == "TOOLS2":
  123. self.outputpath = releasepath
  124. else:
  125. if not variantplatform:
  126. raise BadQuery("could not get VARIANTPLATFORM for config '%s'" % self.fullname)
  127. if featurevariantname:
  128. variantplatform += featurevariantname
  129. if not varianttype:
  130. raise BadQuery("could not get VARIANTTYPE for config '%s'" % self.fullname)
  131. self.outputpath = str(generic_path.Join(releasepath, variantplatform, varianttype))
  132. except Exception, e: # Unable to determine output path
  133. self.text = str(e)
  134. def resolveMetadata(self):
  135. try:
  136. metadata = self.metadata
  137. except AttributeError:
  138. metadata = MetaData(self.meaning, self._raptor)
  139. self.metadata = metadata
  140. try:
  141. metadata.resolve()
  142. except Exception:
  143. # Evaluator exception hopefully - already handled
  144. self.metadata = None
  145. def resolveBuild(self):
  146. try:
  147. build = self.build
  148. except AttributeError:
  149. build = Build(self.meaning, self._raptor)
  150. self.build = build
  151. try:
  152. build.resolve()
  153. except Exception:
  154. # Evaluator exception, hopefully - already handled
  155. self.build = None
  156. def resolveTargettypes(self):
  157. try:
  158. build = self.build
  159. except AttributeError:
  160. build = Build(self.meaning, self._raptor)
  161. self.build = build
  162. try:
  163. build.resolveTargettypes()
  164. except Exception:
  165. # Evaluator exception hopefully - already handled
  166. self.build = None
  167. class MetaData(Reply):
  168. def __init__(self, meaning, raptor):
  169. super(MetaData,self).__init__("", raptor)
  170. self.__meaning = meaning
  171. def resolve(self):
  172. includepaths = []
  173. preincludeheader = ""
  174. platmacros = []
  175. evaluator = self._getEvaluator(self.__meaning)
  176. # Initialise data and metadata objects
  177. buildunits = raptor_data.GetBuildUnits([self.__meaning], self._raptor.cache, self._raptor)
  178. metareader = raptor_meta.MetaReader(self._raptor, buildunits)
  179. metadatafile = raptor_meta.MetaDataFile(generic_path.Path("bld.inf"), "cpp", [], None, self._raptor)
  180. # There is only one build platform here; obtain the pre-processing include paths,
  181. # OS pre-include file, compiler pre-include file and macros.
  182. includepaths = metadatafile.preparePreProcessorIncludePaths(metareader.BuildPlatforms[0])
  183. preincludeheader = metareader.BuildPlatforms[0]['VARIANT_HRH']
  184. # Macros arrive as a a list of strings, or a single string, containing definitions of the form "name" or "name=value".
  185. platmacrolist = metadatafile.preparePreProcessorMacros(metareader.BuildPlatforms[0])
  186. platmacros.extend(map(lambda macrodef: [macrodef.partition("=")[0], macrodef.partition("=")[2]], platmacrolist))
  187. # Add child elements to appropriate areas if they were calculated
  188. if len(includepaths) > 0:
  189. self.includepaths = map(lambda x: Include(str(x)), includepaths)
  190. if preincludeheader != "":
  191. self.preincludeheader = PreInclude(str(preincludeheader))
  192. if len(platmacros):
  193. self.platmacros = map(lambda x: Macro(x[0],x[1]) if x[1] else Macro(x[0]), platmacros)
  194. class Build(Reply):
  195. def __init__(self, meaning, raptor):
  196. super(Build,self).__init__("", raptor)
  197. self.__meaning = meaning
  198. def resolve(self):
  199. compilerpreincludeheader = ""
  200. sourcemacros = []
  201. evaluator = self._getEvaluator(self.__meaning)
  202. platform = evaluator.Get("TRADITIONAL_PLATFORM")
  203. # Compiler preinclude files may or may not be present, depending on the configuration.
  204. if evaluator.Get("PREINCLUDE"):
  205. compilerpreincludeheader = generic_path.Path(evaluator.Get("PREINCLUDE"))
  206. # Macros arrive as a a list of strings, or a single string, containing definitions of the form "name" or "name=value".
  207. # If required, we split to a list, and then processes the constituent parts of the macro.
  208. sourcemacrolist = evaluator.Get("CDEFS").split()
  209. sourcemacros.extend(map(lambda macrodef: [macrodef.partition("=")[0], macrodef.partition("=")[2]], sourcemacrolist))
  210. if platform == "TOOLS2":
  211. # Source macros are determined in the FLM for tools2 builds, therefore we have to
  212. # mimic the logic here
  213. if 'win' in raptor.hostplatform or 'win32' in self.__meaning:
  214. sourcemacrolist = evaluator.Get("CDEFS.WIN32").split()
  215. else:
  216. sourcemacrolist = evaluator.Get("CDEFS.LINUX").split()
  217. sourcemacros.extend(map(lambda macrodef: [macrodef.partition("=")[0], macrodef.partition("=")[2]], sourcemacrolist))
  218. if len(sourcemacros):
  219. self.sourcemacros = map(lambda x: Macro(x[0],x[1]) if x[1] else Macro(x[0]), sourcemacros)
  220. if compilerpreincludeheader:
  221. self.compilerpreincludeheader = PreInclude(str(compilerpreincludeheader))
  222. def resolveTargettypes(self):
  223. evaluator = self._getEvaluator(self.__meaning)
  224. targettypes = evaluator.Get("TARGET_TYPES").split(' ')
  225. self.targettypes = []
  226. for type in targettypes:
  227. self.targettypes.append(TargetType(type))
  228. self.targettypes.sort()
  229. class TargetType(Reply):
  230. def __init__(self, name):
  231. super(TargetType,self).__init__()
  232. self.name = name
  233. def __cmp__(self, other):
  234. return cmp(self.name, other.name)
  235. class Product(Reply):
  236. def __init__(self, name):
  237. super(Product,self).__init__()
  238. self.name = name
  239. def __cmp__(self, other):
  240. """ Add __cmp__ to enable comparisons between two Product objects based upon name."""
  241. return cmp(self.name, other.name)
  242. class Include(Reply):
  243. def __init__(self, path):
  244. super(Include,self).__init__()
  245. self.path = path
  246. class PreInclude(Reply):
  247. def __init__(self, file):
  248. super(PreInclude,self).__init__()
  249. self.file = file
  250. class Macro(Reply):
  251. def __init__(self, name, value=None):
  252. super(Macro,self).__init__()
  253. self.name = name
  254. self.value = value
  255. import generic_path
  256. import raptor
  257. import raptor_data
  258. import raptor_meta
  259. import re
  260. class Context(object):
  261. """object to contain state information for API calls.
  262. For example,
  263. api = raptor_api.Context()
  264. val = api.getaliases("X")
  265. """
  266. def __init__(self, initialiser=None):
  267. # this object has a private Raptor object that can either be
  268. # passed in or created internally.
  269. if initialiser == None:
  270. self.__raptor = raptor.Raptor()
  271. else:
  272. self.__raptor = initialiser
  273. def stringquery(self, query):
  274. """turn a string into an API call and execute it.
  275. This is a convenience method for "lazy" callers.
  276. The return value is also converted into a well-formed XML string.
  277. """
  278. if query == "aliases":
  279. aliases = self.getaliases()
  280. return "".join(map(str, aliases)).strip()
  281. elif query == "products":
  282. variants = self.getproducts()
  283. return "".join(map(str, variants)).strip()
  284. elif query.startswith("config"):
  285. match = re.match("config\[(.*)\]", query)
  286. if match:
  287. config = self.getconfig(match.group(1))
  288. return str(config).strip()
  289. else:
  290. raise BadQuery("syntax error")
  291. raise BadQuery("unknown query")
  292. def getaliases(self, type=""):
  293. """extract all aliases of a given type.
  294. the default type is "".
  295. to get all aliases pass type=ALL
  296. """
  297. aliases = []
  298. for a in self.__raptor.cache.aliases.values():
  299. if type == ALL or a.type == type:
  300. # copy the members we want to expose
  301. aliases.append( Alias(a.name, a.meaning) )
  302. aliases.sort()
  303. return aliases
  304. def getconfig(self, name):
  305. """extract the values for a given configuration.
  306. 'name' should be an alias or variant followed optionally by a
  307. dot-separated list of variants. For example "armv5_urel" or
  308. "armv5_urel.savespace.vasco".
  309. """
  310. config = Config(self.__raptor, name)
  311. config.resolveOutputPath()
  312. config.resolveTargettypes()
  313. config.resolveMetadata()
  314. config.resolveBuild()
  315. return config
  316. def getproducts(self):
  317. """extract all product variants."""
  318. variants = []
  319. for v in self.__raptor.cache.variants.values():
  320. if v.type == "product":
  321. # copy the members we want to expose
  322. variants.append( Product(v.name) )
  323. variants.sort()
  324. return variants
  325. class BadQuery(Exception):
  326. pass
  327. # end of the raptor_api module