"""Build tracking model for ISO generation.""" import enum import uuid from datetime import datetime from sqlalchemy import DateTime, Enum, Index, String, Text, func from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from backend.app.db.base import Base class BuildStatus(enum.Enum): """Status values for build tracking.""" PENDING = "pending" BUILDING = "building" COMPLETED = "completed" FAILED = "failed" CACHED = "cached" class Build(Base): """Model for tracking ISO build jobs. Attributes: id: Unique identifier for the build (UUID) config_hash: SHA-256 hash of the build configuration (64 chars) status: Current build status iso_path: Path to generated ISO file (if completed) error_message: Error message if build failed build_log: Full build output log started_at: Timestamp when build started completed_at: Timestamp when build completed created_at: Timestamp when build was created updated_at: Timestamp of last update The config_hash enables caching - identical configurations can return existing ISOs without rebuilding. """ __tablename__ = "builds" # Primary key id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, ) # Configuration hash for caching (SHA-256 = 64 hex chars) config_hash: Mapped[str] = mapped_column( String(64), unique=True, index=True, nullable=False, ) # Build status status: Mapped[BuildStatus] = mapped_column( Enum(BuildStatus), default=BuildStatus.PENDING, nullable=False, ) # Build results iso_path: Mapped[str | None] = mapped_column( String(512), nullable=True, ) error_message: Mapped[str | None] = mapped_column( Text, nullable=True, ) build_log: Mapped[str | None] = mapped_column( Text, nullable=True, ) # Timing started_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, ) completed_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, ) # Audit timestamps created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False, ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False, ) # Indexes for common queries __table_args__ = ( # Index on status for queue queries (find pending builds) Index("ix_builds_status", "status"), # Index on config_hash already created via column definition ) def __repr__(self) -> str: """String representation of Build.""" return f""