# retoor from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass, field from typing import Awaitable, Callable, Optional LogCallback = Callable[[str], Awaitable[None]] WORKSPACE_MOUNT = "/app" @dataclass class PortMapping: host: int container: int proto: str = "tcp" @dataclass class Mount: host: str container: str mode: str = "rw" @dataclass class RunSpec: image: str name: str labels: dict = field(default_factory=dict) env: dict = field(default_factory=dict) cpu_limit: str = "" mem_limit: str = "" ports: list = field(default_factory=list) mounts: list = field(default_factory=list) restart_policy: str = "no" command: list = field(default_factory=list) @dataclass class BuildResult: success: bool image_id: str = "" error: str = "" @dataclass class ExecResult: exit_code: int output: str = "" @dataclass class StatsSample: cpu_pct: float = 0.0 mem_bytes: int = 0 mem_pct: float = 0.0 net_rx: int = 0 net_tx: int = 0 blk_read: int = 0 blk_write: int = 0 @dataclass class PsRow: container_id: str name: str state: str status: str exit_code: Optional[int] labels: dict = field(default_factory=dict) class Backend(ABC): @abstractmethod async def build( self, *, context_dir: str, dockerfile_text: str, tags: list, on_log: Optional[LogCallback] = None, network: str = "", ) -> BuildResult: ... @abstractmethod async def run(self, spec: RunSpec) -> str: ... @abstractmethod async def start(self, cid: str) -> None: ... @abstractmethod async def stop(self, cid: str, timeout: int = 10) -> None: ... @abstractmethod async def restart(self, cid: str) -> None: ... @abstractmethod async def pause(self, cid: str) -> None: ... @abstractmethod async def unpause(self, cid: str) -> None: ... @abstractmethod async def rm(self, cid: str, force: bool = False) -> None: ... @abstractmethod async def exec( self, cid: str, cmd: list, *, tty: bool = False, on_log: Optional[LogCallback] = None, ) -> ExecResult: ... @abstractmethod async def logs( self, cid: str, *, follow: bool = False, tail: int = 200, on_log: Optional[LogCallback] = None, ) -> None: ... @abstractmethod async def stats_once(self, cids: list) -> dict: ... @abstractmethod async def ps(self, *, label_filter: str = "devplace.instance") -> list: ... @abstractmethod async def inspect(self, cid: str) -> dict: ... @abstractmethod async def image_prune(self) -> None: ... @abstractmethod async def remove_image(self, ref: str, force: bool = False) -> None: ... @abstractmethod async def image_exists(self, ref: str) -> bool: ...