| 175 | </body></html>''') |
| 176 | |
| 177 | def generate_html_report(html_report_path, builds): |
| 178 | report_dir = os.path.dirname(html_report_path) |
| 179 | # Vertical axis: generator |
| 180 | # Horizontal: variables, then build_type |
| 181 | builds_by_generator = collections.defaultdict(list) |
| 182 | variables = set() |
| 183 | build_types_by_variable = collections.defaultdict(set) |
| 184 | build_by_pos_key = {} # { (generator, var_key, build_type): build } |
| 185 | for build in builds: |
| 186 | builds_by_generator[build.desc.generator].append(build) |
| 187 | var_key = tuple(sorted(build.desc.variables)) |
| 188 | variables.add(var_key) |
| 189 | build_types_by_variable[var_key].add(build.desc.build_type) |
| 190 | pos_key = (build.desc.generator, var_key, build.desc.build_type) |
| 191 | build_by_pos_key[pos_key] = build |
| 192 | variables = sorted(variables) |
| 193 | th_vars = [] |
| 194 | th_build_types = [] |
| 195 | for variable in variables: |
| 196 | build_types = sorted(build_types_by_variable[variable]) |
| 197 | nb_build_type = len(build_types_by_variable[variable]) |
| 198 | th_vars.append('<th colspan="%d">%s</th>' % (nb_build_type, cgi.escape(' '.join(variable)))) |
| 199 | for build_type in build_types: |
| 200 | th_build_types.append('<th>%s</th>' % cgi.escape(build_type)) |
| 201 | tr_builds = [] |
| 202 | for generator in sorted(builds_by_generator): |
| 203 | tds = [ '<td>%s</td>\n' % cgi.escape(generator) ] |
| 204 | for variable in variables: |
| 205 | build_types = sorted(build_types_by_variable[variable]) |
| 206 | for build_type in build_types: |
| 207 | pos_key = (generator, variable, build_type) |
| 208 | build = build_by_pos_key.get(pos_key) |
| 209 | if build: |
| 210 | cmake_status = 'ok' if build.cmake_succeeded else 'FAILED' |
| 211 | build_status = 'ok' if build.build_succeeded else 'FAILED' |
| 212 | cmake_log_url = os.path.relpath(build.cmake_log_path, report_dir) |
| 213 | build_log_url = os.path.relpath(build.build_log_path, report_dir) |
| 214 | td = '<td class="%s"><a href="%s" class="%s">CMake: %s</a>' % ( build_status.lower(), cmake_log_url, cmake_status.lower(), cmake_status) |
| 215 | if build.cmake_succeeded: |
| 216 | td += '<br><a href="%s" class="%s">Build: %s</a>' % ( build_log_url, build_status.lower(), build_status) |
| 217 | td += '</td>' |
| 218 | else: |
| 219 | td = '<td></td>' |
| 220 | tds.append(td) |
| 221 | tr_builds.append('<tr>%s</tr>' % '\n'.join(tds)) |
| 222 | html = HTML_TEMPLATE.substitute( title='Batch build report', |
| 223 | th_vars=' '.join(th_vars), |
| 224 | th_build_types=' '.join(th_build_types), |
| 225 | tr_builds='\n'.join(tr_builds)) |
| 226 | with open(html_report_path, 'wt') as fhtml: |
| 227 | fhtml.write(html) |
| 228 | print('HTML report generated in:', html_report_path) |
| 229 | |
| 230 | def main(): |
| 231 | usage = r"""%prog WORK_DIR SOURCE_DIR CONFIG_JSON_PATH [CONFIG2_JSON_PATH...] |