@@ -16,31 +16,79 @@ use subprocess::{Exec, Redirection};
16
16
use crate :: manifest:: component_build_configs;
17
17
18
18
/// 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
+ } ) ?;
29
33
let app_dir = parent_dir ( manifest_file) ?;
30
34
31
- let build_result = build_components ( component_ids, components, app_dir) ;
35
+ let build_result = build_components ( component_ids, build_info . components ( ) , & app_dir) ;
32
36
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.
34
41
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
+ }
35
83
}
36
84
37
- build_result
85
+ Ok ( ( ) )
38
86
}
39
87
40
88
fn build_components (
41
89
component_ids : & [ String ] ,
42
90
components : Vec < ComponentBuildInfo > ,
43
- app_dir : PathBuf ,
91
+ app_dir : & Path ,
44
92
) -> Result < ( ) , anyhow:: Error > {
45
93
let components_to_build = if component_ids. is_empty ( ) {
46
94
components
@@ -70,7 +118,7 @@ fn build_components(
70
118
71
119
components_to_build
72
120
. into_iter ( )
73
- . map ( |c| build_component ( c, & app_dir) )
121
+ . map ( |c| build_component ( c, app_dir) )
74
122
. collect :: < Result < Vec < _ > , _ > > ( ) ?;
75
123
76
124
terminal:: step!( "Finished" , "building all Spin components" ) ;
@@ -171,6 +219,6 @@ mod tests {
171
219
#[ tokio:: test]
172
220
async fn can_load_even_if_trigger_invalid ( ) {
173
221
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 ( ) ;
175
223
}
176
224
}
0 commit comments