@@ -4,32 +4,96 @@ use std::{collections::BTreeMap, path::Path};
4
4
5
5
use spin_manifest:: { schema:: v2, ManifestVersion } ;
6
6
7
- pub type DeploymentTarget = String ;
8
- pub type DeploymentTargets = Vec < DeploymentTarget > ;
7
+ pub enum ManifestBuildInfo {
8
+ Loadable {
9
+ components : Vec < ComponentBuildInfo > ,
10
+ deployment_targets : Vec < String > ,
11
+ manifest : spin_manifest:: schema:: v2:: AppManifest ,
12
+ } ,
13
+ Unloadable {
14
+ components : Vec < ComponentBuildInfo > ,
15
+ has_deployment_targets : bool ,
16
+ load_error : spin_manifest:: Error ,
17
+ } ,
18
+ }
19
+
20
+ impl ManifestBuildInfo {
21
+ pub fn components ( & self ) -> Vec < ComponentBuildInfo > {
22
+ match self {
23
+ Self :: Loadable { components, .. } => components. clone ( ) ,
24
+ Self :: Unloadable { components, .. } => components. clone ( ) ,
25
+ }
26
+ }
27
+
28
+ pub fn load_error ( & self ) -> Option < & spin_manifest:: Error > {
29
+ match self {
30
+ Self :: Loadable { .. } => None ,
31
+ Self :: Unloadable { load_error, .. } => Some ( load_error) ,
32
+ }
33
+ }
34
+
35
+ pub fn deployment_targets ( & self ) -> & [ String ] {
36
+ match self {
37
+ Self :: Loadable {
38
+ deployment_targets, ..
39
+ } => deployment_targets,
40
+ Self :: Unloadable { .. } => & [ ] ,
41
+ }
42
+ }
43
+
44
+ pub fn has_deployment_targets ( & self ) -> bool {
45
+ match self {
46
+ Self :: Loadable {
47
+ deployment_targets, ..
48
+ } => !deployment_targets. is_empty ( ) ,
49
+ Self :: Unloadable {
50
+ has_deployment_targets,
51
+ ..
52
+ } => * has_deployment_targets,
53
+ }
54
+ }
55
+
56
+ pub fn manifest ( & self ) -> Option < & spin_manifest:: schema:: v2:: AppManifest > {
57
+ match self {
58
+ Self :: Loadable { manifest, .. } => Some ( manifest) ,
59
+ Self :: Unloadable { .. } => None ,
60
+ }
61
+ }
62
+ }
9
63
10
64
/// Returns a map of component IDs to [`v2::ComponentBuildConfig`]s for the
11
65
/// given (v1 or v2) manifest path. If the manifest cannot be loaded, the
12
66
/// function attempts fallback: if fallback succeeds, result is Ok but the load error
13
67
/// is also returned via the second part of the return value tuple.
14
- pub async fn component_build_configs (
15
- manifest_file : impl AsRef < Path > ,
16
- ) -> Result < (
17
- Vec < ComponentBuildInfo > ,
18
- DeploymentTargets ,
19
- Result < spin_manifest:: schema:: v2:: AppManifest , spin_manifest:: Error > ,
20
- ) > {
68
+ pub async fn component_build_configs ( manifest_file : impl AsRef < Path > ) -> Result < ManifestBuildInfo > {
21
69
let manifest = spin_manifest:: manifest_from_file ( & manifest_file) ;
22
70
match manifest {
23
71
Ok ( mut manifest) => {
24
72
spin_manifest:: normalize:: normalize_manifest ( & mut manifest) ;
25
- let bc = build_configs_from_manifest ( & manifest) ;
26
- let dt = deployment_targets_from_manifest ( & manifest) ;
27
- Ok ( ( bc, dt, Ok ( manifest) ) )
73
+ let components = build_configs_from_manifest ( & manifest) ;
74
+ let deployment_targets = deployment_targets_from_manifest ( & manifest) ;
75
+ Ok ( ManifestBuildInfo :: Loadable {
76
+ components,
77
+ deployment_targets,
78
+ manifest,
79
+ } )
28
80
}
29
- Err ( e) => {
30
- let bc = fallback_load_build_configs ( & manifest_file) . await ?;
31
- let dt = fallback_load_deployment_targets ( & manifest_file) . await ?;
32
- Ok ( ( bc, dt, Err ( e) ) )
81
+ Err ( load_error) => {
82
+ // The manifest didn't load, but the problem might not be build-affecting.
83
+ // Try to fall back by parsing out only the bits we need. And if something
84
+ // goes wrong with the fallback, give up and return the original manifest load
85
+ // error.
86
+ let Ok ( components) = fallback_load_build_configs ( & manifest_file) . await else {
87
+ return Err ( load_error. into ( ) ) ;
88
+ } ;
89
+ let Ok ( has_deployment_targets) = has_deployment_targets ( & manifest_file) . await else {
90
+ return Err ( load_error. into ( ) ) ;
91
+ } ;
92
+ Ok ( ManifestBuildInfo :: Unloadable {
93
+ components,
94
+ has_deployment_targets,
95
+ load_error,
96
+ } )
33
97
}
34
98
}
35
99
}
@@ -49,7 +113,7 @@ fn build_configs_from_manifest(
49
113
50
114
fn deployment_targets_from_manifest (
51
115
manifest : & spin_manifest:: schema:: v2:: AppManifest ,
52
- ) -> DeploymentTargets {
116
+ ) -> Vec < String > {
53
117
manifest. application . targets . clone ( )
54
118
}
55
119
@@ -75,31 +139,23 @@ async fn fallback_load_build_configs(
75
139
} )
76
140
}
77
141
78
- async fn fallback_load_deployment_targets (
79
- manifest_file : impl AsRef < Path > ,
80
- ) -> Result < DeploymentTargets > {
142
+ async fn has_deployment_targets ( manifest_file : impl AsRef < Path > ) -> Result < bool > {
81
143
let manifest_text = tokio:: fs:: read_to_string ( manifest_file) . await ?;
82
144
Ok ( match ManifestVersion :: detect ( & manifest_text) ? {
83
- ManifestVersion :: V1 => Default :: default ( ) ,
145
+ ManifestVersion :: V1 => false ,
84
146
ManifestVersion :: V2 => {
85
147
let table: toml:: value:: Table = toml:: from_str ( & manifest_text) ?;
86
- let target_environments = table
148
+ table
87
149
. get ( "application" )
88
150
. and_then ( |a| a. as_table ( ) )
89
151
. and_then ( |t| t. get ( "targets" ) )
90
152
. and_then ( |arr| arr. as_array ( ) )
91
- . map ( |v| v. as_slice ( ) )
92
- . unwrap_or_default ( )
93
- . iter ( )
94
- . filter_map ( |t| t. as_str ( ) )
95
- . map ( |s| s. to_owned ( ) )
96
- . collect ( ) ;
97
- target_environments
153
+ . is_some_and ( |arr| !arr. is_empty ( ) )
98
154
}
99
155
} )
100
156
}
101
157
102
- #[ derive( Deserialize ) ]
158
+ #[ derive( Clone , Deserialize ) ]
103
159
pub struct ComponentBuildInfo {
104
160
#[ serde( default ) ]
105
161
pub id : String ,
0 commit comments