@@ -8,15 +8,28 @@ use wasm_pkg_loader::PackageRef;
88struct TargetWorld {
99 wit_package : PackageRef ,
1010 package_ver : String , // TODO: tidy to semver::Version
11- world_name : String ,
11+ world_name : WorldNames ,
12+ }
13+
14+ #[ derive( Debug , Eq , Hash , PartialEq , serde:: Deserialize ) ]
15+ #[ serde( untagged) ]
16+ enum WorldNames {
17+ Exactly ( String ) ,
18+ AnyOf ( Vec < String > ) ,
1219}
1320
1421impl TargetWorld {
15- fn versioned_name ( & self ) -> String {
16- format ! (
17- "{}/{}@{}" ,
18- self . wit_package, self . world_name, self . package_ver
19- )
22+ fn versioned_name ( & self , world_name : & str ) -> String {
23+ format ! ( "{}/{}@{}" , self . wit_package, world_name, self . package_ver)
24+ }
25+
26+ fn versioned_names ( & self ) -> Vec < String > {
27+ match & self . world_name {
28+ WorldNames :: Exactly ( name) => vec ! [ self . versioned_name( name) ] ,
29+ WorldNames :: AnyOf ( names) => {
30+ names. iter ( ) . map ( |name| self . versioned_name ( name) ) . collect ( )
31+ }
32+ }
2033 }
2134}
2235
@@ -59,22 +72,20 @@ fn component_source<'a>(
5972 . component
6073 . as_ref ( )
6174 . ok_or_else ( || anyhow ! ( "No component specified for trigger {}" , trigger. id) ) ?;
62- let ( id, csrc ) = match component_spec {
75+ let ( id, source ) = match component_spec {
6376 spin_manifest:: schema:: v2:: ComponentSpec :: Inline ( c) => ( trigger. id . as_str ( ) , & c. source ) ,
64- spin_manifest:: schema:: v2:: ComponentSpec :: Reference ( r) => (
65- r. as_ref ( ) ,
66- & app. components
67- . get ( r)
68- . ok_or_else ( || {
69- anyhow ! (
70- "Component {r} specified for trigger {} does not exist" ,
71- trigger. id
72- )
73- } ) ?
74- . source ,
75- ) ,
77+ spin_manifest:: schema:: v2:: ComponentSpec :: Reference ( r) => {
78+ let id = r. as_ref ( ) ;
79+ let Some ( component) = app. components . get ( r) else {
80+ anyhow:: bail!(
81+ "Component {id} specified for trigger {} does not exist" ,
82+ trigger. id
83+ ) ;
84+ } ;
85+ ( id, & component. source )
86+ }
7687 } ;
77- Ok ( ComponentToValidate { id, source : csrc } )
88+ Ok ( ComponentToValidate { id, source } )
7889}
7990
8091pub async fn validate_application_against_environment_ids (
@@ -180,32 +191,28 @@ async fn validate_component_against_environments(
180191 . map ( |w| ( e. name . as_str ( ) , w) )
181192 } )
182193 . collect :: < Result < std:: collections:: HashSet < _ > , _ > > ( ) ?;
183- validate_file_against_worlds ( worlds. into_iter ( ) , component, resolution_context) . await ?;
194+ validate_component_against_worlds ( worlds. into_iter ( ) , component, resolution_context) . await ?;
184195 Ok ( ( ) )
185196}
186197
187198impl ResolutionContext {
188- async fn load_wasm (
189- & self ,
190- source : & spin_manifest:: schema:: v2:: ComponentSource ,
191- ) -> anyhow:: Result < Vec < u8 > > {
192- if let spin_manifest:: schema:: v2:: ComponentSource :: Local ( path) = source {
193- let wasm_file = self . base_dir . join ( path) ;
194- Ok ( std:: fs:: read ( & wasm_file)
195- . with_context ( || format ! ( "Can't read Wasm file {}" , quoted_path( wasm_file) ) ) ?)
196- } else {
197- anyhow:: bail!( "can't do non-local component sources yet" ) ;
198- }
199+ async fn load_wasm ( & self , component : & ComponentToValidate < ' _ > ) -> anyhow:: Result < Vec < u8 > > {
200+ let loader = spin_loader:: WasmLoader :: new ( self . base_dir . clone ( ) , None , None ) . await ?;
201+ let wasm_file = loader
202+ . load_component_source ( component. id , component. source )
203+ . await ?;
204+ std:: fs:: read ( & wasm_file)
205+ . with_context ( || format ! ( "Can't read Wasm file {}" , quoted_path( wasm_file) ) )
199206 }
200207}
201208
202- async fn validate_file_against_worlds (
209+ async fn validate_component_against_worlds (
203210 target_worlds : impl Iterator < Item = ( & str , & TargetWorld ) > ,
204211 component : & ComponentToValidate < ' _ > ,
205212 resolution_context : & ResolutionContext ,
206213) -> anyhow:: Result < ( ) > {
207214 let raw_wasm = resolution_context
208- . load_wasm ( component. source )
215+ . load_wasm ( component)
209216 . await
210217 . with_context ( || format ! ( "Couldn't read Wasm {}" , component. source_description( ) ) ) ?;
211218 // FUTURE: take in manifest composition as well
@@ -218,14 +225,8 @@ async fn validate_file_against_worlds(
218225 } ) ?;
219226
220227 for ( env_name, target_world) in target_worlds {
221- validate_wasm_against_world ( env_name, target_world, component, cooked_wasm. as_ref ( ) )
228+ validate_wasm_against_any_world ( env_name, target_world, component, cooked_wasm. as_ref ( ) )
222229 . await ?;
223- tracing:: info!(
224- "Validated component {} {} against target world {}" ,
225- component. id,
226- component. source_description( ) ,
227- target_world. versioned_name( )
228- ) ;
229230 }
230231
231232 tracing:: info!(
@@ -236,13 +237,48 @@ async fn validate_file_against_worlds(
236237 Ok ( ( ) )
237238}
238239
239- async fn validate_wasm_against_world (
240+ async fn validate_wasm_against_any_world (
240241 env_name : & str ,
241242 target_world : & TargetWorld ,
242243 component : & ComponentToValidate < ' _ > ,
243244 wasm : & [ u8 ] ,
244245) -> anyhow:: Result < ( ) > {
245- let target_str = target_world. versioned_name ( ) ;
246+ let mut result = Ok ( ( ) ) ;
247+ for target_str in target_world. versioned_names ( ) {
248+ tracing:: info!(
249+ "Trying component {} {} against target world {target_str}" ,
250+ component. id,
251+ component. source_description( ) ,
252+ ) ;
253+ match validate_wasm_against_world ( env_name, & target_str, component, wasm) . await {
254+ Ok ( ( ) ) => {
255+ tracing:: info!(
256+ "Validated component {} {} against target world {target_str}" ,
257+ component. id,
258+ component. source_description( ) ,
259+ ) ;
260+ return Ok ( ( ) ) ;
261+ }
262+ Err ( e) => {
263+ // Record the error, but continue in case a different world succeeds
264+ tracing:: info!(
265+ "Rejecting component {} {} for target world {target_str} because {e:?}" ,
266+ component. id,
267+ component. source_description( ) ,
268+ ) ;
269+ result = Err ( e) ;
270+ }
271+ }
272+ }
273+ result
274+ }
275+
276+ async fn validate_wasm_against_world (
277+ env_name : & str ,
278+ target_str : & str ,
279+ component : & ComponentToValidate < ' _ > ,
280+ wasm : & [ u8 ] ,
281+ ) -> anyhow:: Result < ( ) > {
246282 let comp_name = "root:component" ;
247283
248284 let wac_text = format ! (
@@ -266,7 +302,7 @@ async fn validate_wasm_against_world(
266302 . await
267303 . context ( "reg_resolver.resolve failed" ) ?;
268304
269- packages. insert ( compkey, wasm. to_owned ( ) . to_vec ( ) ) ;
305+ packages. insert ( compkey, wasm. to_vec ( ) ) ;
270306
271307 match doc. resolve ( packages) {
272308 Ok ( _) => Ok ( ( ) ) ,
0 commit comments