Module continuous_delivery_scripts.spdx_report.spdx_summary
Summary generators.
Expand source code
#
# Copyright (C) 2020-2025 Arm Limited or its affiliates and Contributors. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
"""Summary generators."""
import datetime
import jinja2
import logging
from pathlib import Path
from typing import List, Tuple, Optional, Dict, Any
from continuous_delivery_scripts.spdx_report.spdx_helpers import get_package_manual_check
from continuous_delivery_scripts.spdx_report.spdx_package import SpdxPackage
JINJA_TEMPLATE_SUMMARY_HTML = "third_party_IP_report.html.jinja2"
JINJA_TEMPLATE_SUMMARY_CSV = "third_party_IP_report.csv.jinja2"
JINJA_TEMPLATE_SUMMARY_TEXT = "third_party_IP_report.txt.jinja2"
JINJA_TEMPLATES = [JINJA_TEMPLATE_SUMMARY_HTML, JINJA_TEMPLATE_SUMMARY_CSV, JINJA_TEMPLATE_SUMMARY_TEXT]
logger = logging.getLogger(__name__)
try:
jinja2_env = jinja2.Environment(
loader=jinja2.PackageLoader("continuous_delivery_scripts.spdx_report.spdx_summary", "templates"),
autoescape=jinja2.select_autoescape(["html", "xml"]),
)
except ModuleNotFoundError as e:
logger.error(e)
def generate_file_based_on_template(
output_dir: Path, template_name: str, template_args: dict, suffix: Optional[str] = None
) -> None:
"""Write file based on template and arguments."""
logger.info("Loading template '%s'.", template_name)
template = jinja2_env.get_template(template_name)
filename = Path(template_name.rsplit(".", 1)[0])
if suffix:
filename = Path(
"{0}_{2}{1}".format(
*(str(filename.name), str(filename.suffix), str(suffix.replace(".", "_").replace("-", "_")))
)
)
output_filename = output_dir.joinpath(filename)
rendered = template.render(**template_args)
logger.info("Writing to '%s'.", output_filename)
output_filename.write_text(rendered, encoding="utf8")
class SummaryGenerator:
"""Licensing summary generator."""
def __init__(self, project_package: SpdxPackage, dependencies_documents: List[SpdxPackage]) -> None:
"""Initialiser."""
self.project = project_package
self.all_packages = list(dependencies_documents)
self.all_packages.append(self.project)
self._template_arguments: Optional[dict] = None
def _generate_template_arguments(self) -> Dict[str, Any]:
arguments: Dict[str, Any] = dict()
global_compliance, description_list = self._generate_packages_description()
arguments["project"] = {
"name": self.project.name,
"compliance": global_compliance,
"compliance_details": (
(
f"Project [{self.project.name}]'s licence is compliant: {self.project.licence}."
"All its dependencies are also compliant licence-wise."
)
if global_compliance
else f"Project [{self.project.name}] or one, at least, of its dependencies has a non compliant licence"
),
}
arguments["packages"] = description_list
arguments["render_time"] = datetime.datetime.now()
return arguments
def _generate_packages_description(self) -> Tuple[bool, dict]:
description_list = dict()
global_compliance = True
for p in self.all_packages:
main_licence_valid = p.is_main_licence_accepted
actual_licence_valid = p.is_licence_accepted
package_manually_checked, manual_check_details = get_package_manual_check(p.name)
is_licence_compliant = main_licence_valid and actual_licence_valid
is_compliant = is_licence_compliant or package_manually_checked
if not is_compliant:
global_compliance = False
description_list[p.name] = self._generate_description_for_one_package(
is_compliant, is_licence_compliant, package_manually_checked, manual_check_details, p
)
return global_compliance, description_list
def _generate_description_for_one_package(
self,
is_compliant: bool,
is_licence_compliant: bool,
package_manually_checked: bool,
manual_check_details: Optional[str],
p: SpdxPackage,
) -> dict:
return {
"name": p.name,
"is_dependency": p.is_dependency,
"url": p.url,
"licence": p.licence,
"is_compliant": is_compliant,
"mark_as_problematic": not is_licence_compliant,
"licence_compliance_details": (
"Licence is compliant."
if is_licence_compliant
else (
f"Package's licence manually checked: {manual_check_details}"
if package_manually_checked
else "Licence is not compliant according to project's configuration."
)
),
}
@property
def template_arguments(self) -> dict:
"""Gets template arguments."""
if not self._template_arguments:
self._template_arguments = self._generate_template_arguments()
return self._template_arguments
def generate_summary(self, dir: Path) -> None:
"""Generates a licensing summary into the specified directory.
Args:
dir: output directory
"""
for t in JINJA_TEMPLATES:
generate_file_based_on_template(dir, t, self.template_arguments)
Functions
def generate_file_based_on_template(output_dir: pathlib.Path, template_name: str, template_args: dict, suffix: Optional[str] = None) ‑> None
-
Write file based on template and arguments.
Expand source code
def generate_file_based_on_template( output_dir: Path, template_name: str, template_args: dict, suffix: Optional[str] = None ) -> None: """Write file based on template and arguments.""" logger.info("Loading template '%s'.", template_name) template = jinja2_env.get_template(template_name) filename = Path(template_name.rsplit(".", 1)[0]) if suffix: filename = Path( "{0}_{2}{1}".format( *(str(filename.name), str(filename.suffix), str(suffix.replace(".", "_").replace("-", "_"))) ) ) output_filename = output_dir.joinpath(filename) rendered = template.render(**template_args) logger.info("Writing to '%s'.", output_filename) output_filename.write_text(rendered, encoding="utf8")
Classes
class SummaryGenerator (project_package: SpdxPackage, dependencies_documents: List[SpdxPackage])
-
Licensing summary generator.
Initialiser.
Expand source code
class SummaryGenerator: """Licensing summary generator.""" def __init__(self, project_package: SpdxPackage, dependencies_documents: List[SpdxPackage]) -> None: """Initialiser.""" self.project = project_package self.all_packages = list(dependencies_documents) self.all_packages.append(self.project) self._template_arguments: Optional[dict] = None def _generate_template_arguments(self) -> Dict[str, Any]: arguments: Dict[str, Any] = dict() global_compliance, description_list = self._generate_packages_description() arguments["project"] = { "name": self.project.name, "compliance": global_compliance, "compliance_details": ( ( f"Project [{self.project.name}]'s licence is compliant: {self.project.licence}." "All its dependencies are also compliant licence-wise." ) if global_compliance else f"Project [{self.project.name}] or one, at least, of its dependencies has a non compliant licence" ), } arguments["packages"] = description_list arguments["render_time"] = datetime.datetime.now() return arguments def _generate_packages_description(self) -> Tuple[bool, dict]: description_list = dict() global_compliance = True for p in self.all_packages: main_licence_valid = p.is_main_licence_accepted actual_licence_valid = p.is_licence_accepted package_manually_checked, manual_check_details = get_package_manual_check(p.name) is_licence_compliant = main_licence_valid and actual_licence_valid is_compliant = is_licence_compliant or package_manually_checked if not is_compliant: global_compliance = False description_list[p.name] = self._generate_description_for_one_package( is_compliant, is_licence_compliant, package_manually_checked, manual_check_details, p ) return global_compliance, description_list def _generate_description_for_one_package( self, is_compliant: bool, is_licence_compliant: bool, package_manually_checked: bool, manual_check_details: Optional[str], p: SpdxPackage, ) -> dict: return { "name": p.name, "is_dependency": p.is_dependency, "url": p.url, "licence": p.licence, "is_compliant": is_compliant, "mark_as_problematic": not is_licence_compliant, "licence_compliance_details": ( "Licence is compliant." if is_licence_compliant else ( f"Package's licence manually checked: {manual_check_details}" if package_manually_checked else "Licence is not compliant according to project's configuration." ) ), } @property def template_arguments(self) -> dict: """Gets template arguments.""" if not self._template_arguments: self._template_arguments = self._generate_template_arguments() return self._template_arguments def generate_summary(self, dir: Path) -> None: """Generates a licensing summary into the specified directory. Args: dir: output directory """ for t in JINJA_TEMPLATES: generate_file_based_on_template(dir, t, self.template_arguments)
Instance variables
var template_arguments : dict
-
Gets template arguments.
Expand source code
@property def template_arguments(self) -> dict: """Gets template arguments.""" if not self._template_arguments: self._template_arguments = self._generate_template_arguments() return self._template_arguments
Methods
def generate_summary(self, dir: pathlib.Path) ‑> None
-
Generates a licensing summary into the specified directory.
Args
dir
- output directory
Expand source code
def generate_summary(self, dir: Path) -> None: """Generates a licensing summary into the specified directory. Args: dir: output directory """ for t in JINJA_TEMPLATES: generate_file_based_on_template(dir, t, self.template_arguments)