sbsv2/raptor/python/plugins/filter_terminal.py
changeset 3 e1eecf4d390d
parent 0 044383f39525
child 45 0e5978b000d1
child 71 ba3ff6a1ecab
--- a/sbsv2/raptor/python/plugins/filter_terminal.py	Wed Oct 28 14:39:48 2009 +0000
+++ b/sbsv2/raptor/python/plugins/filter_terminal.py	Mon Nov 16 09:46:46 2009 +0000
@@ -1,422 +1,422 @@
-#
-# Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
-# All rights reserved.
-# This component and the accompanying materials are made available
-# under the terms of the License "Eclipse Public License v1.0"
-# which accompanies this distribution, and is available
-# at the URL "http://www.eclipse.org/legal/epl-v10.html".
-#
-# Initial Contributors:
-# Nokia Corporation - initial contribution.
-#
-# Contributors:
-#
-# Description: 
-# Filter class for filtering XML logs and generating reports
-# Prints errors and warnings to stdout
-#
-
-import sys
-import raptor
-import filter_interface
-import generic_path
-import os
-import os.path
-import re
-
-class Recipe(object):
-	"""State machine that parses a recipe
-	"""
-
-	suppress = []
-	warningRE = re.compile("^.*((Warning:)|(MAKEDEF WARNING:)) .*$", re.DOTALL | re.M | re.I)
-	infoRE = None
-	name = [ "default" ]
-	recipes = []
-
-	def __init__(self, text):
-		self.suppress = self.__class__.suppress
-		self.text = text
-		self.warningRE = Recipe.warningRE
-	
-	def warnings(self):
-		return self.warningRE.findall(self.text)
-
-	def info(self):
-		if self.infoRE:
-			return self.infoRE.findall(self.text)
-		else:
-			return []
-
-	@classmethod			
-	def factory(cls, name, text):
-		for r in Recipe.recipes:
-			if name in r.name:
-				return r(text)
-		return Recipe(text)
-	
-
-class MwLinkerRecipe(Recipe):
-	suppress = [ 
-		re.compile(
-r"^mwldsym2: warning: Cannot locate library \"MSL_All_Static_MSE_Symbian\" specified in #pragma comment\(lib,...\)$"
-r"[\n\r]*mwldsym2: warning: referenced from.*$"
-r"[\n\r]*mwldsym2: warning: Option 'Use default libraries' is enabled but linker used.*$"
-r"[\n\r]*mwldsym2: warning: runtime library from MW\[...\]LibraryFiles \(msl_all_static_mse_symbian_d.lib\);$"
-r"[\n\r]*mwldsym2: warning: this indicates a potential settings/libraries mismatch.*$"
-		, re.M)
-		, re.compile(
-r"^mwldsym2.exe: warning: Multiply defined symbol: ___get_MSL_init_count in.*$"
-r"[\n\r]*mwldsym2.exe: warning: files uc_cwhelp.obj \(.*\), startup.win32.c.obj \(msl_all_static_mse_symbian_d.lib\),.*$"
-r"[\n\r]*mwldsym2.exe: warning: keeping definition in startup.win32.c.obj.*$"
-		, re.M )
-		, re.compile(
-r"^mwldsym2.exe: warning: Option 'Use default libraries' is enabled but linker used.*$"
-r"[\n\r]*mwldsym2.exe: warning: runtime library from MW\[...\]LibraryFiles \(msl_all_static_mse_symbian_d.lib\);.*$"
-r"[\n\r]*mwldsym2.exe: warning: this indicates a potential settings/libraries mismatch.*$"
-	, re.M)
-	]
-	name = [ "win32stagetwolink", "win32simplelink" ]
-
-	def warnings(self):
-		edited = self.text
-		for s in MwLinkerRecipe.suppress:
-			edited = s.sub("", edited)
-		return Recipe.warningRE.findall(edited)
-
-Recipe.recipes.append(MwLinkerRecipe)
-
-
-class FreezeRecipe(Recipe):
-	name = [ "freeze" ]
-	warningRE = re.compile("^(WARNING:) .*$", re.DOTALL | re.M | re.I)
-	infoRE = re.compile("^(EFREEZE:) .*$", re.DOTALL | re.M | re.I)
-
-	def __init__(self, text):
-		Recipe.__init__(self, text)
-		self.warningRE = FreezeRecipe.warningRE
-		self.infoRE = FreezeRecipe.infoRE
-
-Recipe.recipes.append(FreezeRecipe)
-
-
-
-class FilterTerminal(filter_interface.Filter):
-
-	attribute_re = re.compile("([a-z][a-z0-9]*)='([^']*)'",re.I)
-	maxdots = 40 # if one prints dots then don't print masses
-	recipelinelimit = 200 # don't scan ultra-long recipes in case we run out of memory
-
-	# recipes that we think most users are interested in
-	# and the mapping that we will use to output them as
-	docare = {
-		"asmcompile" : "asmcompile" ,
-		"compile" : "compile" ,
-		"postlink" : "target",
-		"resourcecompile" : "resource",
-		"genstringtable" : "strtable",
-		"tem" : "tem",
-		"bitmapcompile" : "bitmap",
-		"bitmapcopy" : "bitmapcopy",
-		"win32compile2object" : "compile",
-		"win32stagetwolink" : "target",
-		"win32simplelink" : "target",
-		"tools2install" : "target",
-		"compile2object" : "compile",
-		"msvctoolsinstall" : "target",
-		"msvctoolscompile" : "compile",
-		"freeze" : "freeze",
-		"win32archive" : "target"
-	}
-
-	# Determine the width of the largest mapped recipe name
-	recipewidth = 0
-	for i in docare:
-		l = len(docare[i])
-		if l > recipewidth:
-			recipewidth = l # justification for printing out recipes.
-	recipewidth+=1
-
-	def __init__(self):
-		self.analyseonly = False
-		self.quiet = False
-		# defaults can use EPOCROOT
-		if "EPOCROOT" in os.environ:
-			self.epocroot = str(generic_path.Path(os.environ["EPOCROOT"]))
-		else:
-			self.epocroot = str(generic_path.Path('/'))
-		self.current_recipe_logged = False
-		self.cleaned = 0  # cleaned files
-		self.dotcount = 0 # progress dots printed so far
-		# list of strings to catch make errors (must be lowercase)
-		self.make_error_expr = set([
-				"error:",
-				": ***",
-				"make: interrupt/exception caught (code =",
-				"make.exe: interrupt/exception caught (code ="
-				])
-		# list of strings to catch make warnings (must be lowercase)
-		self.make_warning_expr = ["warning:"]
-
-		# list of strings to catch recipe warnings (must be lowercase)
-		self.recipe_warning_expr = ["warning:"]
-
-	def isMakeWarning(self, text):
-                """A simple test for warnings.
-                Can be extended do to more comprehensive checking."""
-		# generic warnings checked
-		# array of make_warning_expr holds all the possible values
-		for warn in self.make_warning_expr:
-			if warn in text.lower():
-				return True
-	
-		return False
-
-
-	def isMakeError(self, text):
-		"""A simple test for errors.	
-		Can be extended to do more comprehensive checking."""
-
-		# make, emake and pvmgmake spit out things like
-		# make: *** No rule to make target X, needed by Y. Stop.
-		#
-		# array of make_error_expr holds all the possible values
-		for err in self.make_error_expr:
-			if err in text.lower():
-				return True
-		
-		return False
-
-
-	def open(self, raptor_instance):
-		"""Set output to stdout for the various I/O methods to write to."""
-		self.raptor = raptor_instance
-
-		# Be totally silent?
-		if self.raptor.logFileName is None:
-			self.analyseonly = True
-
-		# Only print errors and warnings?
-		if self.raptor.quiet:
-			self.quiet = True
-		
-		# keep count of errors and warnings
-		self.err_count = 0
-		self.warn_count = 0
-		self.suppressed_warn_count = 0
-		self.inBody = False
-		self.inRecipe = False
-		return True
-		
-	def write(self, text):
-		"""Write errors and warnings to stdout"""
-		
-		if text.startswith("<error"):
-			start = text.find(">")
-			end = text.rfind("<")
-			self.err_count += 1
-			if not self.analyseonly:
-				sys.stderr.write(str(raptor.name) + ": error: %s\n" \
-						% text[(start + 1):end])
-		elif text.startswith("<warning"):
-			start = text.find(">")
-			end = text.rfind("<")
-			self.warn_count += 1
-			if not self.analyseonly:
-				sys.stdout.write(str(raptor.name) + ": warning: %s\n" \
-					% text[(start + 1):end])
-		elif text.startswith("<status "):
-			# detect the status report from a recipe
-			if text.find('failed') != -1:
-				self.failed = True
-			else:
-				self.failed = False
-			return
-		elif text.startswith("<recipe "):
-			# detect the start of a recipe
-			if self.inRecipe:
-				sys.stdout.flush()
-				sys.stderr.write(self.formatError("Opening recipe tag found " \
-						+ "before closing recipe tag for previous recipe:\n" \
-						+ "Discarding previous recipe (Possible logfile " \
-						+ "corruption)"))
-				sys.stderr.flush()
-			self.inRecipe = True
-			self.current_recipe_logged = False
-			m = FilterTerminal.attribute_re.findall(text)
-			self.recipe_dict = dict ()
-			for i in m:
-				self.recipe_dict[i[0]] = i[1]
-
-			# Decide what to tell the user about this recipe
-			# The target file or the source file?  
-			name = None
-			if 'source' in self.recipe_dict:
-				name = self.recipe_dict['source']
-
-			name_to_user = ""
-			# Make source files relative to the current directory if they are 
-		 	# not generated files in epocroot.  Also make sure path is in 
-			# the appropriate format for the user's shell.
-			if name and (name.find("epoc32") == -1 or name.endswith('.UID.CPP')):
-				for i in name.rsplit():
-					name_to_user += " " + generic_path.Path(i).From(generic_path.CurrentDir()).GetShellPath()
-			else:
-				# using the target.  Shorten it if it's in epocroot by just chopping off
-				# epocroot
-				name_to_user = self.recipe_dict['target']
-				if name_to_user.find(self.epocroot) != -1:
-					name_to_user = name_to_user.replace(self.epocroot,"")
-					if name_to_user.startswith('/') or name_to_user.startswith('\\'):
-						name_to_user = name_to_user[1:]
-				name_to_user = generic_path.Path(name_to_user).GetShellPath()	
-			self.recipe_dict['name_to_user'] = name_to_user
-			self.recipe_dict['mappedname'] = self.recipe_dict['name'] 
-
-			# Status message to indicate that we are building
-			recipename = self.recipe_dict['name']
-			if recipename in FilterTerminal.docare:
-				self.recipe_dict['mappedname'] = FilterTerminal.docare[recipename]
-				self.logit_if()
-
-			# This variable holds all recipe information
-			self.failed = False # Recipe status
-			self.recipeBody = []
-			return		
-		elif text.startswith("</recipe>"):
-			# detect the end of a recipe
-			if not self.inRecipe:
-				sys.stdout.flush()
-				sys.stderr.write(self.formatError("Closing recipe tag found " \
-						+ "before opening recipe tag:\nUnable to print " \
-						+ "recipe data (Possible logfile corruption)"))
-				sys.stderr.flush()
-			else:
-				self.inRecipe = False
-				
-				if self.failed == True:
-					if not self.analyseonly:
-						sys.stderr.write("\n FAILED %s for %s: %s\n" % \
-								(self.recipe_dict['name'],
-								self.recipe_dict['config'],
-								self.recipe_dict['name_to_user']))
-	
-						mmppath = generic_path.Path(self.recipe_dict['mmp']).From(generic_path.CurrentDir()).GetShellPath()
-						sys.stderr.write("  mmp: %s\n" % mmppath)
-						for L in self.recipeBody:
-							if not L.startswith('+'):
-								sys.stdout.write("   %s\n" % L.rstrip())
-					self.err_count += 1
-				else:
-					r = Recipe.factory(self.recipe_dict['name'], "".join(self.recipeBody))
-					warnings = r.warnings()
-					info = r.info()
-					if len(warnings) > 0:
-						if not self.analyseonly:
-							for L in self.recipeBody:
-								if not L.startswith('+'):
-									sys.stdout.write("   %s\n" % L.rstrip())
-						self.warn_count += len(warnings)
-	
-				self.recipeBody = []
-			return
-		elif not self.inRecipe and self.isMakeError(text):
-			# these two statements pick up errors coming from make
-			self.err_count += 1
-			sys.stderr.write("    %s\n" % text.rstrip())
-			return
-		elif not self.inRecipe and self.isMakeWarning(text):
-			self.warn_count += 1
-			sys.stdout.write("    %s\n" % text.rstrip())
-			return
-		elif text.startswith("<![CDATA["):
-                	# save CDATA body during a recipe
-			if self.inRecipe:
-				self.inBody = True
-		elif text.startswith("]]>"):
-			if self.inRecipe:
-				self.inBody = False
-		elif text.startswith("<info>Copied"):
-			if not self.analyseonly and not self.quiet:
-				start = text.find(" to ") + 4
-				end = text.find("</info>",start)
-				short_target = text[start:end]
-				if short_target.startswith(self.epocroot):
-					short_target = short_target.replace(self.epocroot,"")[1:]
-				short_target = generic_path.Path(short_target).GetShellPath()
-				sys.stdout.write(" %s: %s\n" % ("export".ljust(FilterTerminal.recipewidth), short_target))
-			return
-		elif text.find("<rm files") != -1 or text.find("<rmdir ") != -1:
-			# search for cleaning output but only if we 
-			# are not in some recipe (that would be pointless)
-			if not self.analyseonly and not self.quiet:
-				if  self.cleaned == 0:
-					sys.stdout.write("\ncleaning ")
-					self.cleaned+=1
-				elif self.dotcount < FilterTerminal.maxdots:
-					if self.cleaned % 5 == 0:
-						self.dotcount+=1
-						sys.stdout.write(".")
-					self.cleaned+=1
-			
-				return
-		elif self.inBody:
-			# We are parsing the output from a recipe
-			# we have to keep the output until we find out
-			# if the recipe failed. But not all of it if it turns
-			# out to be very long
-			if len(self.recipeBody) < FilterTerminal.recipelinelimit:
-				self.recipeBody.append(text)
-
-	def logit(self):
-		""" log a message """
-		info = self.recipe_dict['mappedname'].ljust(FilterTerminal.recipewidth)
-		config = self.recipe_dict['config']
-		name = self.recipe_dict['name_to_user'].lstrip()
-		# If its a multifile config, we print source files one below the other in a single
-		# 'compile:' statement
-		if config.endswith('multifile'):
-			files =  self.recipe_dict['name_to_user'].split()
-			name = ""
-			for i in files:
-				if i == files[0]:
-					name +=  i
-				else:
-					name +=  '\n\t      ' + i
-		sys.stdout.write(" %s: %s  \t[%s]\n" % (info, name, config))
-
-	def logit_if(self):
-		""" Tell the user about the recipe that we are processing """
-		if not self.analyseonly and not self.quiet:
-			if self.inRecipe and not self.current_recipe_logged:
-				self.logit()
-				self.current_recipe_logged = True
-	
-	def summary(self):
-		"""Errors and warnings summary"""
-		
-		if self.raptor.skipAll or self.analyseonly:
-			return
-
-
-		if self.cleaned != 0:
-			sys.stdout.write("\n\n")
-
-		if self.warn_count > 0 or self.err_count > 0:
-			sys.stdout.write("\n%s : warnings: %s\n" % (raptor.name,
-					self.warn_count))
-			sys.stdout.write("%s : errors: %s\n" % (raptor.name,
-					self.err_count))
-		else:
-			sys.stdout.write("\nno warnings or errors\n")
-
-		sys.stdout.write("\nRun time %d seconds\n" % self.raptor.runtime);
-		sys.stdout.write("\n")
-		return True
-	
-	def close(self):
-		"""Tell raptor that there were errors."""
-		if self.err_count > 0:
-			return False
-		return True
-
+#
+# Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description: 
+# Filter class for filtering XML logs and generating reports
+# Prints errors and warnings to stdout
+#
+
+import sys
+import raptor
+import filter_interface
+import generic_path
+import os
+import os.path
+import re
+
+class Recipe(object):
+	"""State machine that parses a recipe
+	"""
+
+	suppress = []
+	warningRE = re.compile("^.*((Warning:)|(MAKEDEF WARNING:)) .*$", re.DOTALL | re.M | re.I)
+	infoRE = None
+	name = [ "default" ]
+	recipes = []
+
+	def __init__(self, text):
+		self.suppress = self.__class__.suppress
+		self.text = text
+		self.warningRE = Recipe.warningRE
+	
+	def warnings(self):
+		return self.warningRE.findall(self.text)
+
+	def info(self):
+		if self.infoRE:
+			return self.infoRE.findall(self.text)
+		else:
+			return []
+
+	@classmethod			
+	def factory(cls, name, text):
+		for r in Recipe.recipes:
+			if name in r.name:
+				return r(text)
+		return Recipe(text)
+	
+
+class MwLinkerRecipe(Recipe):
+	suppress = [ 
+		re.compile(
+r"^mwldsym2: warning: Cannot locate library \"MSL_All_Static_MSE_Symbian\" specified in #pragma comment\(lib,...\)$"
+r"[\n\r]*mwldsym2: warning: referenced from.*$"
+r"[\n\r]*mwldsym2: warning: Option 'Use default libraries' is enabled but linker used.*$"
+r"[\n\r]*mwldsym2: warning: runtime library from MW\[...\]LibraryFiles \(msl_all_static_mse_symbian_d.lib\);$"
+r"[\n\r]*mwldsym2: warning: this indicates a potential settings/libraries mismatch.*$"
+		, re.M)
+		, re.compile(
+r"^mwldsym2.exe: warning: Multiply defined symbol: ___get_MSL_init_count in.*$"
+r"[\n\r]*mwldsym2.exe: warning: files uc_cwhelp.obj \(.*\), startup.win32.c.obj \(msl_all_static_mse_symbian_d.lib\),.*$"
+r"[\n\r]*mwldsym2.exe: warning: keeping definition in startup.win32.c.obj.*$"
+		, re.M )
+		, re.compile(
+r"^mwldsym2.exe: warning: Option 'Use default libraries' is enabled but linker used.*$"
+r"[\n\r]*mwldsym2.exe: warning: runtime library from MW\[...\]LibraryFiles \(msl_all_static_mse_symbian_d.lib\);.*$"
+r"[\n\r]*mwldsym2.exe: warning: this indicates a potential settings/libraries mismatch.*$"
+	, re.M)
+	]
+	name = [ "win32stagetwolink", "win32simplelink" ]
+
+	def warnings(self):
+		edited = self.text
+		for s in MwLinkerRecipe.suppress:
+			edited = s.sub("", edited)
+		return Recipe.warningRE.findall(edited)
+
+Recipe.recipes.append(MwLinkerRecipe)
+
+
+class FreezeRecipe(Recipe):
+	name = [ "freeze" ]
+	warningRE = re.compile("^(WARNING:) .*$", re.DOTALL | re.M | re.I)
+	infoRE = re.compile("^(EFREEZE:) .*$", re.DOTALL | re.M | re.I)
+
+	def __init__(self, text):
+		Recipe.__init__(self, text)
+		self.warningRE = FreezeRecipe.warningRE
+		self.infoRE = FreezeRecipe.infoRE
+
+Recipe.recipes.append(FreezeRecipe)
+
+
+
+class FilterTerminal(filter_interface.Filter):
+
+	attribute_re = re.compile("([a-z][a-z0-9]*)='([^']*)'",re.I)
+	maxdots = 40 # if one prints dots then don't print masses
+	recipelinelimit = 200 # don't scan ultra-long recipes in case we run out of memory
+
+	# recipes that we think most users are interested in
+	# and the mapping that we will use to output them as
+	docare = {
+		"asmcompile" : "asmcompile" ,
+		"compile" : "compile" ,
+		"postlink" : "target",
+		"resourcecompile" : "resource",
+		"genstringtable" : "strtable",
+		"tem" : "tem",
+		"bitmapcompile" : "bitmap",
+		"bitmapcopy" : "bitmapcopy",
+		"win32compile2object" : "compile",
+		"win32stagetwolink" : "target",
+		"win32simplelink" : "target",
+		"tools2install" : "target",
+		"compile2object" : "compile",
+		"msvctoolsinstall" : "target",
+		"msvctoolscompile" : "compile",
+		"freeze" : "freeze",
+		"win32archive" : "target"
+	}
+
+	# Determine the width of the largest mapped recipe name
+	recipewidth = 0
+	for i in docare:
+		l = len(docare[i])
+		if l > recipewidth:
+			recipewidth = l # justification for printing out recipes.
+	recipewidth+=1
+
+	def __init__(self):
+		self.analyseonly = False
+		self.quiet = False
+		# defaults can use EPOCROOT
+		if "EPOCROOT" in os.environ:
+			self.epocroot = str(generic_path.Path(os.environ["EPOCROOT"]))
+		else:
+			self.epocroot = str(generic_path.Path('/'))
+		self.current_recipe_logged = False
+		self.cleaned = 0  # cleaned files
+		self.dotcount = 0 # progress dots printed so far
+		# list of strings to catch make errors (must be lowercase)
+		self.make_error_expr = set([
+				"error:",
+				": ***",
+				"make: interrupt/exception caught (code =",
+				"make.exe: interrupt/exception caught (code ="
+				])
+		# list of strings to catch make warnings (must be lowercase)
+		self.make_warning_expr = ["warning:"]
+
+		# list of strings to catch recipe warnings (must be lowercase)
+		self.recipe_warning_expr = ["warning:"]
+
+	def isMakeWarning(self, text):
+                """A simple test for warnings.
+                Can be extended do to more comprehensive checking."""
+		# generic warnings checked
+		# array of make_warning_expr holds all the possible values
+		for warn in self.make_warning_expr:
+			if warn in text.lower():
+				return True
+	
+		return False
+
+
+	def isMakeError(self, text):
+		"""A simple test for errors.	
+		Can be extended to do more comprehensive checking."""
+
+		# make, emake and pvmgmake spit out things like
+		# make: *** No rule to make target X, needed by Y. Stop.
+		#
+		# array of make_error_expr holds all the possible values
+		for err in self.make_error_expr:
+			if err in text.lower():
+				return True
+		
+		return False
+
+
+	def open(self, raptor_instance):
+		"""Set output to stdout for the various I/O methods to write to."""
+		self.raptor = raptor_instance
+
+		# Be totally silent?
+		if self.raptor.logFileName is None:
+			self.analyseonly = True
+
+		# Only print errors and warnings?
+		if self.raptor.quiet:
+			self.quiet = True
+		
+		# keep count of errors and warnings
+		self.err_count = 0
+		self.warn_count = 0
+		self.suppressed_warn_count = 0
+		self.inBody = False
+		self.inRecipe = False
+		return True
+		
+	def write(self, text):
+		"""Write errors and warnings to stdout"""
+		
+		if text.startswith("<error"):
+			start = text.find(">")
+			end = text.rfind("<")
+			self.err_count += 1
+			if not self.analyseonly:
+				sys.stderr.write(str(raptor.name) + ": error: %s\n" \
+						% text[(start + 1):end])
+		elif text.startswith("<warning"):
+			start = text.find(">")
+			end = text.rfind("<")
+			self.warn_count += 1
+			if not self.analyseonly:
+				sys.stdout.write(str(raptor.name) + ": warning: %s\n" \
+					% text[(start + 1):end])
+		elif text.startswith("<status "):
+			# detect the status report from a recipe
+			if text.find('failed') != -1:
+				self.failed = True
+			else:
+				self.failed = False
+			return
+		elif text.startswith("<recipe "):
+			# detect the start of a recipe
+			if self.inRecipe:
+				sys.stdout.flush()
+				sys.stderr.write(self.formatError("Opening recipe tag found " \
+						+ "before closing recipe tag for previous recipe:\n" \
+						+ "Discarding previous recipe (Possible logfile " \
+						+ "corruption)"))
+				sys.stderr.flush()
+			self.inRecipe = True
+			self.current_recipe_logged = False
+			m = FilterTerminal.attribute_re.findall(text)
+			self.recipe_dict = dict ()
+			for i in m:
+				self.recipe_dict[i[0]] = i[1]
+
+			# Decide what to tell the user about this recipe
+			# The target file or the source file?  
+			name = None
+			if 'source' in self.recipe_dict:
+				name = self.recipe_dict['source']
+
+			name_to_user = ""
+			# Make source files relative to the current directory if they are 
+		 	# not generated files in epocroot.  Also make sure path is in 
+			# the appropriate format for the user's shell.
+			if name and (name.find("epoc32") == -1 or name.endswith('.UID.CPP')):
+				for i in name.rsplit():
+					name_to_user += " " + generic_path.Path(i).From(generic_path.CurrentDir()).GetShellPath()
+			else:
+				# using the target.  Shorten it if it's in epocroot by just chopping off
+				# epocroot
+				name_to_user = self.recipe_dict['target']
+				if name_to_user.find(self.epocroot) != -1:
+					name_to_user = name_to_user.replace(self.epocroot,"")
+					if name_to_user.startswith('/') or name_to_user.startswith('\\'):
+						name_to_user = name_to_user[1:]
+				name_to_user = generic_path.Path(name_to_user).GetShellPath()	
+			self.recipe_dict['name_to_user'] = name_to_user
+			self.recipe_dict['mappedname'] = self.recipe_dict['name'] 
+
+			# Status message to indicate that we are building
+			recipename = self.recipe_dict['name']
+			if recipename in FilterTerminal.docare:
+				self.recipe_dict['mappedname'] = FilterTerminal.docare[recipename]
+				self.logit_if()
+
+			# This variable holds all recipe information
+			self.failed = False # Recipe status
+			self.recipeBody = []
+			return		
+		elif text.startswith("</recipe>"):
+			# detect the end of a recipe
+			if not self.inRecipe:
+				sys.stdout.flush()
+				sys.stderr.write(self.formatError("Closing recipe tag found " \
+						+ "before opening recipe tag:\nUnable to print " \
+						+ "recipe data (Possible logfile corruption)"))
+				sys.stderr.flush()
+			else:
+				self.inRecipe = False
+				
+				if self.failed == True:
+					if not self.analyseonly:
+						sys.stderr.write("\n FAILED %s for %s: %s\n" % \
+								(self.recipe_dict['name'],
+								self.recipe_dict['config'],
+								self.recipe_dict['name_to_user']))
+	
+						mmppath = generic_path.Path(self.recipe_dict['mmp']).From(generic_path.CurrentDir()).GetShellPath()
+						sys.stderr.write("  mmp: %s\n" % mmppath)
+						for L in self.recipeBody:
+							if not L.startswith('+'):
+								sys.stdout.write("   %s\n" % L.rstrip())
+					self.err_count += 1
+				else:
+					r = Recipe.factory(self.recipe_dict['name'], "".join(self.recipeBody))
+					warnings = r.warnings()
+					info = r.info()
+					if len(warnings) > 0:
+						if not self.analyseonly:
+							for L in self.recipeBody:
+								if not L.startswith('+'):
+									sys.stdout.write("   %s\n" % L.rstrip())
+						self.warn_count += len(warnings)
+	
+				self.recipeBody = []
+			return
+		elif not self.inRecipe and self.isMakeError(text):
+			# these two statements pick up errors coming from make
+			self.err_count += 1
+			sys.stderr.write("    %s\n" % text.rstrip())
+			return
+		elif not self.inRecipe and self.isMakeWarning(text):
+			self.warn_count += 1
+			sys.stdout.write("    %s\n" % text.rstrip())
+			return
+		elif text.startswith("<![CDATA["):
+                	# save CDATA body during a recipe
+			if self.inRecipe:
+				self.inBody = True
+		elif text.startswith("]]>"):
+			if self.inRecipe:
+				self.inBody = False
+		elif text.startswith("<info>Copied"):
+			if not self.analyseonly and not self.quiet:
+				start = text.find(" to ") + 4
+				end = text.find("</info>",start)
+				short_target = text[start:end]
+				if short_target.startswith(self.epocroot):
+					short_target = short_target.replace(self.epocroot,"")[1:]
+				short_target = generic_path.Path(short_target).GetShellPath()
+				sys.stdout.write(" %s: %s\n" % ("export".ljust(FilterTerminal.recipewidth), short_target))
+			return
+		elif text.find("<rm files") != -1 or text.find("<rmdir ") != -1:
+			# search for cleaning output but only if we 
+			# are not in some recipe (that would be pointless)
+			if not self.analyseonly and not self.quiet:
+				if  self.cleaned == 0:
+					sys.stdout.write("\ncleaning ")
+					self.cleaned+=1
+				elif self.dotcount < FilterTerminal.maxdots:
+					if self.cleaned % 5 == 0:
+						self.dotcount+=1
+						sys.stdout.write(".")
+					self.cleaned+=1
+			
+				return
+		elif self.inBody:
+			# We are parsing the output from a recipe
+			# we have to keep the output until we find out
+			# if the recipe failed. But not all of it if it turns
+			# out to be very long
+			if len(self.recipeBody) < FilterTerminal.recipelinelimit:
+				self.recipeBody.append(text)
+
+	def logit(self):
+		""" log a message """
+		info = self.recipe_dict['mappedname'].ljust(FilterTerminal.recipewidth)
+		config = self.recipe_dict['config']
+		name = self.recipe_dict['name_to_user'].lstrip()
+		# If its a multifile config, we print source files one below the other in a single
+		# 'compile:' statement
+		if config.endswith('multifile'):
+			files =  self.recipe_dict['name_to_user'].split()
+			name = ""
+			for i in files:
+				if i == files[0]:
+					name +=  i
+				else:
+					name +=  '\n\t      ' + i
+		sys.stdout.write(" %s: %s  \t[%s]\n" % (info, name, config))
+
+	def logit_if(self):
+		""" Tell the user about the recipe that we are processing """
+		if not self.analyseonly and not self.quiet:
+			if self.inRecipe and not self.current_recipe_logged:
+				self.logit()
+				self.current_recipe_logged = True
+	
+	def summary(self):
+		"""Errors and warnings summary"""
+		
+		if self.raptor.skipAll or self.analyseonly:
+			return
+
+
+		if self.cleaned != 0:
+			sys.stdout.write("\n\n")
+
+		if self.warn_count > 0 or self.err_count > 0:
+			sys.stdout.write("\n%s : warnings: %s\n" % (raptor.name,
+					self.warn_count))
+			sys.stdout.write("%s : errors: %s\n" % (raptor.name,
+					self.err_count))
+		else:
+			sys.stdout.write("\nno warnings or errors\n")
+
+		sys.stdout.write("\nRun time %d seconds\n" % self.raptor.runtime);
+		sys.stdout.write("\n")
+		return True
+	
+	def close(self):
+		"""Tell raptor that there were errors."""
+		if self.err_count > 0:
+			return False
+		return True
+