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