From 5880d5e0513ca759a41b49c7c55abfbdfa144534 Mon Sep 17 00:00:00 2001 From: ganesh-k13 Date: Thu, 5 Dec 2024 18:42:49 +0530 Subject: [PATCH] ENH: Add `generate-lcov-html` flag --- spin/cmds/meson.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/spin/cmds/meson.py b/spin/cmds/meson.py index ca47801..346accf 100644 --- a/spin/cmds/meson.py +++ b/spin/cmds/meson.py @@ -1,5 +1,6 @@ import contextlib import copy +import itertools import json import os import re @@ -14,6 +15,8 @@ from .util import get_commands, get_config from .util import run as _run +LCOV_OUTPUT_FILE = Path("build", "meson-logs", "coveragereport") + class GcovReportFormat(str, Enum): html = "html" @@ -231,6 +234,48 @@ def _check_coverage_tool_installation(coverage_type: GcovReportFormat, build_dir ) +def _get_coverage_files(): + cwd = Path.cwd() + build_dir = Path(cwd, "build") + return itertools.chain(build_dir.rglob("*.gcda"), build_dir.rglob("*.da")) + + +def _gcov_reset_counters(): + click.secho("Removing previous GCOV .gcda files...", fg="yellow") + for filename in _get_coverage_files(): + Path.unlink(filename) + + +def _generate_lcov_coverage_html(): + if next(_get_coverage_files(), None) is None: + raise click.ClickException( + "GCOV files missing... Cannot generate coverage reports. " + "Coverage reports can be generated by `spin test --coverage --gcov`" + ) + + click.secho( + "Deleting old HTML coverage report...", + fg="yellow", + ) + shutil.rmtree(LCOV_OUTPUT_FILE, ignore_errors=True) + + click.secho( + "Generating HTML coverage report...", + fg="blue", + ) + cmd = ["ninja", "coverage-html", "-C", "build"] + p = _run( + cmd, + echo=True, + output=False, + ) + coverage_folder = re.search(r"file://(.*)", p.stdout.decode("utf-8")).group(1) + click.secho( + f"Coverage report generated successfully and written to {coverage_folder}", + fg="green", + ) + + if sys.platform.startswith("win"): DEFAULT_PREFIX = "C:/" else: @@ -447,6 +492,13 @@ def _get_configured_command(command_name): default="html", help=f"Format of the gcov report. Can be one of {', '.join(e.value for e in GcovReportFormat)}.", ) +@click.option( + "--generate-lcov-html", + is_flag=True, + help="produce HTML for C code coverage information " + "from a previous run with --gcov. " + "HTML output goes to `build/meson-logs/coveragereport/`", +) @build_dir_option @click.pass_context def test( @@ -459,6 +511,7 @@ def test( coverage=False, gcov=None, gcov_format=None, + generate_lcov_html=None, build_dir=None, ): """🔧 Run tests @@ -503,6 +556,10 @@ def test( distname = cfg.get("project.name", None) pytest_args = pytest_args or () + if generate_lcov_html: + _generate_lcov_coverage_html() + sys.exit(0) + # User specified tests without -t flag # Rewrite arguments as though they specified using -t and proceed if (len(pytest_args) == 1) and (not tests): @@ -547,6 +604,7 @@ def test( "Invoking `build` prior to running tests:", bold=True, fg="bright_green" ) if gcov is not None: + _gcov_reset_counters() ctx.invoke(build_cmd, build_dir=build_dir, gcov=bool(gcov)) else: ctx.invoke(build_cmd, build_dir=build_dir)