piglit-summary-html.py 7.69 KB
Newer Older
1
#!/usr/bin/env python
Nicolai Hähnle's avatar
Nicolai Hähnle committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# This permission notice shall be included in all copies or
# substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
18
# PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHOR(S) BE
Nicolai Hähnle's avatar
Nicolai Hähnle committed
19 20 21 22 23 24
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

from getopt import getopt, GetoptError
Nicolai Hähnle's avatar
Nicolai Hähnle committed
25
import cgi
Nicolai Hähnle's avatar
Nicolai Hähnle committed
26 27 28 29 30
import errno
import os
import sys

import framework.core as core
31
import framework.summary
Nicolai Hähnle's avatar
Nicolai Hähnle committed
32

33

Nicolai Hähnle's avatar
Nicolai Hähnle committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#############################################################################
##### Auxiliary functions
#############################################################################

def testPathToHtmlFilename(path):
	return filter(lambda s: s.isalnum() or s == '_', path.replace('/', '__')) + '.html'


#############################################################################
##### HTML output
#############################################################################

def readfile(filename):
	f = open(filename, "r")
	s = f.read()
	f.close()
	return s

def writefile(filename, text):
	f = open(filename, "w")
	f.write(text)
	f.close()

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
templatedir = os.path.dirname(__file__) + '/templates/'
Result = readfile(templatedir + 'result.html')
ResultDetail = readfile(templatedir + 'result_detail.html')
ResultList = readfile(templatedir + 'result_list.html')
ResultListItem = readfile(templatedir + 'result_listitem.html')
ResultMString = readfile(templatedir + 'result_mstring.html')

Index = readfile(templatedir + 'index.html')
IndexTestrun = readfile(templatedir + 'index_testrun.html')
IndexTestrunB = readfile(templatedir + 'index_testrunb.html')
IndexGroup = readfile(templatedir + 'index_group.html')
IndexGroupTestrun = readfile(templatedir + 'index_group_testrun.html')
IndexGroupGroup = readfile(templatedir + 'index_groupgroup.html')
IndexTest = readfile(templatedir + 'index_test.html')
IndexTestTestrun = readfile(templatedir + 'index_test_testrun.html')
Nicolai Hähnle's avatar
Nicolai Hähnle committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

SummaryPages = {
	'all': 'index.html',
	'changes': 'changes.html',
	'problems': 'problems.html'
}

def buildDetailValue(detail):
	if type(detail) == list:
		items = ''

		for d in detail:
			items = items + ResultListItem % { 'detail': buildDetailValue(d) }

		return ResultList % { 'items': items }
	elif type(detail) == str and detail[0:3] == '@@@':
Nicolai Hähnle's avatar
Nicolai Hähnle committed
88
		return ResultMString % { 'detail': cgi.escape(detail[3:]) }
Nicolai Hähnle's avatar
Nicolai Hähnle committed
89

Nicolai Hähnle's avatar
Nicolai Hähnle committed
90
	return cgi.escape(str(detail))
Nicolai Hähnle's avatar
Nicolai Hähnle committed
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116


def buildDetails(testResult):
	details = []
	for name in testResult:
		if type(name) != str or name == 'result':
			continue

		value = buildDetailValue(testResult[name])
		details += [(name,value)]

	details.sort(lambda a,b: len(a[1])-len(b[1]))

	text = ''
	alternate = 'a'
	for name,value in details:
		text += ResultDetail % locals()

		if alternate == 'a':
			alternate = 'b'
		else:
			alternate = 'a'

	return text


117 118 119
def writeResultHtml(test, testResult, filename):
	path = test.path
	name = test.name
Nicolai Hähnle's avatar
Nicolai Hähnle committed
120 121 122 123 124 125 126 127 128 129 130 131
	status = testResult.status

	if 'result' in testResult:
		result = testResult['result']
	else:
		result = '?'

	details = buildDetails(testResult)

	writefile(filename, Result % locals())


132
def buildTestSummary(indent, alternate, testsummary):
Nicolai Hähnle's avatar
Nicolai Hähnle committed
133
	tenindent = 10 - indent
134 135
	path = testsummary.path
	name = testsummary.name
Nicolai Hähnle's avatar
Nicolai Hähnle committed
136 137
	testruns = "".join([IndexTestTestrun % {
		'alternate': alternate,
138 139 140
		'status': result.status,
		'link': result.testrun.codename + '/' + testPathToHtmlFilename(path)
	} for result in testsummary.results])
Nicolai Hähnle's avatar
Nicolai Hähnle committed
141 142 143 144

	return IndexTest % locals()


145 146 147 148 149
def buildGroupSummaryTestrun(groupresult):
	passnr = groupresult.passvector.passnr
	warnnr = groupresult.passvector.warnnr
	failnr = groupresult.passvector.failnr
	skipnr = groupresult.passvector.skipnr
Nicolai Hähnle's avatar
Nicolai Hähnle committed
150 151 152 153 154 155 156 157 158 159 160 161 162 163
	totalnr = passnr + warnnr + failnr # do not count skips

	if failnr > 0:
		status = 'fail'
	elif warnnr > 0:
		status = 'warn'
	elif passnr > 0:
		status = 'pass'
	else:
		status = 'skip'

	return IndexGroupTestrun % locals()


