11//! Spin lock file (spin.lock) serialization models.
22
3- use std:: path:: PathBuf ;
3+ use std:: { collections :: HashSet , path:: PathBuf } ;
44
5+ use itertools:: Itertools ;
56use serde:: { Deserialize , Serialize } ;
67use serde_json:: Value ;
78use spin_serde:: { DependencyName , FixedVersionBackwardCompatible } ;
@@ -25,21 +26,19 @@ pub const HOST_REQ_OPTIONAL: &str = "optional";
2526/// Indicates that a host feature is required.
2627pub const HOST_REQ_REQUIRED : & str = "required" ;
2728
29+ // TODO: it turns out that using an enum for this results in bad
30+ // errors by non-understanders (unknown variant rather than "I'm sorry
31+ // Dave I can't do that")
2832/// Identifies fields in the LockedApp that the host must process if present.
2933#[ derive( Clone , Debug , Serialize , Deserialize ) ]
3034#[ serde( rename_all = "snake_case" ) ]
3135pub enum MustUnderstand {
3236 /// If present in `must_understand`, the host must support all features
3337 /// in the app's `host_requirements` section.
3438 HostRequirements ,
35- }
36-
37- /// Features or capabilities the application requires the host to support.
38- #[ derive( Clone , Debug , Serialize , Deserialize ) ]
39- #[ serde( rename_all = "snake_case" ) ]
40- pub enum HostRequirement {
41- /// The application requires local service chaining.
42- LocalServiceChaining ,
39+ /// If present in `must_understand`, the host must support all features
40+ /// in components' `host_requirements` section.
41+ ComponentHostRequirements ,
4342}
4443
4544/// A LockedApp represents a "fully resolved" Spin application.
@@ -187,10 +186,26 @@ impl LockedApp {
187186 /// Checks that the application does not have any host requirements
188187 /// outside the supported set. The error case returns a comma-separated
189188 /// list of unmet requirements.
190- pub fn ensure_needs_only ( & self , supported : & [ & str ] ) -> Result < ( ) , String > {
191- let unmet_requirements = self
192- . host_requirements
193- . keys ( )
189+ pub fn ensure_needs_only ( & self , trigger_type : & str , supported : & [ & str ] ) -> Result < ( ) , String > {
190+ let app_host_requirements = self . host_requirements . keys ( ) ;
191+
192+ let component_ids = self
193+ . triggers
194+ . iter ( )
195+ . filter ( |t| t. trigger_type == trigger_type)
196+ . flat_map ( |t| t. trigger_config . get ( "component" ) )
197+ . filter_map ( |v| v. as_str ( ) )
198+ . collect :: < HashSet < _ > > ( ) ;
199+ let components = self
200+ . components
201+ . iter ( )
202+ . filter ( |c| component_ids. contains ( c. id . as_str ( ) ) ) ;
203+ let component_host_requirements = components. flat_map ( |c| c. host_requirements . keys ( ) ) ;
204+
205+ let all_host_requirements = app_host_requirements. chain ( component_host_requirements) ;
206+
207+ let unmet_requirements = all_host_requirements
208+ . unique ( )
194209 . filter ( |hr| !supported. contains ( & hr. as_str ( ) ) )
195210 . map ( |s| s. to_string ( ) )
196211 . collect :: < Vec < _ > > ( ) ;
@@ -225,6 +240,13 @@ pub struct LockedComponent {
225240 /// Component dependencies
226241 #[ serde( default , skip_serializing_if = "BTreeMap::is_empty" ) ]
227242 pub dependencies : BTreeMap < DependencyName , LockedComponentDependency > ,
243+ /// Host requirements
244+ #[ serde(
245+ default ,
246+ skip_serializing_if = "ValuesMap::is_empty" ,
247+ deserialize_with = "deserialize_host_requirements"
248+ ) ]
249+ pub host_requirements : ValuesMap ,
228250}
229251
230252/// A LockedDependency represents a "fully resolved" Spin component dependency.
0 commit comments