Skip to content

Commit d840496

Browse files
committed
Consider dependencies during target validation
Signed-off-by: itowlson <[email protected]>
1 parent 1bb5ec0 commit d840496

File tree

8 files changed

+309
-105
lines changed

8 files changed

+309
-105
lines changed

Cargo.lock

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/compose/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ async-trait = "0.1"
1414
indexmap = "2.2.6"
1515
semver = "1"
1616
spin-app = { path = "../app" }
17+
spin-common = { path = "../common" }
1718
spin-componentize = { workspace = true }
1819
spin-serde = { path = "../serde" }
1920
thiserror = "1"

crates/compose/src/lib.rs

+68-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::Context;
22
use indexmap::IndexMap;
33
use semver::Version;
4-
use spin_app::locked::{self, InheritConfiguration, LockedComponent, LockedComponentDependency};
4+
use spin_app::locked::InheritConfiguration as LockedInheritConfiguration;
55
use spin_serde::{DependencyName, KebabId};
66
use std::collections::BTreeMap;
77
use thiserror::Error;
@@ -28,18 +28,68 @@ use wac_graph::{CompositionGraph, NodeId};
2828
/// composition graph into a byte array and return it.
2929
pub async fn compose<'a, L: ComponentSourceLoader>(
3030
loader: &'a L,
31-
component: &LockedComponent,
31+
component: &L::Component,
3232
) -> Result<Vec<u8>, ComposeError> {
3333
Composer::new(loader).compose(component).await
3434
}
3535

36+
#[async_trait::async_trait]
37+
pub trait DependencyLike {
38+
fn inherit(&self) -> InheritConfiguration;
39+
fn export(&self) -> &Option<String>;
40+
}
41+
42+
pub enum InheritConfiguration {
43+
All,
44+
Some(Vec<String>),
45+
}
46+
47+
#[async_trait::async_trait]
48+
pub trait ComponentLike {
49+
type Dependency: DependencyLike;
50+
51+
fn dependencies(
52+
&self,
53+
) -> impl std::iter::ExactSizeIterator<Item = (&DependencyName, &Self::Dependency)>;
54+
fn id(&self) -> &str;
55+
}
56+
57+
#[async_trait::async_trait]
58+
impl ComponentLike for spin_app::locked::LockedComponent {
59+
type Dependency = spin_app::locked::LockedComponentDependency;
60+
61+
fn dependencies(
62+
&self,
63+
) -> impl std::iter::ExactSizeIterator<Item = (&DependencyName, &Self::Dependency)> {
64+
self.dependencies.iter()
65+
}
66+
67+
fn id(&self) -> &str {
68+
&self.id
69+
}
70+
}
71+
72+
#[async_trait::async_trait]
73+
impl DependencyLike for spin_app::locked::LockedComponentDependency {
74+
fn inherit(&self) -> InheritConfiguration {
75+
match &self.inherit {
76+
LockedInheritConfiguration::All => InheritConfiguration::All,
77+
LockedInheritConfiguration::Some(cfgs) => InheritConfiguration::Some(cfgs.clone()),
78+
}
79+
}
80+
81+
fn export(&self) -> &Option<String> {
82+
&self.export
83+
}
84+
}
85+
3686
/// This trait is used to load component source code from a locked component source across various embdeddings.
3787
#[async_trait::async_trait]
3888
pub trait ComponentSourceLoader {
39-
async fn load_component_source(
40-
&self,
41-
source: &locked::LockedComponentSource,
42-
) -> anyhow::Result<Vec<u8>>;
89+
type Component: ComponentLike<Dependency = Self::Dependency>;
90+
type Dependency: DependencyLike;
91+
async fn load_component_source(&self, source: &Self::Component) -> anyhow::Result<Vec<u8>>;
92+
async fn load_dependency_source(&self, source: &Self::Dependency) -> anyhow::Result<Vec<u8>>;
4393
}
4494

4595
/// Represents an error that can occur when composing dependencies.
@@ -98,19 +148,19 @@ struct Composer<'a, L> {
98148
}
99149