164
def buildGroupSummary(indent, groupsummary, showcurrent):
Nicolai Hähnle's avatar
Nicolai Hähnle committed
165 166 167 168
	tenindent = 10 - indent

	items = ''
	alternate = 'a'
169 170 171
	path = groupsummary.path
	name = groupsummary.name
	names = groupsummary.children.keys()
Nicolai Hähnle's avatar
Nicolai Hähnle committed
172 173

	if showcurrent == 'changes':
174
		names = filter(lambda n: groupsummary.children[n].changes, names)
Nicolai Hähnle's avatar
Nicolai Hähnle committed
175
	elif showcurrent == 'problems':
176
		names = filter(lambda n: groupsummary.children[n].problems, names)
Nicolai Hähnle's avatar
Nicolai Hähnle committed
177 178 179

	names.sort()
	for n in names:
180 181
		child = groupsummary.children[n]
		if isinstance(child, framework.summary.GroupSummary):
Nicolai Hähnle's avatar
Nicolai Hähnle committed
182
			items = items + IndexGroupGroup % {
183
				'group': buildGroupSummary(indent+1, child, showcurrent)
Nicolai Hähnle's avatar
Nicolai Hähnle committed
184 185
			}
		else:
186
			items = items + buildTestSummary(indent+1, alternate, child)
Nicolai Hähnle's avatar
Nicolai Hähnle committed
187 188 189 190 191 192

		if alternate == 'a':
			alternate = 'b'
		else:
			alternate = 'a'

193 194
	testruns = "".join([buildGroupSummaryTestrun(result)
			for result in groupsummary.results])
Nicolai Hähnle's avatar
Nicolai Hähnle committed
195 196 197 198

	return IndexGroup % locals()


199
def writeSummaryHtml(summary, summaryDir, showcurrent):
Nicolai Hähnle's avatar
Nicolai Hähnle committed
200 201 202 203 204 205 206 207 208 209
	"""\
results is an array containing the top-level results dictionarys.
"""
	def link(to):
		if to == showcurrent:
			return to
		else:
			page = SummaryPages[to]
			return '<a href="%(page)s">%(to)s</a>' % locals()

210 211 212
	group = buildGroupSummary(1, summary.root, showcurrent)
	testruns = "".join([IndexTestrun % tr.__dict__ for tr in summary.testruns])
	testrunsb = "".join([IndexTestrunB % tr.__dict__ for tr in summary.testruns])
Nicolai Hähnle's avatar
Nicolai Hähnle committed
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

	tolist = SummaryPages.keys()
	tolist.sort()
	showlinks = " | ".join([link(to) for to in tolist])

	writefile(summaryDir + '/' + SummaryPages[showcurrent], Index % locals())


#############################################################################
##### Main program
#############################################################################
def usage():
	USAGE = """\
Usage: %(progName)s [options] [summary-dir] [test.results]...

Options:
  -h, --help            Show this message
  -o, --overwrite       Overwrite existing directories

Example:
  %(progName)s summary/mysum results/all.results
"""
	print USAGE % {'progName': sys.argv[0]}
Jeff Muizelaar's avatar
Jeff Muizelaar committed
236
	sys.exit(1)
Nicolai Hähnle's avatar
Nicolai Hähnle committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261


def main():
	try:
		options, args = getopt(sys.argv[1:], "ho", [ "help", "overwrite" ])
	except GetoptError:
		usage()

	OptionOverwrite = False
	for name,value in options:
		if name == "-h" or name == "--help":
			usage()
		elif name == "-o" or name == "--overwrite":
			OptionOverwrite = True

	if len(args) < 2:
		usage()

	summaryDir = args[0]
	resultFilenames = args[1:]

	core.checkDir(summaryDir, not OptionOverwrite)

	results = [core.loadTestResults(name) for name in resultFilenames]

262 263 264 265 266 267 268 269 270
	summary = framework.summary.Summary(results)
	for j in range(len(summary.testruns)):
		tr = summary.testruns[j]
		tr.codename = filter(lambda s: s.isalnum(), tr.name)
		dirname = summaryDir + '/' + tr.codename
		core.checkDir(dirname, False)
		for test in summary.allTests():
			filename = dirname + testPathToHtmlFilename(test.path)
			writeResultHtml(test, test.results[j], filename)
Nicolai Hähnle's avatar
Nicolai Hähnle committed
271

272 273
	writefile(summaryDir + '/result.css', readfile(templatedir + 'result.css'))
	writefile(summaryDir + '/index.css', readfile(templatedir + 'index.css'))
274 275 276
	writeSummaryHtml(summary, summaryDir, 'all')
	writeSummaryHtml(summary, summaryDir, 'problems')
	writeSummaryHtml(summary, summaryDir, 'changes')
Nicolai Hähnle's avatar
Nicolai Hähnle committed
277 278 279 280


if __name__ == "__main__":
	main()