From f562ff2c9c767415c66901f171fda8ab08bd3da0 Mon Sep 17 00:00:00 2001 From: Vladimir Petrigo Date: Tue, 7 May 2024 22:45:38 +0200 Subject: [PATCH] Make htmlreport installable single package (#6335) For example, with `pipx` you can install `cppcheck-htmlreport` executable as follow: ```py pipx install "git+https://github.com/vpetrigo/cppcheck@feature/installable_htmlreport#subdirectory=htmlreport" ``` That also allows populating `Pygments` into user's environment automatically. No need to switch to the `htmlreport` and execute `pip install .` or something. After that the user is able to use `cppcheck-htmlreport` without installation of DEB/RPM packages. Moreover, on Windows it allows usage of this utility withot necessity to execute it like that, because shebans are not supported there: ```bash python /cppcheck-htmlreport ``` --- .github/workflows/scriptcheck.yml | 19 ++++++++-- .gitignore | 8 ++++ htmlreport/cppcheck-htmlreport | 6 ++- htmlreport/cppcheck_htmlreport/__init__.py | 0 htmlreport/setup.py | 38 ++++++++++++------- htmlreport/test_suppressions.txt | 3 -- htmlreport/tox.ini | 12 ------ .../tools/htmlreport}/check.sh | 21 +++++----- .../tools/htmlreport}/example.cc | 0 .../tools/htmlreport}/example.xml | 0 .../tools/htmlreport}/test_htmlreport.py | 16 +++++--- test/tools/htmlreport/test_suppressions.txt | 3 ++ 12 files changed, 78 insertions(+), 48 deletions(-) create mode 100644 htmlreport/cppcheck_htmlreport/__init__.py delete mode 100644 htmlreport/test_suppressions.txt delete mode 100644 htmlreport/tox.ini rename {htmlreport => test/tools/htmlreport}/check.sh (54%) rename {htmlreport => test/tools/htmlreport}/example.cc (100%) rename {htmlreport => test/tools/htmlreport}/example.xml (100%) rename {htmlreport => test/tools/htmlreport}/test_htmlreport.py (86%) create mode 100644 test/tools/htmlreport/test_suppressions.txt diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml index 8e6d4859157..307310616bc 100644 --- a/.github/workflows/scriptcheck.yml +++ b/.github/workflows/scriptcheck.yml @@ -143,10 +143,23 @@ jobs: env: PYTHONPATH: ./addons - - name: test htmlreport + - name: test htmlreport (standalone) run: | - htmlreport/test_htmlreport.py - cd htmlreport + test/tools/htmlreport/test_htmlreport.py + cd test/tools/htmlreport + ./check.sh + # Python 3.5 and 3.6 are excluded as they are not supported by setuptools-scm package for getting + # package version + - name: test htmlreport (pip) + if: matrix.python-version != '3.5' && matrix.python-version != '3.6' + run: | + python -m venv venv + source venv/bin/activate + python -m pip install -U pip + pip install ./htmlreport/ + which cppcheck-htmlreport + PIP_PACKAGE_TEST=1 test/tools/htmlreport/test_htmlreport.py + cd test/tools/htmlreport ./check.sh - name: test reduce diff --git a/.gitignore b/.gitignore index 8afdc9611b9..90a97ae5873 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,11 @@ compile_commands.json /oss-fuzz/corpus /oss-fuzz/corpus_ /oss-fuzz/samples + +# Python +/.venv/ +/venv/ +**/*.egg-info/ + +# cppcheck-htmlreport auto files +/htmlreport/cppcheck_htmlreport/run.py diff --git a/htmlreport/cppcheck-htmlreport b/htmlreport/cppcheck-htmlreport index 8a3686b0d65..411b03551d8 100755 --- a/htmlreport/cppcheck-htmlreport +++ b/htmlreport/cppcheck-htmlreport @@ -616,7 +616,7 @@ class CppCheckHandler(XmlContentHandler): 'info': attributes.get('info') }) -if __name__ == '__main__': +def main() -> None: # Configure all the options this little utility is using. parser = optparse.OptionParser() parser.add_option('--title', dest='title', @@ -984,3 +984,7 @@ if __name__ == '__main__': stats_file.write(HTML_FOOTER % contentHandler.versionCppcheck) print("\nOpen '" + options.report_dir + "/index.html' to see the results.") + + +if __name__ == "__main__": + main() diff --git a/htmlreport/cppcheck_htmlreport/__init__.py b/htmlreport/cppcheck_htmlreport/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htmlreport/setup.py b/htmlreport/setup.py index ac790fbebc1..3e049181ce6 100755 --- a/htmlreport/setup.py +++ b/htmlreport/setup.py @@ -1,21 +1,31 @@ #!/usr/bin/env python3 +import shutil +from setuptools import find_packages, setup -from setuptools import setup - -with open('README.txt') as f: +with open("README.txt") as f: readme = f.read() +shutil.copy("cppcheck-htmlreport", "cppcheck_htmlreport/run.py") + setup( - name="cppcheck", - description='Python script to parse the XML (version 2) output of ' + - 'cppcheck and generate an HTML report using Pygments for syntax ' + - 'highlighting.', + name="cppcheck-htmlreport", + description=( + "Python script to parse the XML (version 2) output of " + "cppcheck and generate an HTML report using Pygments for syntax " + "highlighting." + ), long_description=readme, - author='Henrik Nilsson', - url='https://github.com/danmar/cppcheck', - license='GPL', - scripts=[ - "cppcheck-htmlreport", - ], - install_requires=['Pygments'] + author="Cppcheck Team", + url="https://github.com/danmar/cppcheck", + license="GPL", + packages=find_packages(exclude=("tests", "docs")), + use_scm_version={"root": ".."}, + entry_points={ + "console_scripts": [ + "cppcheck-htmlreport = cppcheck_htmlreport:run.main", + ] + }, + install_requires=["Pygments"], + # Required by setuptools-scm 7.0 for Python 3.7+ + setup_requires=["setuptools>=60", "setuptools-scm>=7.0"], ) diff --git a/htmlreport/test_suppressions.txt b/htmlreport/test_suppressions.txt deleted file mode 100644 index ec3130c099f..00000000000 --- a/htmlreport/test_suppressions.txt +++ /dev/null @@ -1,3 +0,0 @@ -variableScope:../samples/memleak/good.c -*:../samples/resourceLeak/notexisting.c* -uninitstring:* diff --git a/htmlreport/tox.ini b/htmlreport/tox.ini deleted file mode 100644 index 502ca70c110..00000000000 --- a/htmlreport/tox.ini +++ /dev/null @@ -1,12 +0,0 @@ -[tox] -envlist=py26,py27,py32,pypy - -[testenv] -commands= - python test_htmlreport.py -deps=pygments - -[testenv:py26] -deps= - unittest2 - pygments diff --git a/htmlreport/check.sh b/test/tools/htmlreport/check.sh similarity index 54% rename from htmlreport/check.sh rename to test/tools/htmlreport/check.sh index a4515ec0690..dc9d9970cd6 100755 --- a/htmlreport/check.sh +++ b/test/tools/htmlreport/check.sh @@ -26,6 +26,9 @@ if [ -z "$PYTHON" ]; then PYTHON=python fi +SCRIPT_DIR="$(dirname ${BASH_SOURCE[0]})" +ABSOLUTE_SCRIPT_DIR="$(cd -- ${SCRIPT_DIR} ; pwd -P)" +PROJECT_ROOT_DIR="$(cd -- ${SCRIPT_DIR}/../../../ ; pwd -P)" REPORT_DIR=$(mktemp -d -t htmlreport-XXXXXXXXXX) INDEX_HTML="$REPORT_DIR/index.html" STATS_HTML="$REPORT_DIR/stats.html" @@ -33,42 +36,42 @@ GUI_TEST_XML="$REPORT_DIR/gui_test.xml" ERRORLIST_XML="$REPORT_DIR/errorlist.xml" UNMATCHEDSUPPR_XML="$REPORT_DIR/unmatchedSuppr.xml" -$PYTHON cppcheck-htmlreport --file ../gui/test/data/xmlfiles/xmlreport_v2.xml --title "xml2 test" --report-dir "$REPORT_DIR" --source-dir ../test/ +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file ${PROJECT_ROOT_DIR}/gui/test/data/xmlfiles/xmlreport_v2.xml --title "xml2 test" --report-dir "$REPORT_DIR" --source-dir ${PROJECT_ROOT_DIR}/test/ echo -e "\n" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck ../samples --enable=all --inconclusive --xml-version=2 2> "$GUI_TEST_XML" +${PROJECT_ROOT_DIR}/cppcheck ${PROJECT_ROOT_DIR}/samples --enable=all --inconclusive --xml-version=2 2> "$GUI_TEST_XML" xmllint --noout "$GUI_TEST_XML" -$PYTHON cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive test" --report-dir "$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive test" --report-dir "$REPORT_DIR" echo "" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck ../samples --enable=all --inconclusive --verbose --xml-version=2 2> "$GUI_TEST_XML" +${PROJECT_ROOT_DIR}/cppcheck ${PROJECT_ROOT_DIR}/samples --enable=all --inconclusive --verbose --xml-version=2 2> "$GUI_TEST_XML" xmllint --noout "$GUI_TEST_XML" -$PYTHON cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive + verbose test" --report-dir "$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$GUI_TEST_XML" --title "xml2 + inconclusive + verbose test" --report-dir "$REPORT_DIR" echo -e "\n" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck --errorlist --inconclusive --xml-version=2 > "$ERRORLIST_XML" +${PROJECT_ROOT_DIR}/cppcheck --errorlist --inconclusive --xml-version=2 > "$ERRORLIST_XML" xmllint --noout "$ERRORLIST_XML" -$PYTHON cppcheck-htmlreport --file "$ERRORLIST_XML" --title "errorlist" --report-dir "$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$ERRORLIST_XML" --title "errorlist" --report-dir "$REPORT_DIR" # Check HTML syntax validate_html "$INDEX_HTML" validate_html "$STATS_HTML" -../cppcheck ../samples/memleak/good.c ../samples/resourceLeak/good.c --xml-version=2 --enable=information --suppressions-list=test_suppressions.txt --xml 2> "$UNMATCHEDSUPPR_XML" +${PROJECT_ROOT_DIR}/cppcheck ${PROJECT_ROOT_DIR}/samples/memleak/good.c ${PROJECT_ROOT_DIR}/samples/resourceLeak/good.c --xml-version=2 --enable=information --suppressions-list="${ABSOLUTE_SCRIPT_DIR}/test_suppressions.txt" --xml 2> "$UNMATCHEDSUPPR_XML" xmllint --noout "$UNMATCHEDSUPPR_XML" -$PYTHON cppcheck-htmlreport --file "$UNMATCHEDSUPPR_XML" --title "unmatched Suppressions" --report-dir="$REPORT_DIR" +$PYTHON ${PROJECT_ROOT_DIR}/htmlreport/cppcheck-htmlreport --file "$UNMATCHEDSUPPR_XML" --title "unmatched Suppressions" --report-dir="$REPORT_DIR" grep "unmatchedSuppression<.*>information<.*>Unmatched suppression: variableScope*<" "$INDEX_HTML" grep ">unmatchedSuppressioninformation<.*>Unmatched suppression: uninitstring<" "$INDEX_HTML" grep "notexisting" "$INDEX_HTML" diff --git a/htmlreport/example.cc b/test/tools/htmlreport/example.cc similarity index 100% rename from htmlreport/example.cc rename to test/tools/htmlreport/example.cc diff --git a/htmlreport/example.xml b/test/tools/htmlreport/example.xml similarity index 100% rename from htmlreport/example.xml rename to test/tools/htmlreport/example.xml diff --git a/htmlreport/test_htmlreport.py b/test/tools/htmlreport/test_htmlreport.py similarity index 86% rename from htmlreport/test_htmlreport.py rename to test/tools/htmlreport/test_htmlreport.py index 4fd6cf6c256..4b40650cf09 100755 --- a/htmlreport/test_htmlreport.py +++ b/test/tools/htmlreport/test_htmlreport.py @@ -14,11 +14,15 @@ else: import unittest -ROOT_DIR = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] +TEST_TOOLS_DIR = os.path.abspath(os.path.dirname(__file__)) +ROOT_DIR = os.path.split(os.path.dirname(os.path.dirname(TEST_TOOLS_DIR)))[0] +HTMLREPORT_DIR = os.path.join(ROOT_DIR, 'htmlreport') CPPCHECK_BIN = os.path.join(ROOT_DIR, 'cppcheck') -HTML_REPORT_BIN = os.path.join(os.path.abspath(os.path.dirname(__file__)), - 'cppcheck-htmlreport') +if os.getenv("PIP_PACKAGE_TEST") is not None: + HTML_REPORT_BIN = ['cppcheck-htmlreport'] +else: + HTML_REPORT_BIN = [sys.executable, os.path.join(HTMLREPORT_DIR, 'cppcheck-htmlreport')] class TestHTMLReport(unittest.TestCase): @@ -65,7 +69,7 @@ def checkReportNoError(self, xml_version): def testMissingInclude(self): with runCheck( - xml_filename=os.path.join(ROOT_DIR, 'htmlreport', 'example.xml'), + xml_filename=os.path.join(TEST_TOOLS_DIR, 'example.xml'), ) as (report, output_directory): self.assertIn('