100150
impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
101-
async fn compose(mut self, component: &LockedComponent) -> Result<Vec<u8>, ComposeError> {
151+
async fn compose(mut self, component: &L::Component) -> Result<Vec<u8>, ComposeError> {
102152
let source = self
103153
.loader
104-
.load_component_source(&component.source)
154+
.load_component_source(component)
105155
.await
106156
.map_err(ComposeError::PrepareError)?;
107157

108-
if component.dependencies.is_empty() {
158+
if component.dependencies().len() == 0 {
109159
return Ok(source);
110160
}
111161

112162
let (world_id, instantiation_id) = self
113-
.register_package(&component.id, None, source)
163+
.register_package(component.id(), None, source)
114164
.map_err(ComposeError::PrepareError)?;
115165

116166
let prepared = self.prepare_dependencies(world_id, component).await?;
@@ -150,15 +200,15 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
150200
async fn prepare_dependencies(
151201
&mut self,
152202
world_id: WorldId,
153-
component: &LockedComponent,
203+
component: &L::Component,
154204
) -> Result<IndexMap<String, DependencyInfo>, ComposeError> {
155205
let imports = self.graph.types()[world_id].imports.clone();
156206

157207
let import_keys = imports.keys().cloned().collect::<Vec<_>>();
158208

159209
let mut mappings: BTreeMap<String, Vec<DependencyInfo>> = BTreeMap::new();
160210

161-
for (dependency_name, dependency) in &component.dependencies {
211+
for (dependency_name, dependency) in component.dependencies() {
162212
let mut matched = Vec::new();
163213

164214
for import_name in &import_keys {
@@ -171,7 +221,7 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
171221

172222
if matched.is_empty() {
173223
return Err(ComposeError::UnmatchedDependencyName {
174-
component_id: component.id.clone(),
224+
component_id: component.id().to_owned(),
175225
dependency_name: dependency_name.clone(),
176226
});
177227
}
@@ -195,7 +245,7 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
195245

196246
if !conflicts.is_empty() {
197247
return Err(ComposeError::DependencyConflicts {
198-
component_id: component.id.clone(),
248+
component_id: component.id().to_owned(),
199249
conflicts: conflicts
200250
.into_iter()
201251
.map(|(import_name, infos)| {
@@ -300,19 +350,16 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
300350
async fn register_dependency(
301351
&mut self,
302352
dependency_name: DependencyName,
303-
dependency: &LockedComponentDependency,
353+
dependency: &L::Dependency,
304354
) -> anyhow::Result<DependencyInfo> {
305-
let mut dependency_source = self
306-
.loader
307-
.load_component_source(&dependency.source)
308-
.await?;
355+
let mut dependency_source = self.loader.load_dependency_source(dependency).await?;
309356

310357
let package_name = match &dependency_name {
311358
DependencyName::Package(name) => name.package.to_string(),
312359
DependencyName::Plain(name) => name.to_string(),
313360
};
314361

315-
match &dependency.inherit {
362+
match dependency.inherit() {
316363
InheritConfiguration::Some(configurations) => {
317364
if configurations.is_empty() {
318365
// Configuration inheritance is disabled, apply deny_all adapter
@@ -333,7 +380,7 @@ impl<'a, L: ComponentSourceLoader> Composer<'a, L> {
333380
manifest_name: dependency_name,
334381
instantiation_id,
335382
world_id,
336-
export_name: dependency.export.clone(),
383+
export_name: dependency.export().clone(),
337384
})
338385
}
339386

crates/environments/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = { workspace = true }
66

77
[dependencies]
88
anyhow = { workspace = true }
9+
async-trait = "0.1"
910
futures = "0.3"
1011
indexmap = "2.2.6"
1112
miette = "7.2.0"
@@ -15,8 +16,11 @@ serde = { version = "1.0", features = ["derive"] }
1516
serde_json = "1.0"
1617
spin-common = { path = "../common" }
1718
spin-componentize = { path = "../componentize" }
19+
spin-compose = { path = "../compose" }
1820
spin-loader = { path = "../loader" }
1921
spin-manifest = { path = "../manifest" }
22+
spin-serde = { path = "../serde" }
23+
tokio = { version = "1.23", features = ["fs"] }
2024
tracing = { workspace = true }
2125
wac-parser = "0.6.0"
2226
wac-resolver = "0.6.0"

0 commit comments

Comments
 (0)