sbsv2/raptor/python/raptor.py
branchwip
changeset 76 55ef265012ad
parent 59 0f7d6c11c675
child 115 5869e06bf2ac
equal deleted inserted replaced
75:000ba5e4ba7d 76:55ef265012ad
     9 # Initial Contributors:
     9 # Initial Contributors:
    10 # Nokia Corporation - initial contribution.
    10 # Nokia Corporation - initial contribution.
    11 #
    11 #
    12 # Contributors:
    12 # Contributors:
    13 #
    13 #
    14 # Description: 
    14 # Description:
    15 # raptor module
    15 # raptor module
    16 # This module represents the running Raptor program. Raptor is started
    16 # This module represents the running Raptor program. Raptor is started
    17 # either by calling the Main() function, which creates an instance of
    17 # either by calling the Main() function, which creates an instance of
    18 # the raptor.Raptor class and calls its methods to perform a build based
    18 # the raptor.Raptor class and calls its methods to perform a build based
    19 # on command-line parameters, or by explicitly creating a raptor.Raptor
    19 # on command-line parameters, or by explicitly creating a raptor.Raptor
   117 	def __init__(self, id, parent = None):
   117 	def __init__(self, id, parent = None):
   118 		self.id = id
   118 		self.id = id
   119 		self.type = type
   119 		self.type = type
   120 		self.specs = []
   120 		self.specs = []
   121 		self.deps = []
   121 		self.deps = []
   122 		self.children = set() 
   122 		self.children = set()
   123 		self.unfurled = False
   123 		self.unfurled = False
   124 		self.parent = parent
   124 		self.parent = parent
   125 
   125 
   126 	# Allow one to make a set
   126 	# Allow one to make a set
   127 	def __hash__(self):
   127 	def __hash__(self):
   161 
   161 
   162 		self.realise_exports(build) # permit communication of dependencies between children
   162 		self.realise_exports(build) # permit communication of dependencies between children
   163 
   163 
   164 		for c in self.children:
   164 		for c in self.children:
   165 			c.unfurl_all(build)
   165 			c.unfurl_all(build)
   166 		
   166 
   167 
   167 
   168 	def realise_exports(self, build):
   168 	def realise_exports(self, build):
   169 		"""Do the things that are needed such that we can fully unfurl all 
   169 		"""Do the things that are needed such that we can fully unfurl all
   170 		   sibling nodes.  i.e. this step is here to "take care" of the dependencies
   170 		   sibling nodes.  i.e. this step is here to "take care" of the dependencies
   171 		   between siblings.  
   171 		   between siblings.
   172 		"""
   172 		"""
   173 		pass
   173 		pass
   174 	
   174 
   175 	def realise_makefile(self, build, specs):
   175 	def realise_makefile(self, build, specs):
   176 		makefilename_base = build.topMakefile
   176 		makefilename_base = build.topMakefile
   177 		if self.name is not None:
   177 		if self.name is not None:
   178 			makefile = generic_path.Path(str(makefilename_base) + "_" + raptor_utilities.sanitise(self.name))
   178 			makefile = generic_path.Path(str(makefilename_base) + "_" + raptor_utilities.sanitise(self.name))
   179 		else:
   179 		else:
   188 		makefileset = build.maker.Write(makefile, specs, build.buildUnitsToBuild)
   188 		makefileset = build.maker.Write(makefile, specs, build.buildUnitsToBuild)
   189 		build.InfoEndTime(object_type = "layer", task = "parse",
   189 		build.InfoEndTime(object_type = "layer", task = "parse",
   190 				key = str(makefile.path))
   190 				key = str(makefile.path))
   191 
   191 
   192 		return makefileset
   192 		return makefileset
   193 		
   193 
   194 
   194 
   195 
   195 
   196 	def realise(self, build):
   196 	def realise(self, build):
   197 		"""Give the spec trees to the make engine and actually 
   197 		"""Give the spec trees to the make engine and actually
   198 		"build" the product represented by this model node"""	
   198 		"build" the product represented by this model node"""
   199 		# Must ensure that all children are unfurled at this point
   199 		# Must ensure that all children are unfurled at this point
   200 		self.unfurl_all(build)
   200 		self.unfurl_all(build)
   201 
   201 
   202 		sp = self.specs	
   202 		sp = self.specs
   203 
   203 
   204 		build.AssertBuildOK()
   204 		build.AssertBuildOK()
   205 
   205 
   206 		m = self.realise_makefile(build, sp)
   206 		m = self.realise_makefile(build, sp)
   207 
   207 
   208 		build.InfoStartTime(object_type = "layer", task = "build",
   208 		build.InfoStartTime(object_type = "layer", task = "build",
   209 				key = (str(m.directory) + "/" + str(m.filenamebase)))
   209 				key = (str(m.directory) + "/" + str(m.filenamebase)))
   210 		result = build.Make(m)
   210 		result = build.Make(m)
   211 		build.InfoEndTime(object_type = "layer", task = "build",
   211 		build.InfoEndTime(object_type = "layer", task = "build",
   212 				key = (str(m.directory) + "/" + str(m.filenamebase)))
   212 				key = (str(m.directory) + "/" + str(m.filenamebase)))
   213 		
   213 
   214 		
   214 
   215 		return result
   215 		return result
   216 
   216 
   217 
   217 
   218 
   218 
   219 class Project(ModelNode):
   219 class Project(ModelNode):
   227 		self.id = self.mmp_name
   227 		self.id = self.mmp_name
   228 		self.unfurled = False
   228 		self.unfurled = False
   229 
   229 
   230 	def makefile(self, makefilename_base, engine, named = False):
   230 	def makefile(self, makefilename_base, engine, named = False):
   231 		"""Makefiles for individual mmps not feasible at the moment"""
   231 		"""Makefiles for individual mmps not feasible at the moment"""
   232 		pass # Cannot, currently, "unfurl an mmp" directly but do want 
   232 		pass # Cannot, currently, "unfurl an mmp" directly but do want
   233 		     # to be able to simulate the overall recursive unfurling of a build.
   233 		     # to be able to simulate the overall recursive unfurling of a build.
   234 
   234 
   235 class Component(ModelNode):
   235 class Component(ModelNode):
   236 	"""A group of projects or, in symbian-speak, a bld.inf.
   236 	"""A group of projects or, in symbian-speak, a bld.inf.
   237 	"""
   237 	"""
   250 	def AddMMP(self, filename):
   250 	def AddMMP(self, filename):
   251 		self.children.add(Project(filename))
   251 		self.children.add(Project(filename))
   252 
   252 
   253 
   253 
   254 class Layer(ModelNode):
   254 class Layer(ModelNode):
   255 	""" 	Some components that should be built togther 
   255 	""" 	Some components that should be built togther
   256 		e.g. a Layer in the system definition. 
   256 		e.g. a Layer in the system definition.
   257 	""" 
   257 	"""
   258 	def __init__(self, name, componentlist=[]):
   258 	def __init__(self, name, componentlist=[]):
   259 		super(Layer,self).__init__(name)
   259 		super(Layer,self).__init__(name)
   260 		self.name = name
   260 		self.name = name
   261 
   261 
   262 		for c in componentlist:
   262 		for c in componentlist:
   263 			self.children.add(Component(c))
   263 			self.children.add(Component(c))
   264 
   264 
   265 	def unfurl(self, build):
   265 	def unfurl(self, build):
   266 		"""Discover the children of this layer. This involves parsing the component MetaData (bld.infs, mmps). 
   266 		"""Discover the children of this layer. This involves parsing the component MetaData (bld.infs, mmps).
   267 		Takes a raptor object as a parameter (build), together with a list of Configurations.
   267 		Takes a raptor object as a parameter (build), together with a list of Configurations.
   268 
   268 
   269 		We currently have parsers that work on collections of components/bld.infs and that cannot
   269 		We currently have parsers that work on collections of components/bld.infs and that cannot
   270 		parse at a "finer" level.  So one can't 'unfurl' an mmp at the moment.  
   270 		parse at a "finer" level.  So one can't 'unfurl' an mmp at the moment.
   271 
   271 
   272 		Returns True if the object was successfully unfurled.
   272 		Returns True if the object was successfully unfurled.
   273 		"""
   273 		"""
   274 
   274 
   275 		# setup all our components
   275 		# setup all our components
   298 
   298 
   299 
   299 
   300 	def meta_realise(self, build):
   300 	def meta_realise(self, build):
   301 		"""Generate specs that can be used to "take care of" finding out more
   301 		"""Generate specs that can be used to "take care of" finding out more
   302 		about this metaunit - i.e. one doesn't want to parse it immediately
   302 		about this metaunit - i.e. one doesn't want to parse it immediately
   303 		but to create a makefile that will parse it. 
   303 		but to create a makefile that will parse it.
   304 		In this case it allows bld.infs to be parsed in parallel by make."""
   304 		In this case it allows bld.infs to be parsed in parallel by make."""
   305 
   305 
   306 		# insert the start time into the Makefile name?
   306 		# insert the start time into the Makefile name?
   307 
   307 
   308 		buildconfig = build.GetConfig("build").GenerateBuildUnits(build.cache)
   308 		buildconfig = build.GetConfig("build").GenerateBuildUnits(build.cache)
   309 		self.configs = build.buildUnitsToBuild
   309 		self.configs = build.buildUnitsToBuild
   310 
   310 
   311 		# Pass certain CLI flags through to the makefile-generating sbs calls
   311 		# Pass certain CLI flags through to the makefile-generating sbs calls
   312 		cli_options = ""
   312 		cli_options = ""
   313 			
   313 
   314 		if build.debugOutput == True:
   314 		if build.debugOutput == True:
   315 			cli_options += " -d"
   315 			cli_options += " -d"
   316 				
   316 
   317 		if build.ignoreOsDetection == True:
   317 		if build.ignoreOsDetection == True:
   318 			cli_options += " -i"
   318 			cli_options += " -i"
   319 			
   319 
   320 		if build.keepGoing == True:
   320 		if build.keepGoing == True:
   321 			cli_options += " -k"
   321 			cli_options += " -k"
   322 			
   322 
   323 		if build.quiet == True:
   323 		if build.quiet == True:
   324 			cli_options += " -q"
   324 			cli_options += " -q"
   325 			
   325 
   326 		if build.timing == True:
   326 		if build.timing == True:
   327 			cli_options += " --timing"
   327 			cli_options += " --timing"
   328 
   328 
   329 		
   329 
   330 		nc = len(self.children)
   330 		nc = len(self.children)
   331 		number_blocks = build.jobs
   331 		number_blocks = build.jobs
   332 		block_size = (nc / number_blocks) + 1
   332 		block_size = (nc / number_blocks) + 1
   333 		component_blocks = []
   333 		component_blocks = []
   334 		spec_nodes = []
   334 		spec_nodes = []
   335 		
   335 
   336 		b = 0
   336 		b = 0
   337 		childlist = list(self.children)
   337 		childlist = list(self.children)
   338 		while b < nc:
   338 		while b < nc:
   339 			component_blocks.append(childlist[b:b+block_size])
   339 			component_blocks.append(childlist[b:b+block_size])
   340 			b += block_size
   340 			b += block_size
   341 			
   341 
   342 		while len(component_blocks[-1]) <= 0:
   342 		while len(component_blocks[-1]) <= 0:
   343 			component_blocks.pop()
   343 			component_blocks.pop()
   344 			number_blocks -= 1
   344 			number_blocks -= 1
   345 	
   345 
   346 		build.Info("Parallel Parsing: bld.infs split into %d blocks\n", number_blocks)
   346 		build.Info("Parallel Parsing: bld.infs split into %d blocks\n", number_blocks)
   347 		# Cause the binding makefiles to have the toplevel makefile's 
   347 		# Cause the binding makefiles to have the toplevel makefile's
   348 		# name.  The bindee's have __pp appended.	
   348 		# name.  The bindee's have __pp appended.
   349 		tm = build.topMakefile.Absolute()
   349 		tm = build.topMakefile.Absolute()
   350 		binding_makefiles = raptor_makefile.MakefileSet(str(tm.Dir()), build.maker.selectors, makefiles=None, filenamebase=str(tm.File()))		
   350 		binding_makefiles = raptor_makefile.MakefileSet(str(tm.Dir()), build.maker.selectors, makefiles=None, filenamebase=str(tm.File()))
   351 		build.topMakefile = generic_path.Path(str(build.topMakefile) + "_pp")
   351 		build.topMakefile = generic_path.Path(str(build.topMakefile) + "_pp")
   352 
   352 
   353 		loop_number = 0
   353 		loop_number = 0
   354 		for block in component_blocks:
   354 		for block in component_blocks:
   355 			loop_number += 1
   355 			loop_number += 1
   356 			specNode = raptor_data.Specification("metadata_" + self.name)
   356 			specNode = raptor_data.Specification("metadata_" + self.name)
   357 
   357 
   358 			componentList = " ".join([str(c.bldinf_filename) for c in block])
   358 			componentList = " ".join([str(c.bldinf_filename) for c in block])
   359 
   359 
   360 			
   360 
   361 			configList = " ".join([c.name for c in self.configs if c.name != "build" ])
   361 			configList = " ".join([c.name for c in self.configs if c.name != "build" ])
   362 			
   362 
   363 			makefile_path = str(build.topMakefile) + "_" + str(loop_number)
   363 			makefile_path = str(build.topMakefile) + "_" + str(loop_number)
   364 			try:
   364 			try:
   365 				os.unlink(makefile_path) # until we have dependencies working properly
   365 				os.unlink(makefile_path) # until we have dependencies working properly
   366 			except Exception,e:
   366 			except Exception,e:
   367 				# print "couldn't unlink %s: %s" %(componentMakefileName, str(e))
   367 				# print "couldn't unlink %s: %s" %(componentMakefileName, str(e))
   368 				pass
   368 				pass
   369 			
   369 
   370 			# add some basic data in a component-wide variant
   370 			# add some basic data in a component-wide variant
   371 			var = raptor_data.Variant()
   371 			var = raptor_data.Variant()
   372 			var.AddOperation(raptor_data.Set("COMPONENT_PATHS", componentList))
   372 			var.AddOperation(raptor_data.Set("COMPONENT_PATHS", componentList))
   373 			var.AddOperation(raptor_data.Set("MAKEFILE_PATH", makefile_path))
   373 			var.AddOperation(raptor_data.Set("MAKEFILE_PATH", makefile_path))
   374 			var.AddOperation(raptor_data.Set("CONFIGS", configList))
   374 			var.AddOperation(raptor_data.Set("CONFIGS", configList))
   383 
   383 
   384 			# Pass on '-n' (if specified) to the makefile-generating sbs calls
   384 			# Pass on '-n' (if specified) to the makefile-generating sbs calls
   385 			if build.noBuild:
   385 			if build.noBuild:
   386 				var.AddOperation(raptor_data.Set("NO_BUILD", "1"))
   386 				var.AddOperation(raptor_data.Set("NO_BUILD", "1"))
   387 			specNode.AddVariant(var)
   387 			specNode.AddVariant(var)
   388 	
   388 
   389 			try:
   389 			try:
   390 				interface = build.cache.FindNamedInterface("build.makefiles")
   390 				interface = build.cache.FindNamedInterface("build.makefiles")
   391 				specNode.SetInterface(interface)
   391 				specNode.SetInterface(interface)
   392 			except KeyError:
   392 			except KeyError:
   393 				build.Error("Can't find flm interface 'build.makefiles' ")
   393 				build.Error("Can't find flm interface 'build.makefiles' ")
   394 				
   394 
   395 			spec_nodes.append(specNode)
   395 			spec_nodes.append(specNode)
   396 			binding_makefiles.addInclude(str(makefile_path)+"_all")
   396 			binding_makefiles.addInclude(str(makefile_path)+"_all")
   397 
   397 
   398 		build.InfoDiscovery(object_type = "layers", count = 1)
   398 		build.InfoDiscovery(object_type = "layers", count = 1)
   399 		build.InfoStartTime(object_type = "layer", task = "parse",
   399 		build.InfoStartTime(object_type = "layer", task = "parse",
   428 	created by the Main function. When operated by an IDE several Raptor
   428 	created by the Main function. When operated by an IDE several Raptor
   429 	objects may be created and operated at the same time."""
   429 	objects may be created and operated at the same time."""
   430 
   430 
   431 
   431 
   432 	M_BUILD = 1
   432 	M_BUILD = 1
   433 	M_VERSION = 2	
   433 	M_VERSION = 2
   434 
   434 
   435 	def __init__(self, home = None):
   435 	def __init__(self, home = None):
   436 
   436 
   437 		self.DefaultSetUp(home)
   437 		self.DefaultSetUp(home)
   438 
   438 
   552 	def AddTarget(self, target):
   552 	def AddTarget(self, target):
   553 		if self.doCheck or self.doWhat:
   553 		if self.doCheck or self.doWhat:
   554 			self.Warn("ignoring target %s because --what or --check is specified.\n", target)
   554 			self.Warn("ignoring target %s because --what or --check is specified.\n", target)
   555 		else:
   555 		else:
   556 			self.targets.append(target)
   556 			self.targets.append(target)
   557 			
   557 
   558 	def AddSourceTarget(self, filename):
   558 	def AddSourceTarget(self, filename):
   559 		# source targets are sanitised and then added as if they were a "normal" makefile target
   559 		# source targets are sanitised and then added as if they were a "normal" makefile target
   560 		# in addition they have a default, empty, top-level target assigned in order that they can
   560 		# in addition they have a default, empty, top-level target assigned in order that they can
   561 		# be presented to any generated makefile without error
   561 		# be presented to any generated makefile without error
   562 		sourceTarget = generic_path.Path(filename).Absolute()
   562 		sourceTarget = generic_path.Path(filename).Absolute()
   613 		return True
   613 		return True
   614 
   614 
   615 	def SetNoDependInclude(self, TrueOrFalse):
   615 	def SetNoDependInclude(self, TrueOrFalse):
   616 		self.noDependInclude = TrueOrFalse
   616 		self.noDependInclude = TrueOrFalse
   617 		return True
   617 		return True
   618 		
   618 
   619 	def SetKeepGoing(self, TrueOrFalse):
   619 	def SetKeepGoing(self, TrueOrFalse):
   620 		self.keepGoing = TrueOrFalse
   620 		self.keepGoing = TrueOrFalse
   621 		return True
   621 		return True
   622 
   622 
   623 	def SetLogFileName(self, logfile):
   623 	def SetLogFileName(self, logfile):
   667 		else:
   667 		else:
   668 			self.Warn("toolcheck option must be one of: %s" % toolcheck_types)
   668 			self.Warn("toolcheck option must be one of: %s" % toolcheck_types)
   669 			return False
   669 			return False
   670 
   670 
   671 		return True
   671 		return True
   672 	
   672 
   673 	def SetTiming(self, TrueOrFalse):
   673 	def SetTiming(self, TrueOrFalse):
   674 		self.timing = TrueOrFalse
   674 		self.timing = TrueOrFalse
   675 		return True
   675 		return True
   676 
   676 
   677 	def SetParallelParsing(self, type):
   677 	def SetParallelParsing(self, type):
   715 
   715 
   716 		self.Info("%s %s", env, str(self.home))
   716 		self.Info("%s %s", env, str(self.home))
   717 		self.Info("Set-up %s", str(self.raptorXML))
   717 		self.Info("Set-up %s", str(self.raptorXML))
   718 		self.Info("Command-line-arguments %s", " ".join(self.args))
   718 		self.Info("Command-line-arguments %s", " ".join(self.args))
   719 		self.Info("Current working directory %s", os.getcwd())
   719 		self.Info("Current working directory %s", os.getcwd())
   720 		
   720 
   721 		# the inherited environment
   721 		# the inherited environment
   722 		for e, value in os.environ.items():
   722 		for e, value in sorted( os.environ.items() ):
   723 			self.Info("Environment %s=%s", e, value.replace("]]>", "]]&gt;"))
   723 			self.Info("Environment %s=%s", e, value.replace("]]>", "]]&gt;"))
   724 
   724 
   725 		# and some general debug stuff
   725 		# and some general debug stuff
   726 		self.Debug("Platform %s", "-".join(hostplatform))
   726 		self.Debug("Platform %s", "-".join(hostplatform))
   727 		self.Debug("Filesystem %s", self.filesystem)
   727 		self.Debug("Filesystem %s", self.filesystem)
   820 			absolute if required"""
   820 			absolute if required"""
   821 			if not aGenericPath.isAbsolute():
   821 			if not aGenericPath.isAbsolute():
   822 				return self.home.Append(aGenericPath)
   822 				return self.home.Append(aGenericPath)
   823 			else:
   823 			else:
   824 				return aGenericPath
   824 				return aGenericPath
   825 		
   825 
   826 		# make generic paths absolute (if required)
   826 		# make generic paths absolute (if required)
   827 		self.configPath = map(mkAbsolute, self.configPath)
   827 		self.configPath = map(mkAbsolute, self.configPath)
   828 		self.cache.Load(self.configPath)
   828 		self.cache.Load(self.configPath)
   829 
   829 
   830 		if not self.systemFLM.isAbsolute():
   830 		if not self.systemFLM.isAbsolute():
   857 		except KeyError:
   857 		except KeyError:
   858 			raise Exception("Unknown build configuration '%s'" % configname)
   858 			raise Exception("Unknown build configuration '%s'" % configname)
   859 		return x
   859 		return x
   860 
   860 
   861 	def GetBuildUnitsToBuild(self, configNames):
   861 	def GetBuildUnitsToBuild(self, configNames):
   862 		"""Return a list of the configuration objects that correspond to the 
   862 		"""Return a list of the configuration objects that correspond to the
   863 		   list of configuration names in the configNames parameter.
   863 		   list of configuration names in the configNames parameter.
   864 
   864 
   865 		raptor.GetBuildUnitsToBuild(["armv5", "winscw"])
   865 		raptor.GetBuildUnitsToBuild(["armv5", "winscw"])
   866 		>>> [ config1, config2, ... , configN ]
   866 		>>> [ config1, config2, ... , configN ]
   867 		""" 
   867 		"""
   868 
   868 
   869 		if len(configNames) == 0:
   869 		if len(configNames) == 0:
   870 			# use default config
   870 			# use default config
   871 			if len(self.defaultConfig) == 0:
   871 			if len(self.defaultConfig) == 0:
   872 				self.Warn("No default configuration name")
   872 				self.Warn("No default configuration name")
   876 		buildUnitsToBuild = set()
   876 		buildUnitsToBuild = set()
   877 
   877 
   878 
   878 
   879 		for c in set(configNames):
   879 		for c in set(configNames):
   880 			self.Debug("BuildUnit: %s", c)
   880 			self.Debug("BuildUnit: %s", c)
   881 			try:		
   881 			try:
   882 				x = self.GetConfig(c)
   882 				x = self.GetConfig(c)
   883 				gb = x.GenerateBuildUnits(self.cache) 
   883 				gb = x.GenerateBuildUnits(self.cache)
   884 				buildUnitsToBuild.update( gb )
   884 				buildUnitsToBuild.update( gb )
   885 			except Exception, e:
   885 			except Exception, e:
   886 				self.FatalError(str(e))
   886 				self.FatalError(str(e))
   887 
   887 
   888 		for b in buildUnitsToBuild:
   888 		for b in buildUnitsToBuild:
   892 			self.Error("No build configurations given")
   892 			self.Error("No build configurations given")
   893 
   893 
   894 		return buildUnitsToBuild
   894 		return buildUnitsToBuild
   895 
   895 
   896 	def CheckToolset(self, evaluator, configname):
   896 	def CheckToolset(self, evaluator, configname):
   897 		"""Check the toolset for a particular config, allow other objects access 
   897 		"""Check the toolset for a particular config, allow other objects access
   898 		to the toolset for this build (e.g. the raptor_make class)."""
   898 		to the toolset for this build (e.g. the raptor_make class)."""
   899 		if self.toolset is None:
   899 		if self.toolset is None:
   900 			if self.toolcheck == 'on':
   900 			if self.toolcheck == 'on':
   901 				self.toolset = raptor_data.ToolSet(log=self)
   901 				self.toolset = raptor_data.ToolSet(log=self)
   902 			elif self.toolcheck == 'forced' :
   902 			elif self.toolcheck == 'forced' :
   966 
   966 
   967 		return sysDef
   967 		return sysDef
   968 
   968 
   969 
   969 
   970 	def FindComponentIn(self, aDir = None):
   970 	def FindComponentIn(self, aDir = None):
   971 		# look for a bld.inf 
   971 		# look for a bld.inf
   972 
   972 
   973 		if aDir is None:
   973 		if aDir is None:
   974 			dir = generic_path.CurrentDir()
   974 			dir = generic_path.CurrentDir()
   975 		else:
   975 		else:
   976 			dir = generic_path.Path(aDir)
   976 			dir = generic_path.Path(aDir)
  1107 		"turn a dictionary into a string of XML attributes"
  1107 		"turn a dictionary into a string of XML attributes"
  1108 		atts = ""
  1108 		atts = ""
  1109 		for a,v in dictionary.items():
  1109 		for a,v in dictionary.items():
  1110 			atts += " " + a + "='" + v + "'"
  1110 			atts += " " + a + "='" + v + "'"
  1111 		return atts
  1111 		return atts
  1112 	
  1112 
  1113 	def Info(self, format, *extras, **attributes):
  1113 	def Info(self, format, *extras, **attributes):
  1114 		"""Send an information message to the configured channel
  1114 		"""Send an information message to the configured channel
  1115 				(XML control characters will be escaped)
  1115 				(XML control characters will be escaped)
  1116 		"""
  1116 		"""
  1117 		self.out.write("<info" + self.attributeString(attributes) + ">" +
  1117 		self.out.write("<info" + self.attributeString(attributes) + ">" +
  1118 		               escape(format % extras) + "</info>\n")
  1118 		               escape(format % extras) + "</info>\n")
  1119 		
  1119 
  1120 	def InfoDiscovery(self, object_type, count):
  1120 	def InfoDiscovery(self, object_type, count):
  1121 		if self.timing:
  1121 		if self.timing:
  1122 			try:
  1122 			try:
  1123 				self.out.write(raptor_timing.Timing.discovery_string(object_type = object_type,
  1123 				self.out.write(raptor_timing.Timing.discovery_string(object_type = object_type,
  1124 						count = count))
  1124 						count = count))
  1125 			except Exception, exception:
  1125 			except Exception, exception:
  1126 				Error(exception.Text, function = "InfoDiscoveryTime")
  1126 				Error(exception.Text, function = "InfoDiscoveryTime")
  1127 		
  1127 
  1128 	def InfoStartTime(self, object_type, task, key):
  1128 	def InfoStartTime(self, object_type, task, key):
  1129 		if self.timing:
  1129 		if self.timing:
  1130 			try:
  1130 			try:
  1131 				self.out.write(raptor_timing.Timing.start_string(object_type = object_type,
  1131 				self.out.write(raptor_timing.Timing.start_string(object_type = object_type,
  1132 						task = task, key = key))
  1132 						task = task, key = key))
  1133 			except Exception, exception:
  1133 			except Exception, exception:
  1134 				Error(exception.Text, function = "InfoStartTime")
  1134 				Error(exception.Text, function = "InfoStartTime")
  1135 		
  1135 
  1136 	def InfoEndTime(self, object_type, task, key):
  1136 	def InfoEndTime(self, object_type, task, key):
  1137 		if self.timing:
  1137 		if self.timing:
  1138 			try:
  1138 			try:
  1139 				self.out.write(raptor_timing.Timing.end_string(object_type = object_type,
  1139 				self.out.write(raptor_timing.Timing.end_string(object_type = object_type,
  1140 						task = task, key = key))
  1140 						task = task, key = key))
  1152 
  1152 
  1153 	def Warn(self, format, *extras, **attributes):
  1153 	def Warn(self, format, *extras, **attributes):
  1154 		"""Send a warning message to the configured channel
  1154 		"""Send a warning message to the configured channel
  1155 				(XML control characters will be escaped)
  1155 				(XML control characters will be escaped)
  1156 		"""
  1156 		"""
  1157 		self.out.write("<warning" + self.attributeString(attributes) + ">" + 
  1157 		self.out.write("<warning" + self.attributeString(attributes) + ">" +
  1158 		               escape(format % extras) + "</warning>\n")
  1158 		               escape(format % extras) + "</warning>\n")
  1159 
  1159 
  1160 	def FatalError(self, format, *extras, **attributes):
  1160 	def FatalError(self, format, *extras, **attributes):
  1161 		"""Send an error message to the configured channel. This implies such a serious
  1161 		"""Send an error message to the configured channel. This implies such a serious
  1162 		   error that the entire build must be shut down asap whilst still finishing off
  1162 		   error that the entire build must be shut down asap whilst still finishing off
  1163 		   correctly whatever housekeeping is possible e.g. producing error reports.
  1163 		   correctly whatever housekeeping is possible e.g. producing error reports.
  1164 		   Remains quiet if the raptor object is already in a fatal state since there
  1164 		   Remains quiet if the raptor object is already in a fatal state since there
  1165 		   further errors are probably triggered by the first.
  1165 		   further errors are probably triggered by the first.
  1166 		"""
  1166 		"""
  1167 		if not self.fatalErrorState:
  1167 		if not self.fatalErrorState:
  1168 			self.out.write("<error" + self.attributeString(attributes) + ">" + 
  1168 			self.out.write("<error" + self.attributeString(attributes) + ">" +
  1169 			               (format % extras) + "</error>\n")
  1169 			               (format % extras) + "</error>\n")
  1170 			self.errorCode = 1
  1170 			self.errorCode = 1
  1171 			self.fatalErrorState = True
  1171 			self.fatalErrorState = True
  1172 
  1172 
  1173 	def Error(self, format, *extras, **attributes):
  1173 	def Error(self, format, *extras, **attributes):
  1174 		"""Send an error message to the configured channel
  1174 		"""Send an error message to the configured channel
  1175 				(XML control characters will be escaped)
  1175 				(XML control characters will be escaped)
  1176 		"""
  1176 		"""
  1177 		self.out.write("<error" + self.attributeString(attributes) + ">" + 
  1177 		self.out.write("<error" + self.attributeString(attributes) + ">" +
  1178 		               escape(format % extras) + "</error>\n")
  1178 		               escape(format % extras) + "</error>\n")
  1179 		self.errorCode = 1
  1179 		self.errorCode = 1
  1180 
  1180 
  1181 
  1181 
  1182 	def PrintXML(self, format, *extras):
  1182 	def PrintXML(self, format, *extras):
  1210 
  1210 
  1211 		# If we now have a System Definition to parse then get the layers of components
  1211 		# If we now have a System Definition to parse then get the layers of components
  1212 		if self.systemDefinitionFile != None:
  1212 		if self.systemDefinitionFile != None:
  1213 			systemModel = raptor_xml.SystemModel(self, self.systemDefinitionFile, self.systemDefinitionBase)
  1213 			systemModel = raptor_xml.SystemModel(self, self.systemDefinitionFile, self.systemDefinitionBase)
  1214 			layers = self.GatherSysModelLayers(systemModel, self.systemDefinitionRequestedLayers)
  1214 			layers = self.GatherSysModelLayers(systemModel, self.systemDefinitionRequestedLayers)
  1215 			
  1215 
  1216 		# Now get components specified on a commandline - build them after any
  1216 		# Now get components specified on a commandline - build them after any
  1217 		# layers in the system definition.
  1217 		# layers in the system definition.
  1218 		if len(self.commandlineComponents) > 0:
  1218 		if len(self.commandlineComponents) > 0:
  1219 			layers.append(Layer('commandline',self.commandlineComponents))
  1219 			layers.append(Layer('commandline',self.commandlineComponents))
  1220 
  1220 
  1244 			# show the command and platform info
  1244 			# show the command and platform info
  1245 			self.AssertBuildOK()
  1245 			self.AssertBuildOK()
  1246 			self.Introduction()
  1246 			self.Introduction()
  1247 			# establish an object cache
  1247 			# establish an object cache
  1248 			self.AssertBuildOK()
  1248 			self.AssertBuildOK()
  1249 			
  1249 
  1250 			self.LoadCache()
  1250 			self.LoadCache()
  1251 
  1251 
  1252 			# find out what configurations to build
  1252 			# find out what configurations to build
  1253 			self.AssertBuildOK()
  1253 			self.AssertBuildOK()
  1254 			buildUnitsToBuild = self.GetBuildUnitsToBuild(self.configNames)
  1254 			buildUnitsToBuild = self.GetBuildUnitsToBuild(self.configNames)
  1297 
  1297 
  1298 				self.AssertBuildOK()
  1298 				self.AssertBuildOK()
  1299 				for l in layers:
  1299 				for l in layers:
  1300 					# create specs for a specific group of components
  1300 					# create specs for a specific group of components
  1301 					l.realise(self)
  1301 					l.realise(self)
  1302 					
  1302 
  1303 		except BuildCannotProgressException,b:
  1303 		except BuildCannotProgressException,b:
  1304 			if str(b) != "":
  1304 			if str(b) != "":
  1305 				self.Info(str(b))
  1305 				self.Info(str(b))
  1306 
  1306 
  1307 		# final report
  1307 		# final report
  1324 		build.AssertBuildOK()
  1324 		build.AssertBuildOK()
  1325 		build.ConfigFile()
  1325 		build.ConfigFile()
  1326 		build.ProcessConfig()
  1326 		build.ProcessConfig()
  1327 		build.CommandLine(argv)
  1327 		build.CommandLine(argv)
  1328 
  1328 
  1329 		return build 
  1329 		return build
  1330 
  1330 
  1331 
  1331 
  1332 
  1332 
  1333 # Class for passing constricted parameters to filters
  1333 # Class for passing constricted parameters to filters
  1334 class BuildStats(object):
  1334 class BuildStats(object):