From b107617d46701cb67b7b2ad00b8613d77bfa19c0 Mon Sep 17 00:00:00 2001 From: Henrik Nilsson Date: Tue, 8 Dec 2009 15:09:21 -0500 Subject: [PATCH 1/4] Added a python script that takes the cppcheck output xml file and generates a html report of it. The html report is complete with syntax highlighted source code using the pygments module. This initial commit contains generation of html files but the actual errors is missing from the html content and the index.html file. --- htmlreport/README.txt | 7 ++ htmlreport/cppcheck-htmlreport | 130 +++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 htmlreport/README.txt create mode 100755 htmlreport/cppcheck-htmlreport diff --git a/htmlreport/README.txt b/htmlreport/README.txt new file mode 100644 index 000000000..8efd06df2 --- /dev/null +++ b/htmlreport/README.txt @@ -0,0 +1,7 @@ +cppcheck-htmlreport + +This is a little utility to generate a html report of a xml file produced by +cppcheck. + +The utility is implemented in python and require the pygments module to be +able to generate syntax highlighted source code. diff --git a/htmlreport/cppcheck-htmlreport b/htmlreport/cppcheck-htmlreport new file mode 100755 index 000000000..c23540a0a --- /dev/null +++ b/htmlreport/cppcheck-htmlreport @@ -0,0 +1,130 @@ +#!/usr/bin/python +import sys +import optparse +import os +import os.path +from pygments import highlight +from pygments.lexers import CppLexer +from pygments.formatters import HtmlFormatter +from xml.sax import parse as xml_parse +from xml.sax import SAXParseException as XmlParseException +from xml.sax.handler import ContentHandler as XmlContentHandler + +""" +Turns a cppcheck xml file into a browsable html report along +with syntax highlighted source code. +""" + +HTML_HEAD = """ + + + CppCheck - Html report + + + +""" + +HTML_FOOTER = """ + + +""" + +class CppCheckHandler(XmlContentHandler): + """Parses the cppcheck xml file and produces a list of all its errors.""" + errors = [] + + def startElement(self, name, attributes): + if name != "error": + return + + self.errors.append( + { + "file" : attributes["file"], + "line" : attributes["line"], + "id" : attributes["id"], + "severity" : attributes["severity"], + "msg" : attributes["msg"] + }) + +if __name__ == '__main__': + # Configure all the options this little utility is using. + parser = optparse.OptionParser() + parser.add_option("--file", dest="file", help="The cppcheck xml output file to read defects from. Default is reading from stdin.") + parser.add_option("--report-dir", dest="report_dir", help="The directory where the html report content is written.") + parser.add_option("--source-dir", dest="source_dir", help="Base directory where source code files can be found.") + + # Parse options and make sure that we have an output directory set. + options, args = parser.parse_args() + if not options.report_dir: + parser.error("No report directory set.") + + # Get the directory where source code files are located. + source_dir = os.getcwd() + if options.source_dir: + source_dir = options.source_dir + + # Get the stream that we read cppcheck errors from. + stream = sys.stdin + if options.file: + if os.path.exists(options.file) == False: + parser.error("cppcheck xml file: %s not found." % options.file) + stream = open(options.file, "r") + + # Parse the xml file and produce a simple list of errors. + print("Parsing xml report.") + try: + contentHandler = CppCheckHandler() + xml_parse(stream, contentHandler) + except XmlParseException, msg: + print("Failed to parse cppcheck xml file: %s" % msg) + sys.exit(1) + + # We have a list of errors. But now we want to group them on + # each source code file. Lets create a files dictionary that + # will contain a list of all the errors in that file. For each + # file we will also generate a html filename to use. + files = {} + file_no = 0 + for error in contentHandler.errors: + filename = error["file"] + if filename not in files.keys(): + files[filename] = { "errors" : [], "htmlfile" : str(file_no) + ".html" } + file_no = file_no + 1 + files[filename]["errors"].append(error) + + # Make sure that the report directory is created if it doesn't exist. + print("Creating %s directory" % options.report_dir) + if not os.path.exists(options.report_dir): + os.mkdir(options.report_dir) + + # Generate a html file with syntax highlighted source code for each + # file that contains one or more errors. + print("Processing errors") + for filename, data in files.iteritems(): + htmlfile = data["htmlfile"] + errors = data["errors"] + + stream = file(os.path.join(source_dir, filename)) + content = stream.read() + stream.close() + + htmlFormatter = HtmlFormatter(linenos=True, style='colorful', full=True) + stream = file(os.path.join(options.report_dir, htmlfile), "w") + stream.write(HTML_HEAD) + stream.write(highlight(content, CppLexer(), htmlFormatter)) + stream.write(HTML_FOOTER) + stream.close() + + print(" " + filename) + + # Generate a master index.html file that will contain a list of + # all the errors created. + print("Creating index.html") + stream = file(os.path.join(options.report_dir, "index.html"), "w") + stream.write(HTML_HEAD) + stream.write("") + stream.write(HTML_FOOTER) + stream.close() From 89b2118622d4734778f8dcea8e5e852612a16224 Mon Sep 17 00:00:00 2001 From: Henrik Nilsson Date: Fri, 11 Dec 2009 12:39:39 +0100 Subject: [PATCH 2/4] index.html page is now complete with a list of files and all errors found. Other changes: * added a stylesheet and made the html design much better. * contains links directly to the line in the source file. --- htmlreport/cppcheck-htmlreport | 155 +++++++++++++++++++++++++++++++-- 1 file changed, 147 insertions(+), 8 deletions(-) diff --git a/htmlreport/cppcheck-htmlreport b/htmlreport/cppcheck-htmlreport index c23540a0a..5bb7f552d 100755 --- a/htmlreport/cppcheck-htmlreport +++ b/htmlreport/cppcheck-htmlreport @@ -5,6 +5,7 @@ import os import os.path from pygments import highlight from pygments.lexers import CppLexer +from pygments.lexers import guess_lexer, guess_lexer_for_filename from pygments.formatters import HtmlFormatter from xml.sax import parse as xml_parse from xml.sax import SAXParseException as XmlParseException @@ -15,16 +16,139 @@ Turns a cppcheck xml file into a browsable html report along with syntax highlighted source code. """ +STYLE_FILE = """ +body.body { + font-family: Arial; + font-size: 13px; + background-color: black; + padding: 0px; + margin: 0px; +} + +#page-header { + clear: both; + width: 900px; + margin: 20px auto 0px auto; + height: 10px; + border-bottom-width: 2px; + border-bottom-style: solid; + border-bottom-color: #aaaaaa; +} + +#page { + width: 860px; + margin: auto; + border-left-width: 2px; + border-left-style: solid; + border-left-color: #aaaaaa; + border-right-width: 2px; + border-right-style: solid; + border-right-color: #aaaaaa; + background-color: White; + padding: 20px; +} + +#page-footer { + clear: both; + width: 900px; + margin: auto; + height: 10px; + border-top-width: 2px; + border-top-style: solid; + border-top-color: #aaaaaa; +} + +#header { + width: 100%; + height: 70px; + background-image: url(logo.png); + background-repeat: no-repeat; + background-position: left top; + + border-bottom-style: solid; + border-bottom-width: thin; + border-bottom-color: #aaaaaa; +} + +#menu { + margin-top: 5px; + text-align: left; + float: left; + width: 100px; + height: 300px; +} + +#menu > a { + margin-left: 10px; + display: block; +} + +#content { + float: left; + width: 720px; + + margin: 5px; + padding: 0px 10px 10px 10px; + + border-left-style: solid; + border-left-width: thin; + border-left-color: #aaaaaa; +} + +#footer { + padding-bottom: 5px; + padding-top: 5px; + border-top-style: solid; + border-top-width: thin; + border-top-color: #aaaaaa; + clear: both; + font-size: 10px; +} + +#footer > div { + float: left; + width: 33%; +} +""" + HTML_HEAD = """ CppCheck - Html report - + + +
+ + +
""" HTML_FOOTER = """ +
+ +   +
+ """ @@ -40,7 +164,7 @@ class CppCheckHandler(XmlContentHandler): self.errors.append( { "file" : attributes["file"], - "line" : attributes["line"], + "line" : int(attributes["line"]), "id" : attributes["id"], "severity" : attributes["severity"], "msg" : attributes["msg"] @@ -104,14 +228,19 @@ if __name__ == '__main__': htmlfile = data["htmlfile"] errors = data["errors"] - stream = file(os.path.join(source_dir, filename)) + lines = [] + for error in errors: + lines.append(error["line"]) + + source_file = os.path.join(source_dir, filename) + stream = file(source_file) content = stream.read() stream.close() - htmlFormatter = HtmlFormatter(linenos=True, style='colorful', full=True) + htmlFormatter = HtmlFormatter(linenos=True, style='colorful', full=True, hl_lines=lines, lineanchors="line") stream = file(os.path.join(options.report_dir, htmlfile), "w") stream.write(HTML_HEAD) - stream.write(highlight(content, CppLexer(), htmlFormatter)) + stream.write(highlight(content, guess_lexer_for_filename(source_file, ""), htmlFormatter)) stream.write(HTML_FOOTER) stream.close() @@ -122,9 +251,19 @@ if __name__ == '__main__': print("Creating index.html") stream = file(os.path.join(options.report_dir, "index.html"), "w") stream.write(HTML_HEAD) - stream.write("