build-support/process_gcovr_report.py (49 lines of code) (raw):
#!/usr/bin/env python3
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# This script processes HTML reports generated by gcovr.
# It is primarily needed because we are using an older version
# of gcovr with the following limitations:
#
# - It includes full paths to linked pages, which do not work once
# we publish the reports through Jenkins for example. Newer gcovr
# versions default to relative links.
# - It uses inline CSS styles, which are blocked by Jenkins due
# to Content Security Policy (CSP) restrictions.
#
# To address these issues, the script performs the following steps for each HTML
# file in the given reports directory:
# 1. Extracts CSS from <style> tags and saves it into a separate .css file.
# 2. Converts inline styles to CSS classes and moves them into the .css file.
# 3. Updates all <a href="..."> links to use only the filename (removes absolute paths).
# 4. Inserts a <link> tag in the HTML file to reference the extracted CSS file.
# 5. Saves the modified HTML file with externalized styling.
#
# Usage: python process_gcovr_report.py reports_folder
from bs4 import BeautifulSoup
import sys
import os
if len(sys.argv) != 2:
print("Usage: python process_reports.py reports_folder")
sys.exit(1)
reports_folder = sys.argv[1]
# Ensure the directory exists
if not os.path.isdir(reports_folder):
print(f"Error: '{reports_folder}' is not a directory. It may exist as a file.")
sys.exit(1)
# Process each HTML file in the directory
for filename in os.listdir(reports_folder):
if filename.endswith(".html"):
html_path = os.path.join(reports_folder, filename)
css_filename = filename.replace(".html", ".css")
css_path = os.path.join(reports_folder, css_filename)
print(f"Processing: {filename}")
# Read the HTML file
with open(html_path, "r", encoding="utf-8") as f:
html_content = f.read()
# Parse HTML with BeautifulSoup
parsed_html = BeautifulSoup(html_content, "html.parser")
# Extract CSS from <style> tags
css_content = []
for style_tag in parsed_html.find_all("style"):
if style_tag.string:
css_content.append(style_tag.string.strip()) # Extract full CSS
style_tag.extract() # Remove <style> tag from HTML
# Extract inline styles and convert them to CSS classes
inline_styles = {}
class_counter = 0
for tag in parsed_html.find_all(style=True):
style = tag["style"]
if style not in inline_styles:
class_name = f"class_{class_counter}"
inline_styles[style] = class_name
class_counter += 1
else:
class_name = inline_styles[style]
# Assign class and remove inline style
tag["class"] = tag.get("class", []) + [class_name]
del tag["style"]
# Convert absolute paths in <a href="..."> to relative filenames
for a_tag in parsed_html.find_all("a", href=True):
a_tag["href"] = os.path.basename(a_tag["href"]) # Extract only the file name
# Write extracted CSS to the corresponding CSS file
with open(css_path, "w", encoding="utf-8") as f:
for css_block in css_content:
f.write(css_block + "\n\n") # Ensure proper formatting
for style, class_name in inline_styles.items():
f.write(f".{class_name} {{ {style} !important; }}\n") # Add !important
# Add a <link> tag referencing the new CSS file
link_tag = parsed_html.new_tag("link", rel="stylesheet", type="text/css", href=css_filename)
parsed_html.head.insert(0, link_tag)
# Write the updated HTML file
with open(html_path, "w", encoding="utf-8") as f:
f.write(str(parsed_html))
print(f"Processed: {filename} -> {css_filename}")
print(f"All HTML files in {reports_folder} processed successfully!")