1use std::collections::HashMap;
6use std::sync::Arc;
7use tropel_ext::registry::ExtensionRegistry;
8use tropel_sdk::scenario::Scenario;
9use tropel_sdk::traits::{Driver, InputAdapter};
10use tropel_sdk::{Result, TropelError};
11
12pub(crate) enum ResolvedInput {
13 Scenario(Arc<Scenario>, String),
23 Driver(Box<dyn Driver>),
24}
25
26pub(crate) fn resolve_input_or_driver(
27 input_path: &str,
28 format_hint: Option<&str>,
29 registry: &ExtensionRegistry,
30 base_env: &HashMap<String, String>,
31 pre_read: Option<&[u8]>,
32) -> Result<ResolvedInput> {
33 let input_p = std::path::Path::new(input_path);
34 let bytes: Vec<u8> = match pre_read {
39 Some(b) => b.to_vec(),
40 None => std::fs::read(input_path)
41 .map_err(|e| TropelError::Parse(format!("Failed to read '{}': {}", input_path, e)))?,
42 };
43
44 let driver: Option<Box<dyn Driver>> = if let Some(fmt) = format_hint {
46 registry.resolve_driver_by_id(fmt)
47 } else {
48 registry.resolve_driver(&bytes)
49 };
50
51 if let Some(driver) = driver {
52 tracing::info!(
53 "Input '{}' resolved by driver '{}'",
54 input_path,
55 driver.id()
56 );
57 return Ok(ResolvedInput::Driver(driver));
58 }
59
60 let adapter: Box<dyn InputAdapter> = if let Some(fmt) = format_hint {
62 registry.resolve_input_by_id(fmt).ok_or_else(|| {
63 let available = registry.list_inputs();
64 TropelError::Config(format!(
65 "Unknown input format '{}'. Available formats: {}",
66 fmt,
67 available.join(", ")
68 ))
69 })?
70 } else {
71 registry.resolve_input(&bytes).ok_or_else(|| {
72 let available = registry.list_inputs();
73 TropelError::Parse(format!(
74 "No input adapter recognized '{}'. Available adapters: {}",
75 input_path,
76 if available.is_empty() {
77 "(none registered — check build configuration)".to_string()
78 } else {
79 available.join(", ")
80 }
81 ))
82 })?
83 };
84
85 tracing::info!(
86 "Input '{}' resolved by adapter '{}'",
87 input_path,
88 adapter.id()
89 );
90
91 let format_id = adapter.id().to_string();
92 let mut scenario = adapter.parse_with_path(&bytes, Some(input_p))?;
93 for (key, val) in base_env {
94 scenario
95 .variables
96 .entry(key.clone())
97 .or_insert_with(|| serde_json::Value::String(val.clone()));
98 }
99
100 Ok(ResolvedInput::Scenario(Arc::new(scenario), format_id))
101}