@@ -16,31 +16,79 @@ use subprocess::{Exec, Redirection};
1616use crate :: manifest:: component_build_configs;
1717
1818/// If present, run the build command of each component.
19- pub async fn build ( manifest_file : & Path , component_ids : & [ String ] ) -> Result < ( ) > {
20- let ( components, manifest_err) =
21- component_build_configs ( manifest_file)
22- . await
23- . with_context ( || {
24- format ! (
25- "Cannot read manifest file from {}" ,
26- quoted_path( manifest_file)
27- )
28- } ) ?;
19+ pub async fn build (
20+ manifest_file : & Path ,
21+ component_ids : & [ String ] ,
22+ skip_target_checks : bool ,
23+ cache_root : Option < PathBuf > ,
24+ ) -> Result < ( ) > {
25+ let build_info = component_build_configs ( manifest_file)
26+ . await
27+ . with_context ( || {
28+ format ! (
29+ "Cannot read manifest file from {}" ,
30+ quoted_path( manifest_file)
31+ )
32+ } ) ?;
2933 let app_dir = parent_dir ( manifest_file) ?;
3034
31- let build_result = build_components ( component_ids, components, app_dir) ;
35+ let build_result = build_components ( component_ids, build_info . components ( ) , & app_dir) ;
3236
33- if let Some ( e) = manifest_err {
37+ // Emit any required warnings now, so that they don't bury any errors.
38+ if let Some ( e) = build_info. load_error ( ) {
39+ // The manifest had errors. We managed to attempt a build anyway, but we want to
40+ // let the user know about them.
3441 terminal:: warn!( "The manifest has errors not related to the Wasm component build. Error details:\n {e:#}" ) ;
42+ // Checking deployment targets requires a healthy manifest (because trigger types etc.),
43+ // if any of these were specified, warn they are being skipped.
44+ let should_have_checked_targets =
45+ !skip_target_checks && build_info. has_deployment_targets ( ) ;
46+ if should_have_checked_targets {
47+ terminal:: warn!(
48+ "The manifest error(s) prevented Spin from checking the deployment targets."
49+ ) ;
50+ }
51+ }
52+
53+ // If the build failed, exit with an error at this point.
54+ build_result?;
55+
56+ let Some ( manifest) = build_info. manifest ( ) else {
57+ // We can't proceed to checking (because that needs a full healthy manifest), and we've
58+ // already emitted any necessary warning, so quit.
59+ return Ok ( ( ) ) ;
60+ } ;
61+
62+ if !skip_target_checks {
63+ let application = spin_environments:: ApplicationToValidate :: new (
64+ manifest. clone ( ) ,
65+ manifest_file. parent ( ) . unwrap ( ) ,
66+ )
67+ . await ?;
68+ let errors = spin_environments:: validate_application_against_environment_ids (
69+ & application,
70+ build_info. deployment_targets ( ) ,
71+ cache_root. clone ( ) ,
72+ & app_dir,
73+ )
74+ . await ?;
75+
76+ for error in & errors {
77+ terminal:: error!( "{error}" ) ;
78+ }
79+
80+ if !errors. is_empty ( ) {
81+ anyhow:: bail!( "All components built successfully, but one or more was incompatible with one or more of the deployment targets." ) ;
82+ }
3583 }
3684
37- build_result
85+ Ok ( ( ) )
3886}
3987
4088fn build_components (
4189 component_ids : & [ String ] ,
4290 components : Vec < ComponentBuildInfo > ,
43- app_dir : PathBuf ,
91+ app_dir : & Path ,
4492) -> Result < ( ) , anyhow:: Error > {
4593 let components_to_build = if component_ids. is_empty ( ) {
4694 components
@@ -70,7 +118,7 @@ fn build_components(
70118
71119 components_to_build
72120 . into_iter ( )
73- . map ( |c| build_component ( c, & app_dir) )
121+ . map ( |c| build_component ( c, app_dir) )
74122 . collect :: < Result < Vec < _ > , _ > > ( ) ?;
75123
76124 terminal:: step!( "Finished" , "building all Spin components" ) ;
@@ -171,6 +219,6 @@ mod tests {
171219 #[ tokio:: test]
172220 async fn can_load_even_if_trigger_invalid ( ) {
173221 let bad_trigger_file = test_data_root ( ) . join ( "bad_trigger.toml" ) ;
174- build ( & bad_trigger_file, & [ ] ) . await . unwrap ( ) ;
222+ build ( & bad_trigger_file, & [ ] , true , None ) . await . unwrap ( ) ;
175223 }
176224}
0 commit comments