sbsv2/raptor/python/raptor_data.py
branchwip
changeset 5 593a8820b912
parent 3 e1eecf4d390d
child 60 28ee654acf42
equal deleted inserted replaced
3:e1eecf4d390d 5:593a8820b912
    25 import types
    25 import types
    26 import sys
    26 import sys
    27 import subprocess
    27 import subprocess
    28 from tempfile import gettempdir
    28 from tempfile import gettempdir
    29 from time import time, clock
    29 from time import time, clock
    30 
    30 import traceback
    31 
    31 import raptor_cache
       
    32 
       
    33 
       
    34 class MissingInterfaceError(Exception):
       
    35 	def __init__(self, s):
       
    36 		Exception.__init__(self,s)
    32 
    37 
    33 # What host platforms we recognise
    38 # What host platforms we recognise
    34 # This allows us to tie some variants to one host platform and some to another
    39 # This allows us to tie some variants to one host platform and some to another
    35 class HostPlatform(object):
    40 class HostPlatform(object):
    36 	""" List the host platforms on which we can build.  Allow configuration
    41 	""" List the host platforms on which we can build.  Allow configuration
    66 # raptor_data module classes
    71 # raptor_data module classes
    67 
    72 
    68 class Model(object):
    73 class Model(object):
    69 	"Base class for data-model objects"
    74 	"Base class for data-model objects"
    70 
    75 
       
    76 	__slots__ = ('host', 'source', 'cacheID')
       
    77 
    71 	def __init__(self):
    78 	def __init__(self):
    72 		self.owner = None	# Raptor object
       
    73 		self.source = None	# XML file
    79 		self.source = None	# XML file
    74 		self.indent = " "	# for DebugPrint
       
    75 		self.host = None
    80 		self.host = None
    76 		self.cacheID = ""	# default set of cached objects
    81 		self.cacheID = ""	# default set of cached objects
    77 
    82 		# not using the cache parameter - there to make the 
    78 
    83 		# init for all Model objects "standard"
    79 	def SetOwner(self, aRaptor):
       
    80 		self.owner = aRaptor
       
    81 
    84 
    82 
    85 
    83 	def SetSourceFile(self, filename):
    86 	def SetSourceFile(self, filename):
    84 		self.source = filename
    87 		self.source = filename
    85 
    88 
    89 
    92 
    90 
    93 
    91 	def AddChild(self, child):
    94 	def AddChild(self, child):
    92 		raise InvalidChildError()
    95 		raise InvalidChildError()
    93 
    96 
    94 
       
    95 	def DebugPrint(self, prefix = ""):
       
    96 		if self.owner:
       
    97 			self.owner.Debug("%s", prefix)
       
    98 
    97 
    99 	def Valid(self):
    98 	def Valid(self):
   100 		return False
    99 		return False
   101 
   100 
   102 	def IsApplicable(self):
   101 	def IsApplicable(self):
   137 			raise InvalidPropertyError()
   136 			raise InvalidPropertyError()
   138 
   137 
   139 	def Resolve(self):
   138 	def Resolve(self):
   140 		raise BadReferenceError()
   139 		raise BadReferenceError()
   141 
   140 
   142 	def GetModifiers(self):
   141 	def GetModifiers(self, cache):
   143 		cache = self.owner.cache
       
   144 		return [ cache.FindNamedVariant(m) for m in self.modifiers ]
   142 		return [ cache.FindNamedVariant(m) for m in self.modifiers ]
   145 
   143 
   146 	def Valid(self):
   144 	def Valid(self):
   147 		return self.ref
   145 		return self.ref
   148 
   146 
   152 	def __init__(self):
   150 	def __init__(self):
   153 		Model.__init__(self)	# base class constructor
   151 		Model.__init__(self)	# base class constructor
   154 		self.variants = []
   152 		self.variants = []
   155 
   153 
   156 
   154 
   157 	def SetOwner(self, aRaptor):
   155 	def __str__(self):
   158 		Model.SetOwner(self, aRaptor)
   156 		return "\n".join([str(v) for v in self.variants])
   159 		for v in self.variants:
       
   160 			v.SetOwner(aRaptor)
       
   161 
       
   162 
       
   163 	def DebugPrint(self, prefix = ""):
       
   164 		for v in self.variants:
       
   165 			v.DebugPrint(prefix)
       
   166 
   157 
   167 
   158 
   168 	def AddVariant(self, variant):
   159 	def AddVariant(self, variant):
   169 		if type(variant) is types.StringTypes:
   160 		if type(variant) is types.StringTypes:
   170 			variant = VariantRef(variant)
   161 			variant = VariantRef(ref = variant)
   171 
   162 
   172 
   163 
   173 		# Only add the variant if it's not in the list
   164 		# Only add the variant if it's not in the list
   174 		# already
   165 		# already
   175 		if not variant in self.variants:
   166 		if not variant in self.variants:
   176 			self.variants.append(variant)
   167 			self.variants.append(variant)
   177 
   168 
   178 	def GetVariants(self):
   169 	def GetVariants(self, cache):
   179 		# resolve any VariantRef objects into Variant objects
   170 		# resolve any VariantRef objects into Variant objects
       
   171 		missing_variants = []
   180 		for i,var in enumerate(self.variants):
   172 		for i,var in enumerate(self.variants):
   181 			if isinstance(var, Reference):
   173 			if isinstance(var, Reference):
   182 				try:
   174 				try:
   183 					self.variants[i] = var.Resolve()
   175 					self.variants[i] = var.Resolve(cache=cache)
   184 
   176 
   185 				except BadReferenceError:
   177 				except BadReferenceError:
   186 					self.owner.Error("Missing variant '%s'", var.ref)
   178 					missing_variants.append(var.ref)
       
   179 
       
   180 		if len(missing_variants) > 0:
       
   181 			raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants))
   187 
   182 
   188 		return self.variants
   183 		return self.variants
   189 
   184 
   190 
   185 
   191 class Interface(Model):
   186 class Interface(Model):
   197 		self.abstract = False
   192 		self.abstract = False
   198 		self.extends = None
   193 		self.extends = None
   199 		self.params = []
   194 		self.params = []
   200 		self.paramgroups = []
   195 		self.paramgroups = []
   201 
   196 
   202 	def DebugPrint(self, prefix = ""):
   197 	def __str__(self):
   203 		self.owner.Debug("%s<interface name='%s'>", prefix, self.name)
   198 		return "<interface name='%s'>" % self.name + "</interface>"
   204 		self.owner.Debug("%s...", prefix)
   199 
   205 		self.owner.Debug("%s</interface>", prefix)
   200 	def FindParent(self, cache):
   206 
       
   207 	def FindParent(self):
       
   208 		try:
   201 		try:
   209 			return self.owner.cache.FindNamedInterface(self.extends, self.cacheID)
   202 			return cache.FindNamedInterface(self.extends, self.cacheID)
   210 		except KeyError:
   203 		except KeyError:
   211 			raise BadReferenceError("Cannot extend interface because it cannot be found: "+str(self.extends))
   204 			raise BadReferenceError("Cannot extend interface because it cannot be found: "+str(self.extends))
   212 
   205 
   213 	def GetParams(self):
   206 	def GetParams(self, cache):
   214 		if self.extends != None:
   207 		if self.extends != None:
   215 			parent = self.FindParent()
   208 			parent = self.FindParent(cache)
   216 
   209 
   217 			# what parameter names do we have already?
   210 			# what parameter names do we have already?
   218 			names = set([x.name for x in self.params])
   211 			names = set([x.name for x in self.params])
   219 
   212 
   220 			# pick up ones we don't have that are in our parent
   213 			# pick up ones we don't have that are in our parent
   221 			pp = []
   214 			pp = []
   222 			for p in parent.GetParams():
   215 			for p in parent.GetParams(cache):
   223 				if not p.name in names:
   216 				if not p.name in names:
   224 					pp.append(p)
   217 					pp.append(p)
   225 
   218 
   226 			# list parent parameters first then ours
   219 			# list parent parameters first then ours
   227 			pp.extend(self.params)
   220 			pp.extend(self.params)
   228 			return pp
   221 			return pp
   229 
   222 
   230 		return self.params
   223 		return self.params
   231 
   224 
   232 	def GetParamGroups(self):
   225 	def GetParamGroups(self, cache):
   233 		if self.extends != None:
   226 		if self.extends != None:
   234 			parent = self.FindParent()
   227 			parent = self.FindParent(cache)
   235 
   228 
   236 			# what parameter names do we have already?
   229 			# what parameter names do we have already?
   237 			patterns = set([x.pattern for x in self.paramgroups])
   230 			patterns = set([x.pattern for x in self.paramgroups])
   238 
   231 
   239 			# pick up ones we don't have that are in our parent
   232 			# pick up ones we don't have that are in our parent
   240 			for g in parent.GetParamGroups():
   233 			for g in parent.GetParamGroups(cache):
   241 				if not g.pattern in patterns:
   234 				if not g.pattern in patterns:
   242 					self.paramgroups.append(g)
   235 					self.paramgroups.append(g)
   243 
   236 
   244 		return self.paramgroups
   237 		return self.paramgroups
   245 
   238 
   246 
   239 
   247 	def GetFLMIncludePath(self):
   240 	def GetFLMIncludePath(self, cache):
   248 		"absolute path to the FLM"
   241 		"absolute path to the FLM"
   249 
   242 
   250 		if self.flm == None:
   243 		if self.flm == None:
   251 			if self.extends != None:
   244 			if self.extends != None:
   252 				parent = self.FindParent()
   245 				parent = self.FindParent(cache)
   253 
   246 
   254 				return parent.GetFLMIncludePath()
   247 				return parent.GetFLMIncludePath(cache)
   255 			else:
   248 			else:
   256 				raise InvalidPropertyError()
   249 				raise InvalidPropertyError()
   257 
   250 
   258 		if not os.path.isabs(self.flm):
   251 		if not os.path.isabs(self.flm):
   259 			self.flm = os.path.join(os.path.dirname(self.source), self.flm)
   252 			self.flm = os.path.join(os.path.dirname(self.source), self.flm)
   293 		return (self.name != None)
   286 		return (self.name != None)
   294 
   287 
   295 
   288 
   296 class InterfaceRef(Reference):
   289 class InterfaceRef(Reference):
   297 
   290 
   298 	def DebugPrint(self, prefix = ""):
   291 	def __str__(self):
   299 		self.owner.Debug("%s<interfaceRef ref='%s'/>", prefix, self.ref)
   292 		return "<interfaceRef ref='%s'/>" % self.ref
   300 
   293 
   301 	def Resolve(self):
   294 	def Resolve(self, cache):
   302 		try:
   295 		try:
   303 			return self.owner.cache.FindNamedInterface(self.ref, self.cacheID)
   296 			return cache.FindNamedInterface(self.ref, self.cacheID)
   304 		except KeyError:
   297 		except KeyError:
   305 			raise BadReferenceError()
   298 			raise BadReferenceError()
   306 
   299 
   307 
   300 
   308 class Specification(VariantContainer):
   301 class Specification(VariantContainer):
   314 		self.interface = None
   307 		self.interface = None
   315 		self.childSpecs = []
   308 		self.childSpecs = []
   316 		self.parentSpec = None
   309 		self.parentSpec = None
   317 
   310 
   318 
   311 
   319 	def DebugPrint(self, prefix = ""):
   312 	def __str__(self):
   320 		self.owner.Debug("%s<spec name='%s'>", prefix, self.name)
   313 		s = "<spec name='%s'>" % str(self.name)
   321 		if self.interface:
   314 		s += VariantContainer.__str__(self)
   322 			self.interface.DebugPrint(prefix + self.indent)
       
   323 		VariantContainer.DebugPrint(self, prefix + self.indent)
       
   324 		for c in self.childSpecs:
   315 		for c in self.childSpecs:
   325 			c.DebugPrint(prefix + self.indent)
   316 			s += str(c) + '\n'
   326 		self.owner.Debug("%s</spec>", prefix)
   317 		s += "</spec>"
   327 
   318 		return s
   328 
       
   329 	def SetOwner(self, aRaptor):
       
   330 		VariantContainer.SetOwner(self, aRaptor)
       
   331 
       
   332 		if self.interface != None:
       
   333 			self.interface.SetOwner(aRaptor)
       
   334 
       
   335 		for s in self.childSpecs:
       
   336 			s.SetOwner(aRaptor)
       
   337 
   319 
   338 
   320 
   339 	def SetProperty(self, name, value):
   321 	def SetProperty(self, name, value):
   340 		if name == "name":
   322 		if name == "name":
   341 			self.name = value
   323 			self.name = value
   342 		else:
   324 		else:
   343 			raise InvalidPropertyError()
   325 			raise InvalidPropertyError()
   344 
   326 
   345 
   327 
   346 	def Configure(self, config):
   328 	def Configure(self, config, cache):
   347 		# configure all the children (some may be Filters or parents of)
   329 		# configure all the children (some may be Filters or parents of)
   348 		for spec in self.GetChildSpecs():
   330 		for spec in self.GetChildSpecs():
   349 			spec.Configure(config)
   331 			spec.Configure(config, cache = cache)
   350 
   332 
   351 
   333 
   352 	def HasInterface(self):
   334 	def HasInterface(self):
   353 		return self.interface != None
   335 		return self.interface != None
   354 
   336 
   356 	def SetInterface(self, interface):
   338 	def SetInterface(self, interface):
   357 		if isinstance(interface, Interface) \
   339 		if isinstance(interface, Interface) \
   358 		or isinstance(interface, InterfaceRef):
   340 		or isinstance(interface, InterfaceRef):
   359 			self.interface = interface
   341 			self.interface = interface
   360 		else:
   342 		else:
   361 			self.interface = InterfaceRef(interface)
   343 			self.interface = InterfaceRef(ref = interface)
   362 
   344 
   363 
   345 
   364 	def GetInterface(self):
   346 	def GetInterface(self, cache):
   365 		"""return the Interface (fetching from the cache if it was a ref)
   347 		"""return the Interface (fetching from the cache if it was a ref)
   366 		may return None"""
   348 		may return None"""
   367 
   349 
   368 		if self.interface == None \
   350 		if self.interface == None \
   369 		or isinstance(self.interface, Interface):
   351 		or isinstance(self.interface, Interface):
   370 			return self.interface
   352 			return self.interface
   371 
   353 
   372 		if isinstance(self.interface, InterfaceRef):
   354 		if isinstance(self.interface, InterfaceRef):
   373 			try:
   355 			try:
   374 				self.interface = self.interface.Resolve()
   356 				self.interface = self.interface.Resolve(cache=cache)
   375 				return self.interface
   357 				return self.interface
   376 
   358 
   377 			except BadReferenceError:
   359 			except BadReferenceError:
   378 				self.owner.Error("Missing interface %s", self.interface.ref)
   360 				raise MissingInterfaceError("Missing interface %s" % self.interface.ref)
   379 				return None
       
   380 
       
   381 
   361 
   382 	def AddChild(self, child):
   362 	def AddChild(self, child):
   383 		if isinstance(child, Specification):
   363 		if isinstance(child, Specification):
   384 			self.AddChildSpecification(child)
   364 			self.AddChildSpecification(child)
   385 		elif isinstance(child, Interface) \
   365 		elif isinstance(child, Interface) \
   407 
   387 
   408 	def Valid(self):
   388 	def Valid(self):
   409 		return True
   389 		return True
   410 
   390 
   411 
   391 
   412 	def GetAllVariantsRecursively(self):
   392 	def GetAllVariantsRecursively(self, cache):
   413 		"""Returns all variants contained in this node and in its ancestors.
   393 		"""Returns all variants contained in this node and in its ancestors.
   414 
   394 
   415 		The returned value is a list, the structure of which is [variants-in-parent,
   395 		The returned value is a list, the structure of which is [variants-in-parent,
   416 		variants-in-self].
   396 		variants-in-self].
   417 
   397 
   418 		Note that the function recurses through parent *Specifications*, not through
   398 		Note that the function recurses through parent *Specifications*, not through
   419 		the variants themselves.
   399 		the variants themselves.
   420 		"""
   400 		"""
   421 		if self.parentSpec:
   401 		if self.parentSpec:
   422 			variants = self.parentSpec.GetAllVariantsRecursively()
   402 			variants = self.parentSpec.GetAllVariantsRecursively(cache = cache)
   423 		else:
   403 		else:
   424 			variants = []
   404 			variants = []
   425 
   405 
   426 		variants.extend( self.GetVariants() )
   406 		variants.extend( self.GetVariants(cache = cache) )
   427 
   407 
   428 		return variants
   408 		return variants
   429 
   409 
   430 
   410 
   431 class Filter(Specification):
   411 class Filter(Specification):
   436 	when the Configure method is called after setting up a Condition.
   416 	when the Configure method is called after setting up a Condition.
   437 
   417 
   438 	If several Conditions are set, the test is an OR of all of them."""
   418 	If several Conditions are set, the test is an OR of all of them."""
   439 
   419 
   440 	def __init__(self, name = ""):
   420 	def __init__(self, name = ""):
   441 		Specification.__init__(self, name)	# base class constructor
   421 		Specification.__init__(self, name = name)	# base class constructor
   442 		self.Else = Specification(name)     # same for Else part
   422 		self.Else = Specification(name = name)     # same for Else part
   443 		self.isTrue = True
   423 		self.isTrue = True
   444 		self.configNames = set()            #
   424 		self.configNames = set()            #
   445 		self.variableNames = set()          # TO DO: Condition class
   425 		self.variableNames = set()          # TO DO: Condition class
   446 		self.variableValues = {}            #
   426 		self.variableValues = {}            #
   447 
   427 
   448 	def DebugPrint(self, prefix = ""):
   428 	def __str__(self, prefix = ""):
   449 		self.owner.Debug("%s<filter name='%s'>", prefix, self.name)
   429 		s = "<filter name='%s'>\n"% self.name
   450 		self.owner.Debug("%s <if config='%s'>", prefix, " | ".join(self.configNames))
   430 		s += "<if config='%s'>\n" % " | ".join(self.configNames)
   451 		Specification.DebugPrint(self, prefix + self.indent)
   431 		s += Specification.__str__(self)
   452 		self.owner.Debug("%s </if>", prefix)
   432 		s += "</if>\n <else>\n"
   453 		self.owner.Debug("%s <else>", prefix)
   433 		s += str(self.Else)
   454 		self.Else.DebugPrint(prefix + self.indent)
   434 		s += " </else>\n</filter>\n"
   455 		self.owner.Debug("%s </else>", prefix)
   435 		return s
   456 		self.owner.Debug("%s</filter>", prefix)
       
   457 
   436 
   458 
   437 
   459 	def SetConfigCondition(self, configName):
   438 	def SetConfigCondition(self, configName):
   460 		self.configNames = set([configName])
   439 		self.configNames = set([configName])
   461 
   440 
   476 			self.variableValues[variableName] = set(variableValues)
   455 			self.variableValues[variableName] = set(variableValues)
   477 		else:
   456 		else:
   478 			self.variableValues[variableName] = set([variableValues])
   457 			self.variableValues[variableName] = set([variableValues])
   479 
   458 
   480 
   459 
   481 	def Configure(self, buildUnit):
   460 	def Configure(self, buildUnit, cache):
   482 		self.isTrue = False
   461 		self.isTrue = False
   483 
   462 
   484 		if buildUnit.name in self.configNames:
   463 		if buildUnit.name in self.configNames:
   485 			self.isTrue = True
   464 			self.isTrue = True
   486 		elif self.variableNames:
   465 		elif self.variableNames:
   487 			evaluator = self.owner.GetEvaluator(self.parentSpec, buildUnit)
   466 
       
   467 			evaluator = Evaluator(self.parentSpec, buildUnit, cache=cache)
   488 
   468 
   489 			for variableName in self.variableNames:
   469 			for variableName in self.variableNames:
   490 				variableValue = evaluator.Get(variableName)
   470 				variableValue = evaluator.Get(variableName)
   491 
   471 
   492 				if variableValue in self.variableValues[variableName]:
   472 				if variableValue in self.variableValues[variableName]:
   493 					self.isTrue = True
   473 					self.isTrue = True
   494 					break
   474 					break
   495 
   475 
   496 		# configure all the children too
   476 		# configure all the children too
   497 		for spec in self.GetChildSpecs():
   477 		for spec in self.GetChildSpecs():
   498 			spec.Configure(buildUnit)
   478 			spec.Configure(buildUnit, cache=cache)
   499 
       
   500 
       
   501 	def SetOwner(self, aRaptor):
       
   502 		# base class method
       
   503 		Specification.SetOwner(self, aRaptor)
       
   504 		# same for Else part
       
   505 		self.Else.SetOwner(aRaptor)
       
   506 
   479 
   507 
   480 
   508 	def HasInterface(self):
   481 	def HasInterface(self):
   509 		if self.isTrue:
   482 		if self.isTrue:
   510 			return Specification.HasInterface(self)
   483 			return Specification.HasInterface(self)
   511 		else:
   484 		else:
   512 			return self.Else.HasInterface()
   485 			return self.Else.HasInterface()
   513 
   486 
   514 
   487 
   515 	def GetInterface(self):
   488 	def GetInterface(self, cache):
   516 		if self.isTrue:
   489 		if self.isTrue:
   517 			return Specification.GetInterface(self)
   490 			return Specification.GetInterface(self, cache = cache)
   518 		else:
   491 		else:
   519 			return self.Else.GetInterface()
   492 			return self.Else.GetInterface(cache = cache)
   520 
   493 
   521 
   494 
   522 	def GetVariants(self):
   495 	def GetVariants(self, cache):
   523 		if self.isTrue:
   496 		if self.isTrue:
   524 			return Specification.GetVariants(self)
   497 			return Specification.GetVariants(self, cache = cache)
   525 		else:
   498 		else:
   526 			return self.Else.GetVariants()
   499 			return self.Else.GetVariants(cache = cache)
   527 
   500 
   528 
   501 
   529 	def SetParentSpec(self, parent):
   502 	def SetParentSpec(self, parent):
   530 		# base class method
   503 		# base class method
   531 		Specification.SetParentSpec(self, parent)
   504 		Specification.SetParentSpec(self, parent)
   589 		return (self.pattern != None and self.patternre != None)
   562 		return (self.pattern != None and self.patternre != None)
   590 
   563 
   591 
   564 
   592 class Operation(Model):
   565 class Operation(Model):
   593 	"Base class for variant operations"
   566 	"Base class for variant operations"
       
   567 	__slots__ = 'type'
   594 	def __init__(self):
   568 	def __init__(self):
   595 		Model.__init__(self)	# base class constructor
   569 		Model.__init__(self)	# base class constructor
   596 		self.type = None
   570 		self.type = None
   597 
   571 
   598 
       
   599 	def Apply(self, oldValue):
   572 	def Apply(self, oldValue):
   600 		pass
   573 		pass
   601 
   574 
   602 
   575 
   603 class Append(Operation):
   576 class Append(Operation):
   604 	__slots__ = ('name','value','separator','owner')
   577 	__slots__ = ('name', 'value', 'separator')
   605 
       
   606 	def __init__(self, name = None, value = None, separator = " "):
   578 	def __init__(self, name = None, value = None, separator = " "):
   607 		Operation.__init__(self)	# base class constructor
   579 		Operation.__init__(self)	# base class constructor
   608 		self.name = name
   580 		self.name = name
   609 		self.value = value
   581 		self.value = value
   610 		self.separator = separator
   582 		self.separator = separator
   611 
   583 
   612 
   584 
   613 	def DebugPrint(self, prefix = ""):
   585 	def __str__(self):
   614 		attributes = "name='" + self.name + "' value='" + self.value + "' separator='" + self.separator + "'"
   586 		attributes = "name='" + self.name + "' value='" + self.value + "' separator='" + self.separator + "'"
   615 		self.owner.Debug("%s<append %s/>", prefix, attributes)
   587 		return "<append %s/>" % attributes
   616 
   588 
   617 
   589 
   618 	def Apply(self, oldValue):
   590 	def Apply(self, oldValue):
   619 		if len(oldValue) > 0:
   591 		if len(oldValue) > 0:
   620 			if len(self.value) > 0:
   592 			if len(self.value) > 0:
   639 	def Valid(self):
   611 	def Valid(self):
   640 		return (self.name != None and self.value != None)
   612 		return (self.name != None and self.value != None)
   641 
   613 
   642 
   614 
   643 class Prepend(Operation):
   615 class Prepend(Operation):
       
   616 	__slots__ = ('name', 'value', 'separator')
   644 	def __init__(self, name = None, value = None, separator = " "):
   617 	def __init__(self, name = None, value = None, separator = " "):
   645 		Operation.__init__(self)	# base class constructor
   618 		Operation.__init__(self)	# base class constructor
   646 		self.name = name
   619 		self.name = name
   647 		self.value = value
   620 		self.value = value
   648 		self.separator = separator
   621 		self.separator = separator
   649 
   622 
   650 
   623 
   651 	def DebugPrint(self, prefix = ""):
   624 	def __str__(self, prefix = ""):
   652 		attributes = "name='" + self.name + "' value='" + self.value + "' separator='" + self.separator + "'"
   625 		attributes = "name='" + self.name + "' value='" + self.value + "' separator='" + self.separator + "'"
   653 		self.owner.Debug("%s<prepend %s/>", prefix, attributes)
   626 		return "<prepend %s/>" % prefix
   654 
   627 
   655 
   628 
   656 	def Apply(self, oldValue):
   629 	def Apply(self, oldValue):
   657 		if len(oldValue) > 0:
   630 		if len(oldValue) > 0:
   658 			if len(self.value) > 0:
   631 			if len(self.value) > 0:
   677 	def Valid(self):
   650 	def Valid(self):
   678 		return (self.name != None and self.value != None)
   651 		return (self.name != None and self.value != None)
   679 
   652 
   680 
   653 
   681 class Set(Operation):
   654 class Set(Operation):
       
   655 	__slots__ = ('name', 'value', 'type', 'versionCommand', 'versionResult')
   682 	"""implementation of <set> operation"""
   656 	"""implementation of <set> operation"""
   683 	__slots__ = ('name','value', 'type', 'versionCommand', 'versionResult', 'owner')
       
   684 
   657 
   685 	def __init__(self, name = None, value = "", type = ""):
   658 	def __init__(self, name = None, value = "", type = ""):
   686 		Operation.__init__(self)	# base class constructor
   659 		Operation.__init__(self)	# base class constructor
   687 		self.name = name
   660 		self.name = name
   688 		self.value = value
   661 		self.value = value
   689 		self.type = type
   662 		self.type = type
   690 		self.versionCommand = ""
   663 		self.versionCommand = ""
   691 		self.versionResult = ""
   664 		self.versionResult = ""
   692 
   665 
   693 
   666 
   694 	def DebugPrint(self, prefix = ""):
   667 	def __str__(self):
   695 		attributes = "name='" + self.name + "' value='" + self.value + "' type='" + self.type + "'"
   668 		attributes = "name='" + self.name + "' value='" + self.value + "' type='" + self.type + "'"
   696 		if type == "tool":
   669 		if type == "tool":
   697 			attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult
   670 			attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult
   698 
   671 
   699 		self.owner.Debug("%s<set %s/>", prefix, attributes)
   672 		return "<set %s/>" % attributes
   700 
   673 
   701 
   674 
   702 	def Apply(self, oldValue):
   675 	def Apply(self, oldValue):
   703 		return self.value
   676 		return self.value
   704 
   677 
   722 
   695 
   723 
   696 
   724 	def Valid(self):
   697 	def Valid(self):
   725 		return (self.name != None and self.value != None)
   698 		return (self.name != None and self.value != None)
   726 
   699 
       
   700 class BadToolValue(Exception):
       
   701 	pass
   727 
   702 
   728 class Env(Set):
   703 class Env(Set):
   729 	"""implementation of <env> operator"""
   704 	"""implementation of <env> operator"""
   730 
   705 
   731 	def __init__(self, name = None, default = None, type = ""):
   706 	def __init__(self, name = None, default = None, type = ""):
   732 		Set.__init__(self, name, "", type)	# base class constructor
   707 		Set.__init__(self, name, "", type)	# base class constructor
   733 		self.default = default
   708 		self.default = default
   734 
   709 
   735 
   710 
   736 	def DebugPrint(self, prefix = ""):
   711 	def __str__(self):
   737 		attributes = "name='" + self.name + "' type='" + self.type + "'"
   712 		attributes = "name='" + self.name + "' type='" + self.type + "'"
   738 		if default != None:
   713 		if default != None:
   739 			attributes += " default='" + self.default + "'"
   714 			attributes += " default='" + self.default + "'"
   740 
   715 
   741 		if type == "tool":
   716 		if type == "tool":
   742 			attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult + "'"
   717 			attributes += " versionCommand='" + self.versionCommand + "' versionResult='" + self.versionResult + "'"
   743 
   718 
   744 		self.owner.Debug("%s<env %s/>", prefix, attributes)
   719 		return "<env %s/>" % attributes
   745 
   720 
   746 
   721 
   747 	def Apply(self, oldValue):
   722 	def Apply(self, oldValue):
   748 		try:
   723 		try:
   749 			value = os.environ[self.name]
   724 			value = os.environ[self.name]
   753 			if value and (self.type == "path" or self.type == "tool"):
   728 			if value and (self.type == "path" or self.type == "tool"):
   754 				try:
   729 				try:
   755 					path = generic_path.Path(value)
   730 					path = generic_path.Path(value)
   756 					value = str(path.Absolute())
   731 					value = str(path.Absolute())
   757 				except ValueError,e:
   732 				except ValueError,e:
   758 					self.owner.Error("the environment variable %s is incorrect: %s" % (self.name, str(e)))
   733 					raise BadToolValue("the environment variable %s is incorrect: %s" % (self.name, str(e)))
   759 					return "NO_VALUE_FOR_" + self.name
       
   760 		except KeyError:
   734 		except KeyError:
   761 			if self.default != None:
   735 			if self.default != None:
   762 				value = self.default
   736 				value = self.default
   763 			else:
   737 			else:
   764 				self.owner.Error("%s is not set in the environment and has no default", self.name)
   738 				raise BadToolValue("%s is not set in the environment and has no default" % self.name)
   765 				return "NO_VALUE_FOR_" + self.name
       
   766 
   739 
   767 		return value
   740 		return value
   768 
   741 
   769 
   742 
   770 	def SetProperty(self, name, value):
   743 	def SetProperty(self, name, value):
   789 
   762 
   790 		# Cache for the variant operations implied by this BuildUnit.
   763 		# Cache for the variant operations implied by this BuildUnit.
   791 		self.operations = []
   764 		self.operations = []
   792 		self.variantKey = ""
   765 		self.variantKey = ""
   793 
   766 
   794 	def GetOperations(self):
   767 	def GetOperations(self, cache):
   795 		"""Return all operations related to this BuildUnit.
   768 		"""Return all operations related to this BuildUnit.
   796 		
   769 		
   797 		The result is cached, and so will only be computed once per BuildUnit.
   770 		The result is cached, and so will only be computed once per BuildUnit.
   798 		"""
   771 		"""
   799 		key = '.'.join([x.name for x in self.variants])
   772 		key = '.'.join([x.name for x in self.variants])
   800 		if self.variantKey != key:
   773 		if self.variantKey != key:
   801 			self.variantKey = key
   774 			self.variantKey = key
   802 			for v in self.variants:
   775 			for v in self.variants:
   803 				self.operations.extend( v.GetAllOperationsRecursively() )
   776 				self.operations.extend( v.GetAllOperationsRecursively(cache=cache) )
   804 
   777 
   805 		return self.operations
   778 		return self.operations
   806 
   779 
   807 class Config(object):
   780 class Config(object):
   808 	"""Abstract type representing an argument to the '-c' option.
   781 	"""Abstract type representing an argument to the '-c' option.
   818 		self.modifiers.append(variant)
   791 		self.modifiers.append(variant)
   819 
   792 
   820 	def ClearModifiers(self):
   793 	def ClearModifiers(self):
   821 		self.modifiers = []
   794 		self.modifiers = []
   822 
   795 
   823 	def GenerateBuildUnits(self):
   796 	def GenerateBuildUnits(self,cache):
   824 		"""Returns a list of BuildUnits.
   797 		"""Returns a list of BuildUnits.
   825 
   798 
   826 		This function must be overridden by derived classes.
   799 		This function must be overridden by derived classes.
   827 		"""
   800 		"""
   828 		raise NotImplementedError()
   801 		raise NotImplementedError()
   829 
   802 
   830 
   803 
   831 class Variant(Model, Config):
   804 class Variant(Model, Config):
       
   805 
       
   806 	__slots__ = ('cache','name','host','extends','ops','variantRefs','allOperations')
   832 
   807 
   833 	def __init__(self, name = ""):
   808 	def __init__(self, name = ""):
   834 		Model.__init__(self)
   809 		Model.__init__(self)
   835 		Config.__init__(self)
   810 		Config.__init__(self)
   836 		self.name = name
   811 		self.name = name
   866 			raise InvalidChildError()
   841 			raise InvalidChildError()
   867 
   842 
   868 	def Valid(self):
   843 	def Valid(self):
   869 		return self.name
   844 		return self.name
   870 
   845 
   871 	def SetOwner(self, aRaptor):
       
   872 
       
   873 		Model.SetOwner(self, aRaptor)
       
   874 
       
   875 		for r in self.variantRefs:
       
   876 			r.SetOwner(aRaptor)
       
   877 
       
   878 		for op in self.ops:
       
   879 			op.SetOwner(aRaptor)
       
   880 
       
   881 	def AddOperation(self, op):
   846 	def AddOperation(self, op):
   882 		self.ops.append(op)
   847 		self.ops.append(op)
   883 
   848 
   884 	def GetAllOperationsRecursively(self):
   849 	def GetAllOperationsRecursively(self, cache):
   885 		"""Returns a list of all operations in this variant.
   850 		"""Returns a list of all operations in this variant.
   886 
   851 
   887 		The list elements are themselves lists; the overall structure of the
   852 		The list elements are themselves lists; the overall structure of the
   888 		returned value is:
   853 		returned value is:
   889 
   854 
   890 		[ [ops-from-parent],[ops-from-varRefs], [ops-in-self] ]
   855 		[ [ops-from-parent],[ops-from-varRefs], [ops-in-self] ]
   891 		"""
   856 		"""
   892 
   857 
   893 		if not self.allOperations:
   858 		if not self.allOperations:
   894 			if self.extends:
   859 			if self.extends:
   895 				parent = self.owner.cache.FindNamedVariant(self.extends)
   860 				parent = cache.FindNamedVariant(self.extends)
   896 				self.allOperations.extend( parent.GetAllOperationsRecursively() )
   861 				self.allOperations.extend( parent.GetAllOperationsRecursively(cache = cache) )
   897 			for r in self.variantRefs:
   862 			for r in self.variantRefs:
   898 				for v in [ r.Resolve() ] + r.GetModifiers():
   863 				for v in [ r.Resolve(cache = cache) ] + r.GetModifiers(cache = cache):
   899 					self.allOperations.extend( v.GetAllOperationsRecursively() )
   864 					self.allOperations.extend( v.GetAllOperationsRecursively(cache = cache) )
   900 			self.allOperations.append(self.ops)
   865 			self.allOperations.append(self.ops)
   901 
   866 
   902 		return self.allOperations
   867 		return self.allOperations
   903 
   868 
   904 	def GenerateBuildUnits(self):
   869 	def GenerateBuildUnits(self,cache):
   905 
   870 
   906 		name = self.name
   871 		name = self.name
   907 		vars = [self]
   872 		vars = [self]
   908 
   873 
   909 		for m in self.modifiers:
   874 		for m in self.modifiers:
   910 			name = name + "." + m.name
   875 			name = name + "." + m.name
   911 			vars.append(m)
   876 			vars.append(m)
   912 
   877 		return [ BuildUnit(name=name, variants=vars) ]
   913 		return [ BuildUnit(name, vars) ]
   878 
   914 
   879 	def __str__(self):
   915 	def DebugPrint(self, prefix = ""):
   880 		s = "<var name='%s' extends='%s'>\n" % (self.name, self.extends)
   916 
       
   917 		self.owner.Debug("%s<var name='%s' extends='%s'>", prefix, self.name, self.extends)
       
   918 		for op in self.ops:
   881 		for op in self.ops:
   919 			op.DebugPrint(prefix + self.indent)
   882 			s +=  str(op) + '\n'
   920 
   883 		s += "</var>"
   921 		self.owner.Debug("%s</var>", prefix)
   884 		return s
   922 
   885 
   923 
   886 import traceback
   924 class VariantRef(Reference):
   887 class VariantRef(Reference):
   925 
   888 
   926 	def __init__(self, ref=None):
   889 	def __init__(self, ref=None):
   927 		Reference.__init__(self, ref)
   890 		Reference.__init__(self, ref = ref)
   928 
   891 
   929 	def DebugPrint(self, prefix = ""):
   892 	def __str__(self):
   930 		self.owner.Debug("%s<varRef ref='%s'/>", prefix, self.ref)
   893 		return "<varRef ref='%s'/>" % self.ref
   931 
   894 
   932 	def Resolve(self):
   895 	def Resolve(self, cache):
   933 		try:
   896 		try:
   934 			return self.owner.cache.FindNamedVariant(self.ref)
   897 			return cache.FindNamedVariant(self.ref)
   935 		except KeyError:
   898 		except KeyError, e:
   936 			raise BadReferenceError(self.ref)
   899 			raise BadReferenceError(self.ref)
   937 
   900 
       
   901 class MissingVariantException(Exception):
       
   902 	pass
   938 
   903 
   939 class Alias(Model, Config):
   904 class Alias(Model, Config):
   940 
   905 
   941 	def __init__(self, name=""):
   906 	def __init__(self, name=""):
   942 		Model.__init__(self)
   907 		Model.__init__(self)
   944 		self.name = name
   909 		self.name = name
   945 		self.meaning = ""
   910 		self.meaning = ""
   946 		self.varRefs = []
   911 		self.varRefs = []
   947 		self.variants = []
   912 		self.variants = []
   948 
   913 
   949 	def DebugPrint(self, prefix = ""):
   914 	def __str__(self):
   950 		self.owner.Debug("%s<alias name='%s' meaning='%s'/>", prefix, self.name, self.meaning)
   915 		return "<alias name='%s' meaning='%s'/>" % (self.name, self.meaning)
   951 
   916 
   952 	def SetProperty(self, key, val):
   917 	def SetProperty(self, key, val):
   953 		if key == "name":
   918 		if key == "name":
   954 			self.name = val
   919 			self.name = val
   955 		elif key == "meaning":
   920 		elif key == "meaning":
   956 			self.meaning = val
   921 			self.meaning = val
   957 
   922 
   958 			for u in val.split("."):
   923 			for u in val.split("."):
   959 				self.varRefs.append( VariantRef(u) )
   924 				self.varRefs.append( VariantRef(ref = u) )
   960 		else:
   925 		else:
   961 			raise InvalidPropertyError()
   926 			raise InvalidPropertyError()
   962 
       
   963 	def SetOwner(self, raptor):
       
   964 		Model.SetOwner(self, raptor)
       
   965 		for r in self.varRefs:
       
   966 			r.SetOwner(raptor)
       
   967 
   927 
   968 	def Valid(self):
   928 	def Valid(self):
   969 		return self.name and self.meaning
   929 		return self.name and self.meaning
   970 
   930 
   971 	def GenerateBuildUnits(self):
   931 	def GenerateBuildUnits(self, cache):
   972 		if not self.variants:
   932 		if not self.variants:
       
   933 			missing_variants = []
   973 			for r in self.varRefs:
   934 			for r in self.varRefs:
   974 				try:
   935 				try:
   975 					self.variants.append( r.Resolve() )
   936 					self.variants.append( r.Resolve(cache=cache) )
   976 				except BadReferenceError:
   937 				except BadReferenceError:
   977 					self.owner.Error("Missing variant '%s'", r.ref)
   938 					missing_variants.append(r.ref)
       
   939 				
       
   940 			if len(missing_variants) > 0:
       
   941 				raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants))
   978 
   942 
   979 		name = self.name
   943 		name = self.name
   980 
   944 
   981 		for v in self.modifiers:
   945 		for v in self.modifiers:
   982 			name = name + "." + v.name
   946 			name = name + "." + v.name
   983 
   947 
   984 		return [ BuildUnit(name, self.variants + self.modifiers) ]
   948 		return [ BuildUnit(name=name, variants=self.variants + self.modifiers) ]
   985 
   949 
   986 
   950 
   987 class AliasRef(Reference):
   951 class AliasRef(Reference):
   988 
   952 
   989 	def __init__(self, ref=None):
   953 	def __init__(self, ref=None):
   990 		Reference.__init__(self, ref)
   954 		Reference.__init__(self, ref)
   991 
   955 
   992 	def DebugPrint(self, prefix = ""):
   956 	def __str__(self):
   993 		self.owner.Debug("%s<aliasRef ref='%s'/>", prefix, self.ref)
   957 		return "<aliasRef ref='%s'/>" % self.ref
   994 
   958 
   995 	def Resolve(self):
   959 	def Resolve(self, cache):
   996 		try:
   960 		try:
   997 			return self.owner.cache.FindNamedAlias(self.ref)
   961 			return cache.FindNamedAlias(self.ref)
   998 		except KeyError:
   962 		except KeyError:
   999 			raise BadReferenceError(self.ref)
   963 			raise BadReferenceError(self.ref)
  1000 
   964 
  1001 
   965 
  1002 class Group(Model, Config):
   966 class Group(Model, Config):
  1016 		if isinstance( child, (VariantRef,AliasRef,GroupRef) ):
   980 		if isinstance( child, (VariantRef,AliasRef,GroupRef) ):
  1017 			self.childRefs.append(child)
   981 			self.childRefs.append(child)
  1018 		else:
   982 		else:
  1019 			raise InvalidChildError()
   983 			raise InvalidChildError()
  1020 
   984 
  1021 	def SetOwner(self, raptor):
       
  1022 		Model.SetOwner(self, raptor)
       
  1023 		for r in self.childRefs:
       
  1024 			r.SetOwner(raptor)
       
  1025 
       
  1026 	def Valid(self):
   985 	def Valid(self):
  1027 		return self.name and self.childRefs
   986 		return self.name and self.childRefs
  1028 
   987 
  1029 	def DebugPrint(self, prefix = ""):
   988 	def __str__(self):
  1030 
   989 		s = "<group name='%s'>" % self.name
  1031 		self.owner.Debug("<group name='%s'>", prefix, self.name)
       
  1032 
       
  1033 		for r in self.childRefs:
   990 		for r in self.childRefs:
  1034 			r.DebugPrint(prefix + self.indent)
   991 			s += str(r)
  1035 
   992 		s += "</group>"
  1036 		self.owner.Debug("%s</group>", prefix)
   993 		return s
  1037 
   994 
  1038 	def GenerateBuildUnits(self):
   995 	def GenerateBuildUnits(self, cache):
  1039 
       
  1040 		units = []
   996 		units = []
  1041 
   997 
       
   998 		missing_variants = []
  1042 		for r in self.childRefs:
   999 		for r in self.childRefs:
  1043 			refMods = r.GetModifiers()
  1000 			refMods = r.GetModifiers(cache)
  1044 
  1001 
  1045 			try:
  1002 			try:
  1046 				obj = r.Resolve()
  1003 				obj = r.Resolve(cache=cache)
  1047 			except BadReferenceError:
  1004 			except BadReferenceError:
  1048 				self.owner.Error("Missing variant '%s'", r.ref)
  1005 				missing_variants.append(r.ref)
  1049 			else:
  1006 			else:
  1050 				obj.ClearModifiers()
  1007 				obj.ClearModifiers()
  1051 
  1008 
  1052 				for m in refMods + self.modifiers:
  1009 				for m in refMods + self.modifiers:
  1053 					obj.AddModifier(m)
  1010 					obj.AddModifier(m)
  1054 
  1011 
  1055 				units.extend( obj.GenerateBuildUnits() )
  1012 				units.extend( obj.GenerateBuildUnits(cache) )
       
  1013 
       
  1014 		if len(missing_variants) > 0:
       
  1015 			raise MissingVariantException("Missing variants '%s'", " ".join(missing_variants))
  1056 
  1016 
  1057 		return units
  1017 		return units
  1058 
  1018 
  1059 
  1019 
  1060 class GroupRef(Reference):
  1020 class GroupRef(Reference):
  1061 
  1021 
  1062 	def __init__(self, ref=None):
  1022 	def __init__(self, ref=None):
  1063 		Reference.__init__(self, ref)
  1023 		Reference.__init__(self, ref)
  1064 
  1024 
  1065 	def DebugPrint(self, prefix = ""):
  1025 	def __str__(self):
  1066 		mod = ".".join(self.modifiers)
  1026 		return "<%s /><groupRef ref='%s' mod='%s'/>" % (prefix, self.ref, ".".join(self.modifiers))
  1067 		self.owner.Debug("%s<groupRef ref='%s' mod='%s'/>", prefix, self.ref, mod)
  1027 
  1068 
  1028 	def Resolve(self, cache):
  1069 	def Resolve(self):
       
  1070 		try:
  1029 		try:
  1071 			return self.owner.cache.FindNamedGroup(self.ref)
  1030 			return cache.FindNamedGroup(self.ref)
  1072 		except KeyError:
  1031 		except KeyError:
  1073 			raise BadReferenceError(self.ref)
  1032 			raise BadReferenceError(self.ref)
  1074 
  1033 
       
  1034 class ToolErrorException(Exception):
       
  1035 	def __init__(self, s):
       
  1036 		Exception.__init__(self,s)
       
  1037 
  1075 class Tool(object):
  1038 class Tool(object):
  1076 	"""Represents a tool that might be used by raptor e.g. a compiler"""
  1039 	"""Represents a tool that might be used by raptor e.g. a compiler"""
       
  1040 
       
  1041 	# It's difficult and expensive to give each tool a log reference but a class one
       
  1042 	# will facilitate debugging when that is needed without being a design flaw the
       
  1043 	# rest of the time.
       
  1044 	log = raptor_utilities.nulllog
  1077 
  1045 
  1078 	# For use in dealing with tools that return non-ascii version strings.
  1046 	# For use in dealing with tools that return non-ascii version strings.
  1079 	nonascii = ""
  1047 	nonascii = ""
  1080 	identity_chartable = chr(0)
  1048 	identity_chartable = chr(0)
  1081 	for c in xrange(1,128):
  1049 	for c in xrange(1,128):
  1082 		identity_chartable += chr(c)
  1050 		identity_chartable += chr(c)
  1083 	for c in xrange(128,256):
  1051 	for c in xrange(128,256):
  1084 		nonascii += chr(c)
  1052 		nonascii += chr(c)
  1085 		identity_chartable += " "
  1053 		identity_chartable += " "
  1086 
  1054 
  1087 	def __init__(self, name, command, versioncommand, versionresult, id="", log = raptor_utilities.nulllog):
  1055 	def __init__(self, name, command, versioncommand, versionresult, id=""):
  1088 		self.name = name
  1056 		self.name = name
  1089 		self.command = command
  1057 		self.command = command
  1090 		self.versioncommand = versioncommand
  1058 		self.versioncommand = versioncommand
  1091 		self.versionresult = versionresult
  1059 		self.versionresult = versionresult
  1092 		self.id = id # what config this is from - used in debug messages
  1060 		self.id = id # what config this is from - used in debug messages
  1095 
  1063 
  1096 		# Assume the tool is unavailable or the wrong
  1064 		# Assume the tool is unavailable or the wrong
  1097 		# version until someone proves that it's OK
  1065 		# version until someone proves that it's OK
  1098 		self.valid = False
  1066 		self.valid = False
  1099 
  1067 
  1100 		self.log=log
       
  1101 
  1068 
  1102 	def expand(self, toolset):
  1069 	def expand(self, toolset):
  1103 		self.versioncommand = toolset.ExpandAll(self.versioncommand)
  1070 		self.versioncommand = toolset.ExpandAll(self.versioncommand)
  1104 		self.versionresult  = toolset.ExpandAll(self.versionresult)
  1071 		self.versionresult  = toolset.ExpandAll(self.versionresult)
  1105 		self.command = toolset.ExpandAll(self.command)
  1072 		self.command = toolset.ExpandAll(self.command)
  1115 				# executable file (e.g. "armcc" rather than "python myscript.py") then get it's date. 
  1082 				# executable file (e.g. "armcc" rather than "python myscript.py") then get it's date. 
  1116 				# We can use the date later to see if our cache is valid. 
  1083 				# We can use the date later to see if our cache is valid. 
  1117 				# If it really is not a simple command then we won't be able to get a date and
  1084 				# If it really is not a simple command then we won't be able to get a date and
  1118 				# we won't be able to tell if it is altered or updated - too bad!
  1085 				# we won't be able to tell if it is altered or updated - too bad!
  1119 				testfile = generic_path.Where(self.command)
  1086 				testfile = generic_path.Where(self.command)
  1120 				self.log.Debug("toolcheck: tool '%s' was found on the path at '%s' ", self.command, testfile)
  1087 				#self.log.Debug("toolcheck: tool '%s' was found on the path at '%s' ", self.command, testfile)
  1121 				if testfile is None:
  1088 				if testfile is None:
  1122 					raise Exception("Can't be found in path")
  1089 					raise Exception("Can't be found in path")
  1123 
  1090 
  1124 			if not os.path.isfile(testfile):
  1091 			if not os.path.isfile(testfile):
  1125 				raise Exception("tool %s appears to not be a file %s", self.command, testfile)
  1092 				raise Exception("tool %s appears to not be a file %s", self.command, testfile)
  1126 				
  1093 				
  1127 			testfile_stat = os.stat(testfile)
  1094 			testfile_stat = os.stat(testfile)
  1128 			self.date = testfile_stat.st_mtime
  1095 			self.date = testfile_stat.st_mtime
  1129 		except Exception,e:
  1096 		except Exception,e:
  1130 			self.log.Debug("toolcheck: '%s=%s' cannot be dated - this is ok, but the toolcheck won't be able to tell when a new  of the tool is installed. (%s)", self.name, self.command, str(e))
  1097 			# We really don't mind if the tool could not be dated - for any reason
       
  1098 			Tool.log.Debug("toolcheck: '%s=%s' cannot be dated - this is ok, but the toolcheck won't be able to tell when a new version of the tool is installed. (%s)", self.name, self.command, str(e))
       
  1099 			pass
  1131 	
  1100 	
  1132 			
  1101 			
  1133 	def check(self, shell, evaluator):
  1102 	def check(self, shell, evaluator, log = raptor_utilities.nulllog):
  1134 
  1103 
  1135 		self.vre = re.compile(self.versionresult)
  1104 		self.vre = re.compile(self.versionresult)
  1136 
  1105 
  1137 		try:
  1106 		try:
  1138 			self.log.Debug("Pre toolcheck: '%s' for version '%s'", self.name, self.versionresult)
  1107 			self.log.Debug("Pre toolcheck: '%s' for version '%s'", self.name, self.versionresult)
  1139 			p = subprocess.Popen(args=[shell, "-c", self.versioncommand], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  1108 			p = subprocess.Popen(args=[shell, "-c", self.versioncommand], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
       
  1109 			log.Debug("Checking tool '%s' for version '%s'", self.name, self.versionresult)
  1140 			versionoutput,err = p.communicate()
  1110 			versionoutput,err = p.communicate()
  1141 			self.log.Debug("Checking tool '%s' for version '%s'", self.name, self.versionresult)
       
  1142 		except Exception,e:
  1111 		except Exception,e:
  1143 			versionoutput=None
  1112 			versionoutput=None
  1144 
  1113 
  1145 		# Some tools return version strings with unicode characters! 
  1114 		# Some tools return version strings with unicode characters! 
  1146 		# There is no good response other than a lot of decoding and encoding.
  1115 		# There is no good response other than a lot of decoding and encoding.
  1147 		# Simpler to ignore it:
  1116 		# Simpler to ignore it:
  1148 		versionoutput_a = versionoutput.translate(Tool.identity_chartable,"")
  1117 		versionoutput_a = versionoutput.translate(Tool.identity_chartable,"")
  1149 
  1118 
  1150 		if versionoutput_a and self.vre.search(versionoutput_a) != None:
  1119 		if versionoutput_a and self.vre.search(versionoutput_a) != None:
  1151 			self.log.Debug("tool '%s' returned an acceptable version '%s' at %s", self.name, versionoutput_a, str(self.date))
  1120 			log.Debug("tool '%s' returned an acceptable version '%s'", self.name, versionoutput_a)
  1152 			self.valid = True
  1121 			self.valid = True
  1153 		else:
  1122 		else:
  1154 			self.log.Error("tool '%s' from config '%s' did not return version '%s' as required.\nCommand '%s' returned:\n%s\nCheck your environment and configuration.\n", self.name, self.id, self.versionresult, self.versioncommand, versionoutput_a)
       
  1155 			self.valid = False
  1123 			self.valid = False
  1156 		return self.valid
  1124 			raise ToolErrorException("tool '%s' from config '%s' did not return version '%s' as required.\nCommand '%s' returned:\n%s\nCheck your environment and configuration.\n" % (self.name, self.id, self.versionresult, self.versioncommand, versionoutput_a))
  1157 
  1125 
  1158 def envhash(irrelevant_vars):
  1126 def envhash(irrelevant_vars):
  1159 	"""Determine something unique about this environment to identify it.
  1127 	"""Determine something unique about this environment to identify it.
  1160 	must ignore variables that change without mattering to the caller
  1128 	must ignore variables that change without mattering to the caller
  1161 	e.g. perhaps PATH matters but PWD and PPID don't"""
  1129 	e.g. perhaps PATH matters but PWD and PPID don't"""
  1173 	toolset.check() is called for each config but the cache is kept across calls to
  1141 	toolset.check() is called for each config but the cache is kept across calls to
  1174 	catch the use of one tool in many configs.
  1142 	catch the use of one tool in many configs.
  1175 	write() is used to flush the cache to disc.
  1143 	write() is used to flush the cache to disc.
  1176 	"""
  1144 	"""
  1177 	# The raptor shell - this is not mutable.
  1145 	# The raptor shell - this is not mutable.
  1178 	hostbinaries = os.path.join(os.environ['SBS_HOME'], 
  1146 	if 'SBS_SHELL' in os.environ:
  1179 	                            os.environ['HOSTPLATFORM_DIR'])
  1147 		shell = os.environ['SBS_SHELL']
       
  1148 	else:
       
  1149 		hostbinaries = os.path.join(os.environ['SBS_HOME'], 
       
  1150 	                                os.environ['HOSTPLATFORM_DIR'])
  1180 	                            
  1151 	                            
  1181 	if HostPlatform.IsHost('lin*'):
  1152 		if HostPlatform.IsHost('lin*'):
  1182 		shell=os.path.join(hostbinaries, 'bin/bash')
  1153 			shell=os.path.join(hostbinaries, 'bin/bash')
  1183 	else:
  1154 		else:
  1184 		if 'SBS_CYGWIN' in os.environ:
  1155 			if 'SBS_CYGWIN' in os.environ:
  1185 			shell=os.path.join(os.environ['SBS_CYGWIN'], 'bin\\bash.exe')
  1156 				shell=os.path.join(os.environ['SBS_CYGWIN'], 'bin\\bash.exe')
  1186 		else:
  1157 			else:
  1187 			shell=os.path.join(hostbinaries, 'cygwin\\bin\\bash.exe')
  1158 				shell=os.path.join(hostbinaries, 'cygwin\\bin\\bash.exe')
  1188 
  1159 
  1189 
  1160 
  1190 	irrelevant_vars = ['PWD','OLDPWD','PID','PPID', 'SHLVL' ]
  1161 	irrelevant_vars = ['PWD','OLDPWD','PID','PPID', 'SHLVL' ]
  1191 
  1162 
  1192 
  1163 
  1253 									self.__toolcheckcache[toolhistory[0]] = ce
  1224 									self.__toolcheckcache[toolhistory[0]] = ce
  1254 								log.Info("Loaded toolcheck cache: %s\n", self.cachefilename)
  1225 								log.Info("Loaded toolcheck cache: %s\n", self.cachefilename)
  1255 							except Exception, e:
  1226 							except Exception, e:
  1256 								log.Info("Ignoring garbled toolcheck cache: %s (%s)\n", self.cachefilename, str(e))
  1227 								log.Info("Ignoring garbled toolcheck cache: %s (%s)\n", self.cachefilename, str(e))
  1257 								self.__toolcheckcache = {}
  1228 								self.__toolcheckcache = {}
  1258 								
       
  1259 									
  1229 									
  1260 						else:
  1230 						else:
  1261 							log.Info("Toolcheck cache %s ignored - environment changed\n", self.cachefilename)
  1231 							log.Info("Toolcheck cache %s ignored - environment changed\n", self.cachefilename)
  1262 					else:
  1232 					else:
  1263 						log.Info("Toolcheck cache not loaded = marker missing: %s %s\n", self.cachefilename, ToolSet.filemarker)
  1233 						log.Info("Toolcheck cache not loaded = marker missing: %s %s\n", self.cachefilename, ToolSet.filemarker)
  1314 						continue
  1284 						continue
  1315 
  1285 
  1316 
  1286 
  1317 			self.log.Debug("toolcheck done: %s -key: %s" % (tool.name, tool.key))
  1287 			self.log.Debug("toolcheck done: %s -key: %s" % (tool.name, tool.key))
  1318 
  1288 
  1319 			if not tool.check(ToolSet.shell, evaluator):
  1289 			try:
       
  1290 				tool.check(ToolSet.shell, evaluator, log = self.log)
       
  1291 			except ToolErrorException, e:
  1320 				self.valid = False
  1292 				self.valid = False
       
  1293 				self.log.Error("%s\n" % str(e))
  1321 
  1294 
  1322 			# Tool failures are cached just like successes - don't want to repeat them
  1295 			# Tool failures are cached just like successes - don't want to repeat them
  1323 			cache[tool.key] =  { "name" : tool.name, "valid" : tool.valid, "age" : 0 , "date" : tool.date }
  1296 			cache[tool.key] =  { "name" : tool.name, "valid" : tool.valid, "age" : 0 , "date" : tool.date }
  1324 
  1297 
  1325 
  1298 
  1354 				self.log.Info("Created/Updated toolcheck cache: %s\n", self.cachefilename)
  1327 				self.log.Info("Created/Updated toolcheck cache: %s\n", self.cachefilename)
  1355 			except Exception, e:
  1328 			except Exception, e:
  1356 				self.log.Info("Could not write toolcheck cache: %s", str(e))
  1329 				self.log.Info("Could not write toolcheck cache: %s", str(e))
  1357 		return self.valid
  1330 		return self.valid
  1358 
  1331 
       
  1332 class UninitialisedVariableException(Exception):
       
  1333 	pass
  1359 
  1334 
  1360 class Evaluator(object):
  1335 class Evaluator(object):
  1361 	"""Determine the values of variables under different Configurations.
  1336 	"""Determine the values of variables under different Configurations.
  1362 	Either of specification and buildUnit may be None."""
  1337 	Either of specification and buildUnit may be None."""
  1363 
  1338 
  1364 
  1339 
  1365 	refRegex = re.compile("\$\((.+?)\)")
  1340 	refRegex = re.compile("\$\((.+?)\)")
  1366 
  1341 
  1367 	def __init__(self, Raptor, specification, buildUnit, gathertools = False):
  1342 	def __init__(self, specification, buildUnit, cache, gathertools = False):
  1368 		self.raptor = Raptor
       
  1369 		self.dict = {}
  1343 		self.dict = {}
  1370 		self.tools = []
  1344 		self.tools = []
  1371 		self.gathertools = gathertools
  1345 		self.gathertools = gathertools
       
  1346 		self.cache = cache
  1372 
  1347 
  1373 		specName = "none"
  1348 		specName = "none"
  1374 		configName = "none"
  1349 		configName = "none"
  1375 
  1350 
  1376 		# A list of lists of operations.
  1351 		# A list of lists of operations.
  1377 		opsLists = []
  1352 		opsLists = []
  1378 
  1353 
  1379 		if buildUnit:
  1354 		if buildUnit:
  1380 			opsLists.extend( buildUnit.GetOperations() )
  1355 			ol = buildUnit.GetOperations(cache)
       
  1356 			self.buildUnit = buildUnit
       
  1357 			
       
  1358 			opsLists.extend( ol )
  1381 
  1359 
  1382 		if specification:
  1360 		if specification:
  1383 			for v in specification.GetAllVariantsRecursively():
  1361 			for v in specification.GetAllVariantsRecursively(cache):
  1384 				opsLists.extend( v.GetAllOperationsRecursively() )
  1362 				opsLists.extend( v.GetAllOperationsRecursively(cache) )
  1385 
  1363 
  1386 		tools = {}
  1364 		tools = {}
  1387 
  1365 
       
  1366 		unfound_values = []
  1388 		for opsList in opsLists:
  1367 		for opsList in opsLists:
  1389 			for op in opsList:
  1368 			for op in opsList:
  1390 				# applying an Operation to a non-existent variable
  1369 				# applying an Operation to a non-existent variable
  1391 				# is OK. We assume that it is just an empty string.
  1370 				# is OK. We assume that it is just an empty string.
  1392 				try:
  1371 				try:
  1393 					oldValue = self.dict[op.name]
  1372 					oldValue = self.dict[op.name]
  1394 				except KeyError:
  1373 				except KeyError:
  1395 					oldValue = ""
  1374 					oldValue = ""
  1396 
  1375 
  1397 				newValue = op.Apply(oldValue)
  1376 				try:
       
  1377 					newValue = op.Apply(oldValue)
       
  1378 				except BadToolValue, e:
       
  1379 					unfound_values.append(str(e))
       
  1380 					newValue = "NO_VALUE_FOR_" + op.name
       
  1381 					
  1398 				self.dict[op.name] = newValue
  1382 				self.dict[op.name] = newValue
  1399 			
  1383 			
  1400 				if self.gathertools:
  1384 				if self.gathertools:
  1401 					if op.type == "tool" and op.versionCommand and op.versionResult:
  1385 					if op.type == "tool" and op.versionCommand and op.versionResult:
  1402 						tools[op.name] = Tool(op.name, newValue, op.versionCommand, op.versionResult, configName, log = self.raptor)
  1386 						tools[op.name] = Tool(op.name, newValue, op.versionCommand, op.versionResult, configName)
  1403 
  1387 
       
  1388 		if len(unfound_values) > 0:
       
  1389 			raise UninitialisedVariableException("\n".join(unfound_values))
  1404 
  1390 
  1405 		if self.gathertools:
  1391 		if self.gathertools:
  1406 			self.tools = tools.values()
  1392 			self.tools = tools.values()
  1407 		else:
  1393 		else:
  1408 			self.tools=[]
  1394 			self.tools=[]
  1415 
  1401 
  1416 		while unresolved:
  1402 		while unresolved:
  1417 			unresolved = False
  1403 			unresolved = False
  1418 			for k, v in self.dict.items():
  1404 			for k, v in self.dict.items():
  1419 				if v.find('$(' + k + ')') != -1:
  1405 				if v.find('$(' + k + ')') != -1:
  1420 					self.raptor.Error("Recursion Detected in variable '%s' in configuration '%s' ",k,configName)
  1406 						raise RecursionException("Recursion Detected in variable '%s' in configuration '%s' " % (k,configName))
  1421 					expanded = "RECURSIVE_INVALID_STRING"
  1407 						expanded = "RECURSIVE_INVALID_STRING"
  1422 				else:
  1408 				else:
  1423 					expanded = self.ExpandAll(v, specName, configName)
  1409 					expanded = self.ExpandAll(v, specName, configName)
  1424 
  1410 
  1425 				if expanded != v:				# something changed?
  1411 				if expanded != v:				# something changed?
  1426 					self.dict[k] = expanded
  1412 					self.dict[k] = expanded
  1464 
  1450 
  1465 		returns the newly expanded string."""
  1451 		returns the newly expanded string."""
  1466 
  1452 
  1467 		refs = Evaluator.refRegex.findall(value)
  1453 		refs = Evaluator.refRegex.findall(value)
  1468 
  1454 
       
  1455 		# store up all the unset variables before raising an exception
       
  1456 		# to allow us to find them all
       
  1457 		unset_variables = [] 
       
  1458 
  1469 		for r in set(refs):
  1459 		for r in set(refs):
  1470 			expansion = None
  1460 			expansion = None
  1471 
  1461 
  1472 			if r in self.raptor.override:
  1462 			if r in self.dict:
  1473 				expansion = self.raptor.override[r]
       
  1474 			elif r in self.dict:
       
  1475 				expansion = self.dict[r]
  1463 				expansion = self.dict[r]
  1476 			else:
  1464 			else:
  1477 				# no expansion for $(r)
  1465 				# no expansion for $(r)
  1478 				self.raptor.Error("Unset variable '%s' used in spec '%s' with config '%s'",
  1466 				unset_variables.append("Unset variable '%s' used in spec '%s' with config '%s'" % (r, spec, config))
  1479 							  	  r, spec, config)
       
  1480 			if expansion != None:
  1467 			if expansion != None:
  1481 				value = value.replace("$(" + r + ")", expansion)
  1468 				value = value.replace("$(" + r + ")", expansion)
  1482 
  1469 
       
  1470 		if len(unset_variables) > 0: # raise them all
       
  1471 			raise UninitialisedVariableException(". ".join(unset_variables))
       
  1472 
  1483 		return value
  1473 		return value
  1484 
  1474 
  1485 
  1475 
  1486 # raptor_data module functions
  1476 # raptor_data module functions
  1487 
  1477