Initial commit. monorepo deps are copied in a dirty way to the vendor folder
This commit is contained in:
commit
06593ac488
53 files changed
+7692
No files matched your search
@@ -0,0 +1 @@
|
||||
"""The commands the report generator exposes."""
|
||||
@@ -0,0 +1,88 @@
|
||||
"""report_generator generate command."""
|
||||
|
||||
from pathlib import Path
|
||||
from uuid import UUID
|
||||
|
||||
from cc_common.api import PipelineError, context
|
||||
from cc_common.utils import print
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from persistent_storage.shared import StorageConfiguration
|
||||
|
||||
from ..rendering import render
|
||||
from ..sources import collect
|
||||
|
||||
# Where the report goes when the caller names no path.
|
||||
DEFAULT_DIRECTORY = Path("reports")
|
||||
|
||||
|
||||
class GenerateProperties(BaseModel):
|
||||
"""Configuration properties for the generate CLI command.
|
||||
|
||||
Attributes:
|
||||
scan_id: The scan to report on.
|
||||
path: Where to write the PDF. A directory is written into under the name
|
||||
the renderer chose; leaving it out writes into ``reports/``.
|
||||
storage_config: The store the scan's artifacts are read from.
|
||||
"""
|
||||
|
||||
scan_id: UUID = Field(description="The scan the report should be generated for.")
|
||||
path: Path | None = Field(default=None, description="Where to write the PDF report.")
|
||||
storage_config: StorageConfiguration
|
||||
|
||||
|
||||
class GeneratedReport(BaseModel):
|
||||
"""The report that was written.
|
||||
|
||||
Attributes:
|
||||
scan_id: The scan it is about.
|
||||
path: The file written.
|
||||
size: How large it came out, in bytes.
|
||||
"""
|
||||
|
||||
scan_id: UUID
|
||||
path: Path
|
||||
size: int
|
||||
|
||||
def print_as_cc_common_result(self) -> None:
|
||||
"""Say what was written and where."""
|
||||
print(f"[bold]Report for scan {self.scan_id}[/bold]")
|
||||
print(f" {self.size / 1024:.0f} kB written to {self.path}")
|
||||
|
||||
|
||||
def generate(properties: GenerateProperties) -> GeneratedReport:
|
||||
"""Build the PDF report of one scan and write it.
|
||||
|
||||
Args:
|
||||
properties: Parsed command properties naming the scan and the destination.
|
||||
|
||||
Returns:
|
||||
The report that was written.
|
||||
|
||||
Raises:
|
||||
PipelineError: The scan cannot be read, is missing an input the report
|
||||
needs, or the destination cannot be written.
|
||||
"""
|
||||
sources = collect(properties.storage_config, properties.scan_id)
|
||||
name, content = render(sources)
|
||||
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 report to '{destination}': {error}"
|
||||
|
||||
raise PipelineError(message) from error
|
||||
|
||||
context.logger.info(f"Report written to {destination} ✔")
|
||||
|
||||
return GeneratedReport(scan_id=properties.scan_id, path=destination, size=len(content))
|
||||
|
||||
|
||||
def _destination(path: Path | None, name: str) -> Path:
|
||||
"""Where the report goes, treating a directory as a place to put it rather than as the file."""
|
||||
if path is None:
|
||||
return DEFAULT_DIRECTORY / name
|
||||
|
||||
return path / name if path.is_dir() or not path.suffix else path
|
||||
Reference in new issue
Block a user