2 # Copyright 2013-2016, 2019 Intel Corporation
3 # Copyright 2013, 2014 Advanced Micro Devices
4 # Copyright 2014 VMWare
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 """Generate html summaries."""
37 from mako
.lookup
import TemplateLookup
39 # a local variable status exists, prevent accidental overloading by renaming
41 from framework
import backends
, exceptions
, core
43 from .common
import Results
, escape_filename
, escape_pathname
44 from .feature
import FeatResults
51 # Use the source file location to compute _TEMP_DIR,
52 # because we don't want to share _TEMP_DIR between multiple
53 # source code location of piglit.
54 # See https://gitlab.freedesktop.org/mesa/piglit/issues/26
55 p
= abs(zlib
.crc32(os
.path
.dirname(__file__
).encode()))
57 _TEMP_DIR
= os
.path
.join(
58 tempfile
.gettempdir(),
61 'python-{}'.format(sys
.version
.split()[0]),
62 'mako-{}'.format(mako
.__version
__),
66 _TEMPLATE_DIR
= os
.path
.join(os
.path
.dirname(__file__
), '../..', 'templates')
68 # To ease the bytes/str/uincode between python 2 and python 3 the
69 # output_encoding keyword is set below. This means that in both python 2 and 3
70 # bytes are returned. This means that the files need to be opened in bytes mode
72 _TEMPLATES
= TemplateLookup(
74 output_encoding
='utf-8',
75 module_directory
=os
.path
.join(_TEMP_DIR
, "html-summary"))
78 def _copy_static_files(destination
):
79 """Copy static files into the results directory."""
80 shutil
.copy(os
.path
.join(_TEMPLATE_DIR
, "index.css"),
81 os
.path
.join(destination
, "index.css"))
82 shutil
.copy(os
.path
.join(_TEMPLATE_DIR
, "result.css"),
83 os
.path
.join(destination
, "result.css"))
86 def _make_testrun_info(results
, destination
, exclude
=None):
87 """Create the pages for each results file."""
88 exclude
= exclude
or {}
89 result_css
= os
.path
.join(destination
, "result.css")
90 index
= os
.path
.join(destination
, "index.html")
92 for each
in results
.results
:
93 name
= escape_pathname(each
.name
)
95 core
.check_dir(os
.path
.join(destination
, name
), True)
96 except exceptions
.PiglitException
:
97 raise exceptions
.PiglitFatalError(
98 'Two or more of your results have the same "name" '
99 'attribute. Try changing one or more of the "name" '
100 'values in your json files.\n'
101 'Duplicate value: {}'.format(name
))
103 with
open(os
.path
.join(destination
, name
, "index.html"), 'wb') as out
:
104 out
.write(_TEMPLATES
.get_template('testrun_info.mako').render(
106 totals
=each
.totals
['root'],
107 time
=each
.time_elapsed
.delta
,
108 options
=each
.options
,
111 # Then build the individual test results
112 for key
, value
in each
.tests
.items():
113 html_path
= os
.path
.join(destination
, name
,
114 escape_filename(key
+ ".html"))
115 temp_path
= os
.path
.dirname(html_path
)
117 if value
.result
not in exclude
:
118 core
.check_dir(temp_path
)
121 with
open(html_path
, 'wb') as out
:
122 out
.write(_TEMPLATES
.get_template(
123 'test_result.mako').render(
126 css
=os
.path
.relpath(result_css
, temp_path
),
127 index
=os
.path
.relpath(index
, temp_path
)))
129 if e
.errno
== errno
.ENAMETOOLONG
:
130 print('WARN: filename "{}" too long'.format(html_name
))
135 def _make_comparison_pages(results
, destination
, exclude
):
136 """Create the pages of comparisons."""
137 pages
= frozenset(['changes', 'problems', 'skips', 'fixes',
138 'regressions', 'enabled', 'disabled'])
140 # Index.html is a bit of a special case since there is index, all, and
141 # alltests, where the other pages all use the same name. ie,
142 # changes.html, changes, and page=changes.
143 with
open(os
.path
.join(destination
, "index.html"), 'wb') as out
:
144 out
.write(_TEMPLATES
.get_template('index.mako').render(
150 # Generate the rest of the pages
152 with
open(os
.path
.join(destination
, page
+ '.html'), 'wb') as out
:
153 # If there is information to display display it
154 if sum(getattr(results
.counts
, page
)) > 0:
155 out
.write(_TEMPLATES
.get_template('index.mako').render(
160 # otherwise provide an empty page
163 _TEMPLATES
.get_template('empty_status.mako').render(
164 page
=page
, pages
=pages
))
167 def _make_feature_info(results
, destination
):
168 """Create the feature readiness page."""
170 with
open(os
.path
.join(destination
, "feature.html"), 'wb') as out
:
171 out
.write(_TEMPLATES
.get_template('feature.mako').render(
175 def html(results
, destination
, exclude
):
177 Produce HTML summaries.
179 Basically all this does is takes the information provided by the
180 constructor, and passes it to mako templates to generate HTML files.
181 The beauty of this approach is that mako is leveraged to do the
182 heavy lifting, this method just passes it a bunch of dicts and lists
183 of dicts, which mako turns into pretty HTML.
185 results
= Results([backends
.load(i
) for i
in results
])
187 _copy_static_files(destination
)
188 _make_testrun_info(results
, destination
, exclude
)
189 _make_comparison_pages(results
, destination
, exclude
)
192 def feat(results
, destination
, feat_desc
):
193 """Produce HTML feature readiness summary."""
195 feat_res
= FeatResults([backends
.load(i
) for i
in results
], feat_desc
)
197 _copy_static_files(destination
)
198 _make_testrun_info(feat_res
, destination
)
199 _make_feature_info(feat_res
, destination
)