Skip to content

Commit 816226b

Browse files
committed
Interim commit for transfer
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
1 parent 654d07b commit 816226b

5 files changed

Lines changed: 161 additions & 135 deletions

File tree

crates/manifest/src/normalize.rs

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -63,51 +63,6 @@ fn normalize_inline_components(manifest: &mut AppManifest) {
6363
normalize_spec(spec, trigger_id, false);
6464
}
6565
}
66-
67-
// let component_specs = trigger
68-
// .component
69-
// .iter_mut()
70-
// .chain(
71-
// trigger
72-
// .components
73-
// .values_mut()
74-
// .flat_map(|specs| specs.0.iter_mut()),
75-
// )
76-
// .collect::<Vec<_>>();
77-
// let multiple_components = component_specs.len() > 1;
78-
79-
// for spec in component_specs {
80-
// if !matches!(spec, ComponentSpec::Inline(_)) {
81-
// continue;
82-
// };
83-
84-
// let inline_id = {
85-
// // Try a "natural" component ID...
86-
// let mut id = KebabId::try_from(format!("{trigger_id}-component"));
87-
// // ...falling back to a counter-based component ID
88-
// if multiple_components
89-
// || id.is_err()
90-
// || components.contains_key(id.as_ref().unwrap())
91-
// {
92-
// id = Ok(loop {
93-
// let id = KebabId::try_from(format!("inline-component{counter}")).unwrap();
94-
// if !components.contains_key(&id) {
95-
// break id;
96-
// }
97-
// counter += 1;
98-
// });
99-
// }
100-
// id.unwrap()
101-
// };
102-
103-
// // Replace the inline component with a reference...
104-
// let inline_spec = std::mem::replace(spec, ComponentSpec::Reference(inline_id.clone()));
105-
// let ComponentSpec::Inline(component) = inline_spec else {
106-
// unreachable!();
107-
// };
108-
// // ...moving the inline component into the top-level components map.
109-
// components.insert(inline_id.clone(), *component);
110-
// }
11166
}
11267
}
11368

