From f1bcb2a45c4ba42d8dea3ba7c3413cb1d0fcab93 Mon Sep 17 00:00:00 2001 From: Sen Hastings Date: Fri, 22 Jul 2022 14:15:58 -0500 Subject: [PATCH] support/scripts/pkg-stats: migrate to CSS grid and inline javascript This migrates pkg-stats.html from html tables to CSS grid, allowing the use of newer, simpler javascript that is short enough to be inlined, instead of relying on externally hosted javascript. Javascript sorting function was rewritten from scratch in ~55 lines, short enough to be inlined directly in the html. Tables were redone in CSS grid, but with care taken to mimic existing "look and feel" of prevous implementation, albeit with slightly better responsive behavior and default styling characteristics. Column labels are now "sticky" and stay stuck to the top of the viewport as you scroll down the page. Also, css was rewritten in fewer lines and table elements were changed to divs (for grid support). Other small misc fixes include quoted hrefs and document language declarations to make the w3c html validator happy. Signed-off-by: Sen Hastings Signed-off-by: Arnout Vandecappelle (Essensium/Mind) --- support/scripts/pkg-stats | 415 +++++++++++++++++++++----------------- 1 file changed, 228 insertions(+), 187 deletions(-) diff --git a/support/scripts/pkg-stats b/support/scripts/pkg-stats index f67be0063f..6dc206d2bc 100755 --- a/support/scripts/pkg-stats +++ b/support/scripts/pkg-stats @@ -718,89 +718,113 @@ def calculate_stats(packages): html_header = """ + + - - + Statistics of Buildroot packages + + + Results

@@ -808,13 +832,13 @@ td.cve_ignored { html_footer = """ - + """ @@ -841,73 +865,87 @@ def boolean_str(b): def dump_html_pkg(f, pkg): - f.write(" \n") - f.write(" %s\n" % pkg.path) - + f.write( f'
{pkg.path}
\n') # Patch count - td_class = ["centered"] + data_field_id = f'patch_count_{pkg.name}' + div_class = ["centered patch_count data"] + div_class.append(pkg.name) if pkg.patch_count == 0: - td_class.append("nopatches") + div_class.append("nopatches") elif pkg.patch_count < 5: - td_class.append("somepatches") + div_class.append("somepatches") else: - td_class.append("lotsofpatches") - f.write(" %s\n" % - (" ".join(td_class), str(pkg.patch_count))) + div_class.append("lotsofpatches") + f.write( f'
{str(pkg.patch_count)}
\n') # Infrastructure + data_field_id = f'infrastructure_{pkg.name}' infra = infra_str(pkg.infras) - td_class = ["centered"] + div_class = ["centered infrastructure data"] + div_class.append(pkg.name) if infra == "Unknown": - td_class.append("wrong") + div_class.append("wrong") else: - td_class.append("correct") - f.write(" %s\n" % - (" ".join(td_class), infra_str(pkg.infras))) + div_class.append("correct") + f.write( f'
{infra_str(pkg.infras)}
\n') # License - td_class = ["centered"] + data_field_id = f'license_{pkg.name}' + div_class = ["centered license data"] + div_class.append(pkg.name) if pkg.is_status_ok('license'): - td_class.append("correct") + div_class.append("correct") else: - td_class.append("wrong") - f.write(" %s\n" % - (" ".join(td_class), boolean_str(pkg.is_status_ok('license')))) + div_class.append("wrong") + f.write(f'
{boolean_str(pkg.is_status_ok("license"))}
\n') # License files - td_class = ["centered"] + data_field_id = f'license_files_{pkg.name}' + div_class = ["centered license_files data"] + div_class.append(pkg.name) if pkg.is_status_ok('license-files'): - td_class.append("correct") + div_class.append("correct") else: - td_class.append("wrong") - f.write(" %s\n" % - (" ".join(td_class), boolean_str(pkg.is_status_ok('license-files')))) + div_class.append("wrong") + f.write(f'
{boolean_str(pkg.is_status_ok("license-files"))}
\n') # Hash - td_class = ["centered"] + data_field_id = f'hash_file_{pkg.name}' + div_class = ["centered hash_file data"] + div_class.append(pkg.name) if pkg.is_status_ok('hash'): - td_class.append("correct") + div_class.append("correct") else: - td_class.append("wrong") - f.write(" %s\n" % - (" ".join(td_class), boolean_str(pkg.is_status_ok('hash')))) + div_class.append("wrong") + f.write(f'
{boolean_str(pkg.is_status_ok("hash"))}
\n') # Current version + data_field_id = f'current_version_{pkg.name}' if len(pkg.current_version) > 20: current_version = pkg.current_version[:20] + "..." else: current_version = pkg.current_version - f.write(" %s\n" % current_version) + f.write(f'
{current_version}
\n') # Latest version + data_field_id = f'latest_version_{pkg.name}' + div_class.append(pkg.name) + div_class.append("latest_version data") if pkg.latest_version['status'] == RM_API_STATUS_ERROR: - td_class.append("version-error") + div_class.append("version-error") if pkg.latest_version['version'] is None: - td_class.append("version-unknown") + div_class.append("version-unknown") elif pkg.latest_version['version'] != pkg.current_version: - td_class.append("version-needs-update") + div_class.append("version-needs-update") else: - td_class.append("version-good") + div_class.append("version-good") if pkg.latest_version['status'] == RM_API_STATUS_ERROR: latest_version_text = "Error" @@ -927,74 +965,81 @@ def dump_html_pkg(f, pkg): else: latest_version_text += "found by guess" - f.write(" %s\n" % - (" ".join(td_class), latest_version_text)) + f.write(f'
{latest_version_text}
\n') # Warnings - td_class = ["centered"] + data_field_id = f'warnings_{pkg.name}' + div_class = ["centered warnings data"] + div_class.append(pkg.name) if pkg.warnings == 0: - td_class.append("correct") + div_class.append("correct") else: - td_class.append("wrong") - f.write(" %d\n" % - (" ".join(td_class), pkg.warnings)) + div_class.append("wrong") + f.write(f'
{pkg.warnings}
\n') # URL status - td_class = ["centered"] + data_field_id = f'upstream_url_{pkg.name}' + div_class = ["centered upstream_url data"] + div_class.append(pkg.name) url_str = pkg.status['url'][1] if pkg.status['url'][0] in ("error", "warning"): - td_class.append("missing_url") + div_class.append("missing_url") if pkg.status['url'][0] == "error": - td_class.append("invalid_url") - url_str = "%s" % (pkg.url, pkg.status['url'][1]) + div_class.append("invalid_url") + url_str = "%s" % (pkg.url, pkg.status['url'][1]) else: - td_class.append("good_url") - url_str = "Link" % pkg.url - f.write(" %s\n" % - (" ".join(td_class), url_str)) + div_class.append("good_url") + url_str = "Link" % pkg.url + f.write(f'
{url_str}
\n') # CVEs - td_class = ["centered"] + data_field_id = f'cves_{pkg.name}' + div_class = ["centered cves data"] + div_class.append(pkg.name) if pkg.is_status_ok("cve"): - td_class.append("cve-ok") + div_class.append("cve-ok") elif pkg.is_status_error("cve"): - td_class.append("cve-nok") + div_class.append("cve-nok") elif pkg.is_status_na("cve") and not pkg.is_actual_package: - td_class.append("cve-ok") + div_class.append("cve-ok") else: - td_class.append("cve-unknown") - f.write(" \n" % " ".join(td_class)) + div_class.append("cve-unknown") + f.write(f'
\n') if pkg.is_status_error("cve"): for cve in pkg.cves: - f.write(" %s
\n" % (cve, cve)) + f.write("
%s
\n" % (cve, cve)) for cve in pkg.unsure_cves: - f.write(" %s (unsure)
\n" % (cve, cve)) + f.write("
%s (unsure)
\n" % (cve, cve)) elif pkg.is_status_na("cve"): f.write(" %s" % pkg.status['cve'][1]) else: f.write(" N/A\n") - f.write(" \n") + f.write("
\n") # CVEs Ignored - td_class = ["centered"] + data_field_id = f'ignored_cves_{pkg.name}' + div_class = ["centered data ignored_cves"] + div_class.append(pkg.name) if pkg.ignored_cves: - td_class.append("cve_ignored") - f.write(" \n" % " ".join(td_class)) + div_class.append("cve_ignored") + f.write(f'
\n') for ignored_cve in pkg.ignored_cves: - f.write(" %s
\n" % (ignored_cve, ignored_cve)) - f.write(" \n") + f.write("
%s
\n" % (ignored_cve, ignored_cve)) + f.write("
\n") # CPE ID - td_class = ["left"] + data_field_id = f'cpe_id_{pkg.name}' + div_class = ["left cpe_id data"] + div_class.append(pkg.name) if pkg.is_status_ok("cpe"): - td_class.append("cpe-ok") + div_class.append("cpe-ok") elif pkg.is_status_error("cpe"): - td_class.append("cpe-nok") + div_class.append("cpe-nok") elif pkg.is_status_na("cpe") and not pkg.is_actual_package: - td_class.append("cpe-ok") + div_class.append("cpe-ok") else: - td_class.append("cpe-unknown") - f.write(" \n" % " ".join(td_class)) + div_class.append("cpe-unknown") + f.write(f'
\n') if pkg.cpeid: f.write(" %s\n" % pkg.cpeid) if not pkg.is_status_ok("cpe"): @@ -1008,79 +1053,75 @@ def dump_html_pkg(f, pkg): else: f.write(" %s\n" % pkg.status['cpe'][1]) - f.write(" \n") - - f.write(" \n") + f.write("
\n") def dump_html_all_pkgs(f, packages): f.write(""" - - - - - - - - - - - - - - - - +
+
Package
+
Patch count
+
Infrastructure
+
License
+
License files
+
Hash file
+
Current version
+
Latest version
+
Warnings
+
Upstream URL
+
CVEs
+
CVEs Ignored
+
CPE ID
""") for pkg in sorted(packages): dump_html_pkg(f, pkg) - f.write("
PackagePatch countInfrastructureLicenseLicense filesHash fileCurrent versionLatest versionWarningsUpstream URLCVEsCVEs IgnoredCPE ID
") + f.write("") def dump_html_stats(f, stats): f.write("\n") - f.write("\n") + f.write("
\n") infras = [infra[6:] for infra in stats.keys() if infra.startswith("infra-")] for infra in infras: - f.write("
\n" % + f.write("
Packages using the %s infrastructure
%s
\n" % (infra, stats["infra-%s" % infra])) - f.write(" \n" % + f.write("
Packages having license information
%s
\n" % stats["license"]) - f.write(" \n" % + f.write("
Packages not having license information
%s
\n" % stats["no-license"]) - f.write(" \n" % + f.write("
Packages having license files information
%s
\n" % stats["license-files"]) - f.write(" \n" % + f.write("
Packages not having license files information
%s
\n" % stats["no-license-files"]) - f.write(" \n" % + f.write("
Packages having a hash file
%s
\n" % stats["hash"]) - f.write(" \n" % + f.write("
Packages not having a hash file
%s
\n" % stats["no-hash"]) - f.write(" \n" % + f.write("
Total number of patches
%s
\n" % stats["patches"]) - f.write("\n" % + f.write("
Packages having a mapping on release-monitoring.org
%s
\n" % stats["rmo-mapping"]) - f.write("\n" % + f.write("
Packages lacking a mapping on release-monitoring.org
%s
\n" % stats["rmo-no-mapping"]) - f.write("\n" % + f.write("
Packages that are up-to-date
%s
\n" % stats["version-uptodate"]) - f.write("\n" % + f.write("
Packages that are not up-to-date
%s
\n" % stats["version-not-uptodate"]) - f.write("\n" % + f.write("
Packages with no known upstream version
%s
\n" % stats["version-unknown"]) - f.write("\n" % + f.write("
Packages affected by CVEs
%s
\n" % stats["pkg-cves"]) - f.write("\n" % + f.write("
Total number of CVEs affecting all packages
%s
\n" % stats["total-cves"]) - f.write("\n" % + f.write("
Packages affected by unsure CVEs
%s
\n" % stats["pkg-unsure-cves"]) - f.write("\n" % + f.write("
Total number of unsure CVEs affecting all packages
%s
\n" % stats["total-unsure-cves"]) - f.write("\n" % + f.write("
Packages with CPE ID
%s
\n" % stats["cpe-id"]) - f.write("\n" % + f.write("
Packages without CPE ID
%s
\n" % stats["no-cpe-id"]) - f.write("
Packages using the %s infrastructure%s
Packages having license information%s
Packages not having license information%s
Packages having license files information%s
Packages not having license files information%s
Packages having a hash file%s
Packages not having a hash file%s
Total number of patches%s
Packages having a mapping on release-monitoring.org%s
Packages lacking a mapping on release-monitoring.org%s
Packages that are up-to-date%s
Packages that are not up-to-date%s
Packages with no known upstream version%s
Packages affected by CVEs%s
Total number of CVEs affecting all packages%s
Packages affected by unsure CVEs%s
Total number of unsure CVEs affecting all packages%s
Packages with CPE ID%s
Packages without CPE ID%s
\n") + f.write("\n") def dump_html_gen_info(f, date, commit):