diff -r 000000000000 -r 044383f39525 sbsv2/raptor/python/plugins/filter_terminal.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sbsv2/raptor/python/plugins/filter_terminal.py Tue Oct 27 16:36:35 2009 +0000 @@ -0,0 +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("") + 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("") + 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(""): + # 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(""): + if self.inRecipe: + self.inBody = False + elif text.startswith("Copied"): + if not self.analyseonly and not self.quiet: + start = text.find(" to ") + 4 + end = text.find("",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(" 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 +