"""The summary report: a Markdown summary, set as a PDF in the style of the full report.""" from pathlib import Path from uuid import UUID from pydantic import BaseModel, Field from ..vendor.cc_common.api import PipelineError, context from ..vendor.cc_common.utils import print from ..summary import render_summary from .generate import _destination class SummaryProperties(BaseModel): """Configuration properties for the from-markdown CLI command. Attributes: markdown: The Markdown summary to set. scan_id: The scan it is about. Named on the cover and in the footers when given, and left out when not. path: Where to write the PDF. A directory is written into under the name the renderer chose; leaving it out writes into ``reports/``. project: The name of the scanned project. Taken from the summary's title when not given. manufacturer: Who makes the scanned product, as the summary states it. """ markdown: Path = Field(description="The Markdown summary to build the PDF from.") scan_id: UUID | None = Field(default=None, description="The scan the summary is about.") path: Path | None = Field(default=None, description="Where to write the PDF summary.") project: str | None = Field( default=None, description="The name of the scanned project. Read from the title when omitted." ) manufacturer: str | None = Field(default=None, description="The manufacturer of the scanned product.") class GeneratedSummary(BaseModel): """The summary that was written. Attributes: source: The Markdown it was set from. path: The file written. size: How large it came out, in bytes. """ source: Path path: Path size: int def print_as_cc_common_result(self) -> None: """Say what was written and where.""" print(f"[bold]Summary from {self.source}[/bold]") print(f" {self.size / 1024:.0f} kB written to {self.path}") def from_markdown(properties: SummaryProperties) -> GeneratedSummary: """Build the summary report from a Markdown file. Args: properties: The Markdown file, what to say about it, and the destination. Returns: The summary that was written. Raises: PipelineError: The Markdown cannot be read, or the destination cannot be written. """ try: markdown = properties.markdown.read_text(encoding="utf-8") except (OSError, UnicodeDecodeError) as error: message = f"Cannot read the summary '{properties.markdown}': {error}" raise PipelineError(message) from error name, content = render_summary( markdown, scan_id=properties.scan_id, project=properties.project, manufacturer=properties.manufacturer, ) destination = _destination(properties.path, name) try: destination.parent.mkdir(parents=True, exist_ok=True) destination.write_bytes(content) except OSError as error: message = f"Cannot write the summary to '{destination}': {error}" raise PipelineError(message) from error context.logger.info(f"Summary written to {destination} ✔") return GeneratedSummary(source=properties.markdown, path=destination, size=len(content))