Skip to main content

olai_stack_runtime/
engine.rs

1//! The [`ComposeEngine`] trait: what the runtime asks of Docker Compose.
2
3use std::collections::BTreeMap;
4use std::path::Path;
5use std::time::Duration;
6
7use async_trait::async_trait;
8use futures::stream::BoxStream;
9
10use crate::error::Result;
11use crate::events::{EngineEvent, EventFilter};
12use crate::logs::LogLine;
13use crate::status::{ProjectStatus, ServiceStatus};
14
15/// Where a command's progress output goes.
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
17pub enum Progress {
18    /// To this process's stdout/stderr, as if the user ran `docker compose` themselves.
19    #[default]
20    Inherit,
21    /// Captured: stdout is dropped, stderr is kept for the error.
22    Quiet,
23}
24
25/// How to [`up`](ComposeEngine::up) a project.
26#[derive(Clone, Debug, Default)]
27pub struct UpOptions {
28    /// Wait until every service runs and passes its healthcheck (`--wait`).
29    pub wait: bool,
30    /// Give up waiting after this long (`--wait-timeout`).
31    pub wait_timeout: Option<Duration>,
32    /// Variables added to the command's environment, which Compose interpolates `${VAR}`
33    /// references from. Values reach Compose this way only, never through a file.
34    pub env: BTreeMap<String, String>,
35    /// Where progress output goes.
36    pub progress: Progress,
37}
38
39/// How to [`down`](ComposeEngine::down) a project.
40#[derive(Clone, Debug, Default)]
41pub struct DownOptions {
42    /// Also remove the project's named volumes (`--volumes`).
43    pub volumes: bool,
44    /// Variables added to the command's environment (Compose interpolates the project's
45    /// files on `down` too, so the ones `up` needed must be present).
46    pub env: BTreeMap<String, String>,
47    /// Where progress output goes.
48    pub progress: Progress,
49}
50
51/// How to read a project's [`logs`](ComposeEngine::logs).
52#[derive(Clone, Debug, Default)]
53pub struct LogOptions {
54    /// Keep streaming new lines (`--follow`).
55    pub follow: bool,
56    /// Only the last this many lines per container (`--tail`).
57    pub tail: Option<u32>,
58    /// Only these services (all of them when empty).
59    pub services: Vec<String>,
60}
61
62/// A stream of items from a long-running command; dropping it stops the command.
63pub type EngineStream<T> = BoxStream<'static, Result<T>>;
64
65/// Docker Compose, as the runtime drives it. [`DockerCli`](crate::DockerCli) runs the real
66/// CLI; [`FakeEngine`](crate::FakeEngine) (feature `testing`) is an in-memory stand-in.
67///
68/// A project is addressed by the directory holding its head `compose.yaml` for the commands
69/// that read its files (`up`, `down`), and by its name for the ones Docker answers from its
70/// labels (`ps`, `logs`).
71#[async_trait]
72pub trait ComposeEngine: Send + Sync {
73    /// Create and start the project in `dir` (`docker compose up -d`).
74    async fn up(&self, dir: &Path, opts: &UpOptions) -> Result<()>;
75
76    /// Stop and remove the project in `dir` (`docker compose down`).
77    async fn down(&self, dir: &Path, opts: &DownOptions) -> Result<()>;
78
79    /// Every project Docker knows of, running or stopped (`docker compose ls --all`).
80    async fn ls(&self) -> Result<Vec<ProjectStatus>>;
81
82    /// The containers of `project`, running or stopped (`docker compose ps --all`).
83    async fn ps(&self, project: &str) -> Result<Vec<ServiceStatus>>;
84
85    /// The log lines of `project`'s containers (`docker compose logs --timestamps`).
86    async fn logs(&self, project: &str, opts: &LogOptions) -> Result<EngineStream<LogLine>>;
87
88    /// Container events of the projects `filter` picks, from now on (`docker events`).
89    async fn events(&self, filter: &EventFilter) -> Result<EngineStream<EngineEvent>>;
90
91    /// Remove the network `name`; `Ok(false)` when it doesn't exist or is still in use.
92    async fn network_rm(&self, name: &str) -> Result<bool>;
93}