#![forbid(unsafe_code)]
mod error;
pub use error::{BackendError, Result};
mod request;
pub use request::{Plan, RunOptions, RunRequest, SourceMeta};
mod outcome;
pub use outcome::{BuildOutcome, BuildStatus, StepResultSummary, StepStatus};
mod capabilities;
pub use capabilities::Capabilities;
pub mod local;
pub use local::LocalBackend;
pub mod cloud;
pub use cloud::CloudBackend;
pub use hm_plugin_protocol::events::BuildRef;
use futures::StreamExt as _;
use hm_plugin_protocol::events::BuildEvent;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
use tokio_stream::wrappers::ReceiverStream;
use tokio_util::sync::CancellationToken;
pub type EventStream = futures::stream::BoxStream<'static, BuildEvent>;
#[async_trait::async_trait]
pub trait ExecutionBackend: Send + Sync {
fn name(&self) -> &str;
fn capabilities(&self) -> Capabilities;
async fn start(&self, req: RunRequest) -> Result<BackendHandle>;
}
pub struct BackendHandle {
events: EventStream,
cancel: CancellationToken,
outcome: JoinHandle<Result<BuildOutcome>>,
}
impl BackendHandle {
#[must_use]
pub fn spawn(
rx: mpsc::Receiver<BuildEvent>,
cancel: CancellationToken,
outcome: JoinHandle<Result<BuildOutcome>>,
) -> Self {
Self {
events: ReceiverStream::new(rx).boxed(),
cancel,
outcome,
}
}
#[must_use]
pub fn into_parts(self) -> (EventStream, Control) {
(
self.events,
Control {
cancel: self.cancel,
outcome: self.outcome,
},
)
}
}
impl std::fmt::Debug for BackendHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BackendHandle").finish_non_exhaustive()
}
}
pub struct Control {
cancel: CancellationToken,
outcome: JoinHandle<Result<BuildOutcome>>,
}
impl Control {
#[must_use]
pub fn cancel_token(&self) -> CancellationToken {
self.cancel.clone()
}
pub fn cancel(&self) {
self.cancel.cancel();
}
pub async fn wait(self) -> Result<BuildOutcome> {
match self.outcome.await {
Ok(res) => res,
Err(join_err) => Err(BackendError::Other(Box::new(join_err))),
}
}
}
impl std::fmt::Debug for Control {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Control").finish_non_exhaustive()
}
}