use greentic_deploy_spec::CapabilitySlot;
use semver::VersionReq;
use crate::tool_check::ToolCheck;
pub trait EnvPackHandler: std::fmt::Debug + Send + Sync {
fn slot(&self) -> CapabilitySlot;
fn descriptor_path(&self) -> &str;
fn supported_versions(&self) -> VersionReq;
fn preflight(&self) -> Vec<ToolCheck> {
Vec::new()
}
}
#[derive(Debug, Clone, Copy)]
pub struct BuiltinHandler {
slot: CapabilitySlot,
descriptor_path: &'static str,
version_req: &'static str,
}
impl EnvPackHandler for BuiltinHandler {
fn slot(&self) -> CapabilitySlot {
self.slot
}
fn descriptor_path(&self) -> &str {
self.descriptor_path
}
fn supported_versions(&self) -> VersionReq {
self.version_req
.parse()
.expect("built-in version-req is valid (guarded by tests)")
}
}
pub const BUILTIN_HANDLERS: &[BuiltinHandler] = &[
BuiltinHandler {
slot: CapabilitySlot::Deployer,
descriptor_path: "greentic.deployer.local-process",
version_req: "^0.1.0",
},
BuiltinHandler {
slot: CapabilitySlot::Secrets,
descriptor_path: "greentic.secrets.dev-store",
version_req: "^0.1.0",
},
BuiltinHandler {
slot: CapabilitySlot::Telemetry,
descriptor_path: "greentic.telemetry.stdout",
version_req: "^0.1.0",
},
BuiltinHandler {
slot: CapabilitySlot::Sessions,
descriptor_path: "greentic.sessions.in-memory",
version_req: "^0.1.0",
},
BuiltinHandler {
slot: CapabilitySlot::State,
descriptor_path: "greentic.state.in-memory",
version_req: "^0.1.0",
},
];
#[cfg(test)]
mod tests {
use super::*;
use greentic_deploy_spec::PackDescriptor;
#[test]
fn builtin_table_matches_default_bindings() {
let mut handlers: Vec<(CapabilitySlot, &str)> = BUILTIN_HANDLERS
.iter()
.map(|h| (h.slot, h.descriptor_path))
.collect();
handlers.sort_by_key(|(_, path)| *path);
let mut defaults: Vec<(CapabilitySlot, String)> = crate::defaults::LOCAL_DEFAULT_BINDINGS
.iter()
.map(|(slot, descriptor)| {
let path = PackDescriptor::try_new(*descriptor)
.expect("default descriptor parses")
.path()
.to_string();
(*slot, path)
})
.collect();
defaults.sort_by(|a, b| a.1.cmp(&b.1));
let defaults_refs: Vec<(CapabilitySlot, &str)> =
defaults.iter().map(|(s, p)| (*s, p.as_str())).collect();
assert_eq!(handlers, defaults_refs);
}
#[test]
fn builtin_version_reqs_accept_their_default_binding_version() {
for (slot, descriptor) in crate::defaults::LOCAL_DEFAULT_BINDINGS {
let pd = PackDescriptor::try_new(*descriptor).expect("default descriptor parses");
let handler = BUILTIN_HANDLERS
.iter()
.find(|h| h.descriptor_path() == pd.path())
.unwrap_or_else(|| panic!("no built-in handler for {slot}"));
let req = handler.supported_versions();
assert!(
req.matches(&pd.version().0),
"{descriptor}: req {req} rejects its own default version"
);
}
}
}