1563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#!/usr/bin/env python 2563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 3563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# Copyright (C) 2004, 2005, 2006 Nathaniel Smith 4563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# Copyright (C) 2007 Holger Hans Peter Freyther 5563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 6563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# Redistribution and use in source and binary forms, with or without 7563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# modification, are permitted provided that the following conditions 8563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# are met: 9563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 10563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 1. Redistributions of source code must retain the above copyright 11563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# notice, this list of conditions and the following disclaimer. 12563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 2. Redistributions in binary form must reproduce the above copyright 13563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# notice, this list of conditions and the following disclaimer in the 14563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# documentation and/or other materials provided with the distribution. 15563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# its contributors may be used to endorse or promote products derived 17563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# from this software without specific prior written permission. 18563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 19563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 30563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 31563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# HTML output inspired by the output of lcov as found on the GStreamer 32563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# site. I assume this is not copyrightable. 33563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 34563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 35563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 36563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 37563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# Read all CSV files and 38563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# Create an overview file 39563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 40563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark# 41563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 42563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 43563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport sys 44563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport csv 45563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport glob 46563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport time 47563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport os 48563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport os.path 49563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport datetime 50563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkimport shutil 51563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 52563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkos.environ["TTFPATH"] = ":".join(["/usr/share/fonts/truetype/" + d 53563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for d in "ttf-bitstream-vera", 54563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark "freefont", 55563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark "msttcorefonts"]) 56563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 57563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarklevel_LOW = 10 58563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarklevel_MEDIUM = 70 59563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 60563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef copy_files(dest_dir): 61563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 62563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark Copy the CSS and the png's to the destination directory 63563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 64563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark images = ["amber.png", "emerald.png", "glass.png", "ruby.png", "snow.png"] 65563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark css = "gcov.css" 66563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (base_path, name) = os.path.split(__file__) 67563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark base_path = os.path.abspath(base_path) 68563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 69563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark shutil.copyfile(os.path.join(base_path,css), os.path.join(dest_dir,css)) 70563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark map(lambda x: shutil.copyfile(os.path.join(base_path,x), os.path.join(dest_dir,x)), images) 71563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 72563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef sumcov(cov): 73563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return "%.2f%% (%s/%s)" % (cov[1] * 100.0 / (cov[0] or 1), cov[1], cov[0]) 74563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 75563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef create_page(dest_dir, name): 76563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark index = open(os.path.join(dest_dir, name), "w") 77563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark index.write("""<HTML> 78563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <HEAD> 79563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <TITLE>WebKit test coverage information</TITLE> 80563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <link rel="stylesheet" type="text/css" href="gcov.css"> 81563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </HEAD> 82563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <BODY> 83563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """) 84563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return index 85563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 86563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef generate_header(file, last_time, total_lines, total_executed, path, image): 87563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark product = "WebKit" 88563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(last_time)) 89563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark covered_lines = sumcov((total_lines, total_executed)) 90563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 91563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file.write("""<table width="100%%" border=0 cellspacing=0 cellpadding=0> 92563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr><td class="title">GCOV code coverage report</td></tr> 93563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr> 94563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 95563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 96563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td width="100%%"> 97563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <table cellpadding=1 border=0 width="100%%"> 98563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 99563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerItem" width="20%%">Current view:</td> 100563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerValue" width="80%%" colspan=4>%(path)s</td> 101563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 102563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 103563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerItem" width="20%%">Test:</td> 104563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerValue" width="80%%" colspan=4>%(product)s</td> 105563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 106563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 107563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerItem" width="20%%">Date:</td> 108563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerValue" width="20%%">%(date)s</td> 109563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td width="20%%"></td> 110563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerItem" width="20%%">Instrumented lines:</td> 111563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerValue" width="20%%">%(total_lines)s</td> 112563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 113563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 114563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerItem" width="20%%">Code covered:</td> 115563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerValue" width="20%%">%(covered_lines)s</td> 116563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td width="20%%"></td> 117563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerItem" width="20%%">Executed lines:</td> 118563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="headerValue" width="20%%">%(total_executed)s</td> 119563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 120563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </table> 121563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </td> 122563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 123563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr> 124563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </table>""" % vars()) 125563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # disabled for now <tr><td><img src="%(image)s"></td></tr> 126563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 127563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef generate_table_item(file, name, total_lines, covered_lines): 128563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark covered_precise = (covered_lines*100.0)/(total_lines or 1.0) 129563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark covered = int(round(covered_precise)) 130563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark remainder = 100-covered 131563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (image,perClass,numClass) = coverage_icon(covered_precise) 132563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site = "%s.html" % name.replace(os.path.sep,'__') 133563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file.write(""" 134563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 135563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="coverFile"><a href="%(site)s">%(name)s</a></td> 136563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="coverBar" align="center"> 137563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="%(image)s" width=%(covered)s height=10 alt="%(covered_precise).2f"><img src="snow.png" width=%(remainder)s height=10 alt="%(covered_precise).2f"></td></tr></table> 138563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </td> 139563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="%(perClass)s">%(covered_precise).2f %%</td> 140563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="%(numClass)s">%(covered_lines)s / %(total_lines)s lines</td> 141563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 142563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ % vars()) 143563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 144563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef generate_table_header_start(file): 145563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file.write("""<center> 146563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <table width="80%%" cellpadding=2 cellspacing=1 border=0> 147563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 148563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 149563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td width="50%%"><br></td> 150563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td width="15%%"></td> 151563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td width="15%%"></td> 152563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td width="20%%"></td> 153563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 154563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 155563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 156563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="tableHead">Directory name</td> 157563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td class="tableHead" colspan=3>Coverage</td> 158563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 159563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """) 160563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 161563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef coverage_icon(percent): 162563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if percent < level_LOW: 163563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return ("ruby.png", "coverPerLo", "coverNumLo") 164563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark elif percent < level_MEDIUM: 165563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return ("amber.png", "coverPerMed", "coverNumMed") 166563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark else: 167563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return ("emerald.png", "coverPerHi", "coverNumHi") 168563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 169563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef replace(text, *pairs): 170563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 171563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark From pydoc... almost identical at least 172563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 173563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark from string import split, join 174563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark while pairs: 175563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (a,b) = pairs[0] 176563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark text = join(split(text, a), b) 177563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark pairs = pairs[1:] 178563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return text 179563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 180563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef escape(text): 181563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 182563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark Escape string to be conform HTML 183563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 184563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return replace(text, 185563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark ('&', '&'), 186563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark ('<', '<' ), 187563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark ('>', '>' ) ) 188563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 189563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef generate_table_header_end(file): 190563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file.write("""</table> 191563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </center>""") 192563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 193563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef write_title_page(dest_dir, last_time, last_tot_lines, last_tot_covered, dir_series): 194563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 195563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark Write the index.html with a overview of each directory 196563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """ 197563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark index= create_page(dest_dir, "index.html") 198563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_header(index, last_time, last_tot_lines, last_tot_covered, "directory", "images/Total.png") 199563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Create the directory overview 200563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_table_header_start(index) 201563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dirs = dir_series.keys() 202563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dirs.sort() 203563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for dir in dirs: 204563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (dir_files, total_lines, covered_lines,_) = dir_series[dir][-1] 205563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_table_item(index, dir, total_lines, covered_lines) 206563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_table_header_end(index) 207563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 208563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark index.write("""</BODY></HTML>""") 209563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark index.close() 210563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 211563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef write_directory_site(dest_dir, dir_name, last_time, dir_series, file_series): 212563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark escaped_dir = dir_name.replace(os.path.sep,'__') 213563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site = create_page(dest_dir, "%s.html" % escaped_dir) 214563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (_,tot_lines,tot_covered,files) = dir_series[dir_name][-1] 215563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_header(site, last_time, tot_lines, tot_covered, "directory - %s" % dir_name, "images/%s.png" % escaped_dir) 216563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 217563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark files.sort() 218563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 219563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_table_header_start(site) 220563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for file in files: 221563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (lines,covered) = file_series[file][-1] 222563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_table_item(site, file, lines, covered) 223563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 224563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_table_header_end(site) 225563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.write("""</BODY></HTML>""") 226563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.close() 227563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 228563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef write_file_site(dest_dir, file_name, last_time, data_dir, last_id, file_series): 229563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark escaped_name = file_name.replace(os.path.sep,'__') 230563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site = create_page(dest_dir, "%s.html" % escaped_name) 231563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (tot_lines,tot_covered) = file_series[file_name][-1] 232563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark generate_header(site, last_time, tot_lines, tot_covered, "file - %s" % file_name, "images/%s.png" % escaped_name) 233563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 234563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark path = "%s/%s.annotated%s" % (data_dir,last_id,file_name) 235563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 236563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # In contrast to the lcov we want to show files that have been compiled 237563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # but have not been tested at all. This means we have sourcefiles with 0 238563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # lines covered in the path but they are not lcov files. 239563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # To identify them we check the first line now. If we see that we can 240563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # continue 241563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # -: 0:Source: 242563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark try: 243563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file = open(path, "r") 244563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark except: 245563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return 246563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark all_lines = file.read().split("\n") 247563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 248563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Convert the gcov file to HTML if we have a chanche to do so 249563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Scan each line and see if it was covered or not and escape the 250563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # text 251563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if len(all_lines) == 0 or not "-: 0:Source:" in all_lines[0]: 252563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.write("<p>The file was not excercised</p>") 253563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark else: 254563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.write("""</br><table cellpadding=0 cellspacing=0 border=0> 255563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 256563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td><br></td> 257563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark </tr> 258563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <tr> 259563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark <td><pre class="source"> 260563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark """) 261563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for line in all_lines: 262563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark split_line = line.split(':',2) 263563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # e.g. at the EOF 264563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if len(split_line) == 1: 265563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark continue 266563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark line_number = split_line[1].strip() 267563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if line_number == "0": 268563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark continue 269563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark covered = 15*" " 270563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark end = "" 271563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if "#####" in split_line[0]: 272563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark covered = '<span class="lineNoCov">%15s' % "0" 273563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark end = "</span>" 274563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark elif split_line[0].strip() != "-": 275563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark covered = '<span class="lineCov">%15s' % split_line[0].strip() 276563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark end = "</span>" 277563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 278563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark escaped_line = escape(split_line[2]) 279563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark str = '<span class="lineNum">%(line_number)10s </span>%(covered)s: %(escaped_line)s%(end)s\n' % vars() 280563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.write(str) 281563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.write("</pre></td></tr></table>") 282563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.write("</BODY></HTML>") 283563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark site.close() 284563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 285563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef main(progname, args): 286563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if len(args) != 2: 287563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark sys.exit("Usage: %s DATADIR OUTDIR" % progname) 288563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 289563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark branch = "WebKit from trunk" 290563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark datadir, outdir = args 291563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 292563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # First, load in all data from the data directory. 293563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark data = [] 294563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for datapath in glob.glob(os.path.join(datadir, "*.csv")): 295563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark data.append(read_csv(datapath)) 296563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Sort by time 297563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark data.sort() 298563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 299563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Calculate time series for each file. 300563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark times = [sample[0] for sample in data] 301563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark times = [datetime.datetime.utcfromtimestamp(t) for t in times] 302563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 303563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark all_files = {} 304563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark all_dirs = {} 305563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for sample in data: 306563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark t, i, tot_line, tot_cover, per_file, per_dir = sample 307563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark all_files.update(per_file) 308563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark all_dirs.update(per_dir) 309563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark total_series = [] 310563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file_serieses = dict([[k, [(0, 0)] * len(times)] for k in all_files.keys()]) 311563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dir_serieses = dict([[k, [(0, 0, 0, [])] * len(times)] for k in all_dirs.keys()]) 312563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark data_idx = 0 313563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for sample in data: 314563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark t, i, tot_line, tot_cover, per_file, per_dir = sample 315563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark total_series.append([tot_line, tot_cover]) 316563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for f, covinfo in per_file.items(): 317563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file_serieses[f][data_idx] = covinfo 318563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for f, covinfo in per_dir.items(): 319563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dir_serieses[f][data_idx] = covinfo 320563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark data_idx += 1 321563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 322563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 323563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Okay, ready to start outputting. First make sure our directories 324563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # exist. 325563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if not os.path.exists(outdir): 326563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark os.makedirs(outdir) 327563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark rel_imgdir = "images" 328563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark imgdir = os.path.join(outdir, rel_imgdir) 329563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if not os.path.exists(imgdir): 330563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark os.makedirs(imgdir) 331563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 332563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 333563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # And look up the latest revision id, and coverage information 334563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark last_time, last_id, last_tot_lines, last_tot_covered = data[-1][:4] 335563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 336563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Now start generating our html file 337563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark copy_files(outdir) 338563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark write_title_page(outdir, last_time, last_tot_lines, last_tot_covered, dir_serieses) 339563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 340563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dir_keys = dir_serieses.keys() 341563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dir_keys.sort() 342563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for dir_name in dir_keys: 343563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark write_directory_site(outdir, dir_name, last_time, dir_serieses, file_serieses) 344563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 345563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark file_keys = file_serieses.keys() 346563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for file_name in file_keys: 347563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark write_file_site(outdir, file_name, last_time, datadir, last_id, file_serieses) 348563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 349563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkdef read_csv(path): 350563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark r = csv.reader(open(path, "r")) 351563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # First line is id, time 352563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for row in r: 353563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark id, time_str = row 354563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark break 355563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark time = int(float(time_str)) 356563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Rest of lines are path, total_lines, covered_lines 357563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark per_file = {} 358563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark per_dir = {} 359563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark grand_total_lines, grand_covered_lines = 0, 0 360563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for row in r: 361563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark path, total_lines_str, covered_lines_str = row 362563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark total_lines = int(total_lines_str) 363563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark covered_lines = int(covered_lines_str) 364563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark grand_total_lines += total_lines 365563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark grand_covered_lines += covered_lines 366563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark per_file[path] = [total_lines, covered_lines] 367563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 368563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark # Update dir statistics 369563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dirname = os.path.dirname(path) 370563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if not dirname in per_dir: 371563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark per_dir[dirname] = (0,0,0,[]) 372563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark (dir_files,dir_total_lines,dir_covered_lines, files) = per_dir[dirname] 373563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dir_files += 1 374563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dir_total_lines += total_lines 375563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark dir_covered_lines += covered_lines 376563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark files.append(path) 377563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark per_dir[dirname] = (dir_files,dir_total_lines,dir_covered_lines,files) 378563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return [time, id, grand_total_lines, grand_covered_lines, per_file, per_dir] 379563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 380563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkif __name__ == "__main__": 381563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark import sys 382563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark main(sys.argv[0], sys.argv[1:]) 383