Skip to content

Commit 663daeb

Browse files
committed
ENH: Add generate-lcov-html flag
1 parent 794cabf commit 663daeb

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

spin/cmds/meson.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import contextlib
22
import copy
3+
import itertools
34
import json
45
import os
56
import re
@@ -15,6 +16,9 @@
1516
from .util import run as _run
1617

1718

19+
LCOV_OUTPUT_FILE = Path("build", "meson-logs", "coveragereport")
20+
21+
1822
class GcovReportFormat(str, Enum):
1923
html = "html"
2024
xml = "xml"
@@ -231,6 +235,49 @@ def _check_coverage_tool_installation(coverage_type: GcovReportFormat, build_dir
231235
)
232236

233237

238+
def _get_coverage_files():
239+
cwd = Path.cwd()
240+
build_dir = Path(cwd, "build")
241+
return itertools.chain(build_dir.rglob("*.gcda"), build_dir.rglob("*.da"))
242+
243+
244+
def _gcov_reset_counters():
245+
click.secho("Removing previous GCOV .gcda files...", fg="yellow")
246+
build_dir = Path(Path.cwd(), "build")
247+
for filename in _get_coverage_files():
248+
Path.unlink(filename)
249+
250+
251+
def _generate_lcov_coverage_html():
252+
if next(_get_coverage_files(), None) is None:
253+
raise click.ClickException(
254+
"GCOV files missing... Cannot generate coverage reports. "
255+
"Coverage reports can be generated by `spin test --coverage --gcov`"
256+
)
257+
258+
click.secho(
259+
"Deleting old HTML coverage report...",
260+
fg="yellow",
261+
)
262+
shutil.rmtree(LCOV_OUTPUT_FILE, ignore_errors=True)
263+
264+
click.secho(
265+
"Generating HTML coverage report...",
266+
fg="blue",
267+
)
268+
cmd = ["ninja", "coverage-html", "-C", "build"]
269+
p = _run(
270+
cmd,
271+
echo=True,
272+
output=False,
273+
)
274+
coverage_folder = re.search(r"file://(.*)", p.stdout.decode("utf-8")).group(1)
275+
click.secho(
276+
f"Coverage report generated successfully and written to {coverage_folder}",
277+
fg="green",
278+
)
279+
280+
234281
if sys.platform.startswith("win"):
235282
DEFAULT_PREFIX = "C:/"
236283
else:
@@ -447,6 +494,13 @@ def _get_configured_command(command_name):
447494
default="html",
448495
help=f"Format of the gcov report. Can be one of {', '.join(e.value for e in GcovReportFormat)}.",
449496
)
497+
@click.option(
498+
"--generate-lcov-html",
499+
is_flag=True,
500+
help="produce HTML for C code coverage information "
501+
"from a previous run with --gcov. "
502+
"HTML output goes to `build/meson-logs/coveragereport/`",
503+
)
450504
@build_dir_option
451505
@click.pass_context
452506
def test(
@@ -459,6 +513,7 @@ def test(
459513
coverage=False,
460514
gcov=None,
461515
gcov_format=None,
516+
generate_lcov_html=None,
462517
build_dir=None,
463518
):
464519
"""🔧 Run tests
@@ -503,6 +558,10 @@ def test(
503558
distname = cfg.get("project.name", None)
504559
pytest_args = pytest_args or ()
505560

561+
if generate_lcov_html:
562+
_generate_lcov_coverage_html()
563+
sys.exit(0)
564+
506565
# User specified tests without -t flag
507566
# Rewrite arguments as though they specified using -t and proceed
508567
if (len(pytest_args) == 1) and (not tests):
@@ -547,6 +606,7 @@ def test(
547606
"Invoking `build` prior to running tests:", bold=True, fg="bright_green"
548607
)
549608
if gcov is not None:
609+
_gcov_reset_counters()
550610
ctx.invoke(build_cmd, build_dir=build_dir, gcov=bool(gcov))
551611
else:
552612
ctx.invoke(build_cmd, build_dir=build_dir)

0 commit comments

Comments
 (0)