Skip to main content

camel_component_exec/
bundle.rs

1//! ExecBundle — ComponentBundle for `exec:`. Owns `[components.exec]`.
2//!
3//! Provides fail-fast `from_toml` deserialization + validation (ADR-0033) and
4//! registers the ExecComponent via the real `ComponentRegistrar` trait.
5
6use std::sync::Arc;
7
8use camel_component_api::{CamelError, ComponentBundle, ComponentRegistrar};
9
10use crate::ExecComponent;
11use crate::config::ExecGlobalConfig;
12
13/// Bundle for the `exec:` component scheme.
14#[derive(Debug)]
15pub struct ExecBundle {
16    pub(crate) config: ExecGlobalConfig,
17}
18
19impl ExecBundle {
20    /// Access the validated global config (public for integration tests).
21    pub fn config(&self) -> &ExecGlobalConfig {
22        &self.config
23    }
24}
25
26impl ComponentBundle for ExecBundle {
27    fn config_key() -> &'static str {
28        "exec"
29    }
30
31    fn from_toml(value: toml::Value) -> Result<Self, CamelError> {
32        let mut config: ExecGlobalConfig = value
33            .try_into()
34            .map_err(|e: toml::de::Error| CamelError::Config(e.to_string()))?;
35        // Fail-fast validation + canonical pinning, against CWD as workspace base.
36        config.validate(&std::env::current_dir()?)?;
37        Ok(Self { config })
38    }
39
40    fn register_all(self, ctx: &mut dyn ComponentRegistrar) {
41        let component = ExecComponent::new(self.config);
42        ctx.register_component_dyn(Arc::new(component));
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use std::sync::Arc;
49
50    use super::ExecBundle;
51    use camel_component_api::{Component, ComponentBundle, ComponentRegistrar};
52
53    #[allow(dead_code)]
54    struct TestRegistrar {
55        schemes: Vec<String>,
56    }
57
58    impl ComponentRegistrar for TestRegistrar {
59        fn register_component_dyn(&mut self, component: Arc<dyn Component>) {
60            self.schemes.push(component.scheme().to_string());
61        }
62    }
63
64    #[test]
65    fn from_toml_fails_when_no_profiles() {
66        let v: toml::Value = toml::from_str("workspace_root = \".\"\n").unwrap();
67        let err = ExecBundle::from_toml(v).unwrap_err();
68        assert!(err.to_string().contains("no profiles"));
69    }
70
71    #[test]
72    fn config_key_is_exec() {
73        assert_eq!(ExecBundle::config_key(), "exec");
74    }
75}