@@ -4,32 +4,96 @@ use std::{collections::BTreeMap, path::Path};
44
55use spin_manifest:: { schema:: v2, ManifestVersion } ;
66
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+ }
963
1064/// Returns a map of component IDs to [`v2::ComponentBuildConfig`]s for the
1165/// given (v1 or v2) manifest path. If the manifest cannot be loaded, the
1266/// function attempts fallback: if fallback succeeds, result is Ok but the load error
1367/// 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 > {
2169 let manifest = spin_manifest:: manifest_from_file ( & manifest_file) ;
2270 match manifest {
2371 Ok ( mut manifest) => {
2472 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+ } )
2880 }
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+ } )
3397 }
3498 }
3599}
@@ -49,7 +113,7 @@ fn build_configs_from_manifest(
49113
50114fn deployment_targets_from_manifest (
51115 manifest : & spin_manifest:: schema:: v2:: AppManifest ,
52- ) -> DeploymentTargets {
116+ ) -> Vec < String > {
53117 manifest. application . targets . clone ( )
54118}
55119
@@ -75,31 +139,23 @@ async fn fallback_load_build_configs(
75139 } )
76140}
77141
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 > {
81143 let manifest_text = tokio:: fs:: read_to_string ( manifest_file) . await ?;
82144 Ok ( match ManifestVersion :: detect ( & manifest_text) ? {
83- ManifestVersion :: V1 => Default :: default ( ) ,
145+ ManifestVersion :: V1 => false ,
84146 ManifestVersion :: V2 => {
85147 let table: toml:: value:: Table = toml:: from_str ( & manifest_text) ?;
86- let target_environments = table
148+ table
87149 . get ( "application" )
88150 . and_then ( |a| a. as_table ( ) )
89151 . and_then ( |t| t. get ( "targets" ) )
90152 . 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 ( ) )
98154 }
99155 } )
100156}
101157
102- #[ derive( Deserialize ) ]
158+ #[ derive( Clone , Deserialize ) ]
103159pub struct ComponentBuildInfo {
104160 #[ serde( default ) ]
105161 pub id : String ,
0 commit comments