use async_trait::async_trait;
pub mod enhance;
pub mod task;
pub(crate) mod semver_resolve {
use crate::blueprint::store::{
BlueprintId, BlueprintStore, BlueprintStoreError, BlueprintVersion,
};
pub(crate) enum SemverResolveError {
Store(BlueprintStoreError),
InvalidSemver {
label: String,
source: semver::Error,
},
NoMatchingVersion {
req: String,
},
}
pub(crate) async fn resolve_semver(
store: &dyn BlueprintStore,
id: &BlueprintId,
req: &semver::VersionReq,
) -> Result<BlueprintVersion, SemverResolveError> {
let versions = store
.history(id, 1024)
.await
.map_err(SemverResolveError::Store)?;
let mut candidates: Vec<(semver::Version, BlueprintVersion)> =
Vec::with_capacity(versions.len());
for v in versions {
let traced = store
.read_version(id, v)
.await
.map_err(SemverResolveError::Store)?;
let Some(label) = traced.value.metadata.version_label.as_deref() else {
continue;
};
let sv =
semver::Version::parse(label).map_err(|e| SemverResolveError::InvalidSemver {
label: label.to_string(),
source: e,
})?;
if req.matches(&sv) {
candidates.push((sv, v));
}
}
candidates.sort_by(|a, b| b.0.cmp(&a.0));
candidates
.into_iter()
.next()
.map(|(_, v)| v)
.ok_or_else(|| SemverResolveError::NoMatchingVersion {
req: req.to_string(),
})
}
}
pub use enhance::{
EnhanceApplication, EnhanceApplicationConfig, EnhanceApplicationError, EnhanceApplicationInput,
TickOutcome,
};
pub use task::{
BlueprintRef, TaskApplication, TaskApplicationError, TaskApplicationInput,
TaskApplicationOutput, VersionSelector,
};
#[async_trait]
pub trait Application: Send + Sync {
type Input: Send;
type Output: Send;
type Error: Send + std::fmt::Debug;
fn name(&self) -> &str;
async fn handle(&self, input: Self::Input) -> Result<Self::Output, Self::Error>;
}