crates/manifest/src/schema/v2.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ pub struct Trigger {
132132
/// Learn more: https://spinframework.dev/triggers#triggers-and-components
133133
#[serde(default, skip_serializing_if = "Option::is_none")]
134134
pub component: Option<ComponentSpec>,
135-
/// Reserved for future use.
135+
/// Additional components used when the trigger occurs.
136+
/// The meaning of entries in this table is trigger-specific.
136137
///
137138
/// `components = { ... }`
138139
#[serde(default, skip_serializing_if = "Map::is_empty")]

crates/oci/src/client.rs

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -370,14 +370,26 @@ impl Client {
370370
let locked_url = write_locked_app(&locked, working_dir).await.unwrap();
371371

372372
for mut c in locked.components {
373-
let complicate =
374-
|data: Vec<u8>| compose_trigger_extras(&c, &locked_url, working_dir, data);
373+
// TODO: what if, instead of having a separate complicate that
374+
// called the trigger, we had the trigger do the full compose
375+
// (in the presence of extras)? The trigger already has logic
376+
// for that...
377+
let extras = c.metadata.get("trigger-extras").and_then(|e| e.as_object());
378+
379+
let composed = if extras.is_none_or(|e| e.is_empty()) {
380+
spin_compose::compose(&ComponentSourceLoaderFs, &c, async |a| Ok(a)).await?
381+
} else {
382+
compose_trigger_extras_2(&c, &locked_url, working_dir).await?
383+
};
375384

376-
let composed = spin_compose::compose(&ComponentSourceLoaderFs, &c, complicate)
377-
.await
378-
.with_context(|| {
379-
format!("failed to resolve dependencies for component {:?}", c.id)
380-
})?;
385+
// let complicate =
386+
// |data: Vec<u8>| compose_trigger_extras(&c, &locked_url, working_dir, data);
387+
388+
// let composed = spin_compose::compose(&ComponentSourceLoaderFs, &c, complicate)
389+
// .await
390+
// .with_context(|| {
391+
// format!("failed to resolve dependencies for component {:?}", c.id)
392+
// })?;
381393
let layer = ImageLayer::new(composed, WASM_LAYER_MEDIA_TYPE.to_string(), None);
382394
c.source.content = self.content_ref_for_layer(&layer);
383395
c.dependencies.clear();
@@ -938,11 +950,76 @@ fn add_inferred(map: &mut BTreeMap<String, String>, key: &str, value: Option<Str
938950
const SPIN_LOCKED_URL: &str = "SPIN_LOCKED_URL";
939951
const SPIN_WORKING_DIR: &str = "SPIN_WORKING_DIR";
940952

941-
async fn compose_trigger_extras(
953+
// async fn compose_trigger_extras(
954+
// c: &LockedComponent,
955+
// locked_url: &str,
956+
// working_dir: &Path,
957+
// data: Vec<u8>,
958+
// ) -> Result<Vec<u8>, spin_compose::ComposeError> {
959+
// use spin_compose::ComposeError;
960+
961+
// let Some(resolve_extras_using) = c
962+
// .metadata
963+
// .get("resolve-extras-using")
964+
// .and_then(|v| v.as_str())
965+
// else {
966+
// return Result::<_, ComposeError>::Ok(data);
967+
// };
968+
969+
// let resolver_subcmd = match resolve_extras_using {
970+
// "http" | "redis" => vec!["trigger".into(), resolve_extras_using.into()],
971+
// _ => vec![format!("trigger-{resolve_extras_using}")],
972+
// };
973+
974+
// let mut cmd = tokio::process::Command::new(std::env::current_exe().unwrap());
975+
// cmd.args(resolver_subcmd)
976+
// .args(["--resolve-extras-only", "--resolve-extras-component-id"])
977+
// .arg(&c.id)
978+
// // .stdin(std::process::Stdio::piped())
979+
// .stdout(std::process::Stdio::piped())
980+
// .stderr(std::process::Stdio::inherit())
981+
// .env("SPIN_PLUGINS_SUPPRESS_COMPATIBILITY_WARNINGS", "1")
982+
// .env(SPIN_LOCKED_URL, locked_url)
983+
// .env(SPIN_WORKING_DIR, working_dir);
984+
985+
// let child = cmd
986+
// .spawn()
987+
// .map_err(|e| ComposeError::PrepareError(e.into()))?;
988+
989+
// // use tokio::io::AsyncWriteExt;
990+
991+
// // let mut input = child.stdin.take().unwrap();
992+
// // input
993+
// // .write_all(&data)
994+
// // .await
995+
// // .map_err(|e| ComposeError::PrepareError(e.into()))?;
996+
// // input
997+
// // .flush()
998+
// // .await
999+
// // .map_err(|e| ComposeError::PrepareError(e.into()))?;
1000+
// // drop(input);
1001+
1002+
// let trigger_out = child
1003+
// .wait_with_output()
1004+
// .await
1005+
// .map_err(|e| ComposeError::PrepareError(e.into()))?;
1006+
1007+
// if !trigger_out.status.success() {
1008+
// return Err(ComposeError::PrepareError(anyhow::anyhow!(
1009+
// "unable to compose additional components for {} using `{}`",
1010+
// c.id,
1011+
// resolve_extras_using
1012+
// )));
1013+
// }
1014+
1015+
// let complicated = trigger_out.stdout;
1016+
// Ok(complicated)
1017+
// }
1018+
1019+
async fn compose_trigger_extras_2(
9421020
c: &LockedComponent,
9431021
locked_url: &str,
9441022
working_dir: &Path,
945-
data: Vec<u8>,
9461023
) -> Result<Vec<u8>, spin_compose::ComposeError> {
9471024
use spin_compose::ComposeError;
9481025

@@ -951,7 +1028,8 @@ async fn compose_trigger_extras(
9511028
.get("resolve-extras-using")
9521029
.and_then(|v| v.as_str())
9531030
else {
954-
return Result::<_, ComposeError>::Ok(data);
1031+
return spin_compose::compose(&ComponentSourceLoaderFs, &c, async |a| Ok(a)).await;
1032+
// return Result::<_, ComposeError>::Ok(data);
9551033
};
9561034

9571035
let resolver_subcmd = match resolve_extras_using {
@@ -961,32 +1039,18 @@ async fn compose_trigger_extras(
9611039

9621040
let mut cmd = tokio::process::Command::new(std::env::current_exe().unwrap());
9631041
cmd.args(resolver_subcmd)
964-
.args(["--resolve-extras-only", "--resolve-extras-component-id"])
1042+
.args(["--precompose-only", "--precompose-component-id"])
9651043
.arg(&c.id)
966-
.stdin(std::process::Stdio::piped())
9671044
.stdout(std::process::Stdio::piped())
9681045
.stderr(std::process::Stdio::inherit())
9691046
.env("SPIN_PLUGINS_SUPPRESS_COMPATIBILITY_WARNINGS", "1")
9701047
.env(SPIN_LOCKED_URL, locked_url)
9711048
.env(SPIN_WORKING_DIR, working_dir);
9721049

973-
let mut child = cmd
1050+
let child = cmd
9741051
.spawn()
9751052
.map_err(|e| ComposeError::PrepareError(e.into()))?;
9761053

977-
use tokio::io::AsyncWriteExt;
978-
979-
let mut input = child.stdin.take().unwrap();
980-
input
981-
.write_all(&data)
982-
.await
983-
.map_err(|e| ComposeError::PrepareError(e.into()))?;
984-
input
985-
.flush()
986-
.await
987-
.map_err(|e| ComposeError::PrepareError(e.into()))?;
988-
drop(input);
989-
9901054
let trigger_out = child
9911055
.wait_with_output()
9921056
.await

crates/trigger/src/cli.rs

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,10 @@ pub struct FactorsTriggerCommand<T: Trigger<B::Factors>, B: RuntimeFactorsBuilde
138138
#[clap(long = "launch-metadata-only", hide = true)]
139139
pub launch_metadata_only: bool,
140140

141-
#[clap(long = "resolve-extras-only", hide = true)]
142-
pub resolve_extras_only: bool,
143-
#[clap(long = "resolve-extras-component-id", hide = true)]
144-
pub resolve_extras_component_id: Option<String>,
141+
#[clap(long = "precompose-only", hide = true)]
142+
pub precompose_only: bool,
143+
#[clap(long = "precompose-component-id", hide = true)]
144+
pub precompose_component_id: Option<String>,
145145
}
146146

147147
#[cfg(feature = "experimental-wasm-features")]
@@ -219,54 +219,26 @@ impl<T: Trigger<B::Factors>, B: RuntimeFactorsBuilder> FactorsTriggerCommand<T,
219219
anyhow::bail!("This application requires the following features that are not available in this version of the '{}' trigger: {unmet}", T::TYPE);
220220
}
221221

222-
let trigger = T::new(self.trigger_args, &app)?;
223-
224-
if self.resolve_extras_only {
225-
use spin_factors_executor::Complicator;
226-
227-
let Some(resolve_extras_component_id) = self.resolve_extras_component_id.as_ref()
222+
if self.precompose_only {
223+
let Some(resolve_extras_component_id) = self.precompose_component_id.as_ref()
228224
else {
229225
anyhow::bail!("got --resolve-extras-only but no --resolve-extras-component-id");
230226
};
231227

232-
let complicator = T::complicator();
233228
let Some(component) = app.get_component(resolve_extras_component_id) else {
234229
anyhow::bail!("--resolve-extras-component-id: component does not exist");
235230
};
236-
let Some(extras) = component
237-
.locked
238-
.metadata
239-
.get("trigger-extras")
240-
.and_then(|v| v.as_object())
241-
else {
242-
anyhow::bail!("--resolve-extras-component-id: component has no extras");
243-
};
244-
245-
// let loader = spin_compose::ComponentSourceLoaderFs;
246231

247-
let complications = crate::loader::load_complications(
248-
&app,
249-
extras,
250-
&spin_compose::ComponentSourceLoaderFs,
251-
)
252-
.await?;
253-
254-
// let complicand = loader.load_component_source(&component.locked).await.unwrap();
255-
use std::io::Read;
256-
let mut complicand = Vec::with_capacity(16384);
257-
let read_count = std::io::stdin().read_to_end(&mut complicand)?;
258-
complicand.truncate(read_count);
259-
260-
let complicated = complicator
261-
.complicate(&complications, complicand)
262-
.await
263-
.unwrap();
232+
let loader = crate::loader::ComponentLoader::new();
233+
let composed = loader.load_full(&component, &T::complicator()).await?;
264234

265235
use std::io::Write;
266-
std::io::stdout().write_all(&complicated).unwrap();
236+
std::io::stdout().write_all(&composed).unwrap();
267237
return Ok(());
268238
}
269239

240+
let trigger = T::new(self.trigger_args, &app)?;
241+
270242
let mut builder: TriggerAppBuilder<T, B> = TriggerAppBuilder::new(trigger);
271243
let config = builder.engine_config();
272244

crates/trigger/src/loader.rs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -66,31 +66,8 @@ impl ComponentLoader {
6666
}
6767
}
6868
}
69-
}
70-
71-
#[async_trait]
72-
impl<T: RuntimeFactors, U> spin_factors_executor::ComponentLoader<T, U> for ComponentLoader {
73-
async fn load_component(
74-
&self,
75-
engine: &wasmtime::Engine,
76-
component: &AppComponent,
77-
complicator: &impl spin_factors_executor::Complicator,
78-
) -> anyhow::Result<Component> {
79-
let source = component
80-
.source()
81-
.content
82-
.source
83-
.as_ref()
84-
.context("LockedComponentSource missing source field")?;
85-
let path = parse_file_url(source)?;
86-
87-
#[cfg(feature = "unsafe-aot-compilation")]
88-
if self.aot_compilation_enabled {
89-
return self
90-
.load_precompiled_component(engine, &path)
91-
.with_context(|| format!("error deserializing component from {path:?}"));
92-
}
9369

70+
pub(crate) async fn load_full(&self, component: &AppComponent<'_>, complicator: &impl spin_factors_executor::Complicator) -> anyhow::Result<Vec<u8>> {
9471
let loader = ComponentSourceLoaderFs;
9572

9673
let empty: serde_json::Map<String, serde_json::Value> = Default::default();
@@ -119,6 +96,63 @@ impl<T: RuntimeFactors, U> spin_factors_executor::ComponentLoader<T, U> for Comp
11996
)
12097
})?;
12198

99+
Ok(composed)
100+
}
101+
}
102+
103+
#[async_trait]
104+
impl<T: RuntimeFactors, U> spin_factors_executor::ComponentLoader<T, U> for ComponentLoader {
105+
async fn load_component(
106+
&self,
107+
engine: &wasmtime::Engine,
108+
component: &AppComponent,
109+
complicator: &impl spin_factors_executor::Complicator,
110+
) -> anyhow::Result<Component> {
111+
let source = component
112+
.source()
113+
.content
114+
.source
115+
.as_ref()
116+
.context("LockedComponentSource missing source field")?;
117+
let path = parse_file_url(source)?;
118+
119+
#[cfg(feature = "unsafe-aot-compilation")]
120+
if self.aot_compilation_enabled {
121+
return self
122+
.load_precompiled_component(engine, &path)
123+
.with_context(|| format!("error deserializing component from {path:?}"));
124+
}
125+
126+
let composed = self.load_full(component, complicator).await?;
127+
128+
// let loader = ComponentSourceLoaderFs;
129+
130+
// let empty: serde_json::Map<String, serde_json::Value> = Default::default();
131+
// let extras = component
132+
// .locked
133+
// .metadata
134+
// .get("trigger-extras")
135+
// .and_then(|v| v.as_object())
136+
// .unwrap_or(&empty);
137+
138+
// let complications = load_complications(component.app, extras, &loader).await?;
139+
140+
// let complicate = async |c: Vec<u8>| {
141+
// complicator
142+
// .complicate(&complications, c)
143+
// .await
144+
// .map_err(spin_compose::ComposeError::PrepareError)
145+
// };
146+
147+
// let composed = spin_compose::compose(&loader, component.locked, complicate)
148+
// .await
149+
// .with_context(|| {
150+
// format!(
151+
// "failed to resolve dependencies for component {:?}",
152+
// component.locked.id
153+
// )
154+
// })?;
155+
122156
spin_core::Component::new(engine, composed)
123157
.with_context(|| format!("failed to compile component from {}", quoted_path(&path)))
124158
}

0 commit comments

Comments
 (0)