@@ -52,6 +52,25 @@ impl AppManifest {
52
52
}
53
53
Ok ( ( ) )
54
54
}
55
+
56
+ /// Whether any component in the application defines the given profile.
57
+ /// Not every component defines every profile, and components intentionally
58
+ /// fall back to the anonymouse profile if they are asked for a profile
59
+ /// they don't define. So this can be used to detect that a user might have
60
+ /// mistyped a profile (e.g. `spin up --profile deugb`).
61
+ pub fn ensure_profile ( & self , profile : Option < & str > ) -> anyhow:: Result < ( ) > {
62
+ let Some ( p) = profile else {
63
+ return Ok ( ( ) ) ;
64
+ } ;
65
+
66
+ let is_defined = self . components . values ( ) . any ( |c| c. profile . contains_key ( p) ) ;
67
+
68
+ if is_defined {
69
+ Ok ( ( ) )
70
+ } else {
71
+ Err ( anyhow ! ( "Profile {p} is not defined in this application" ) )
72
+ }
73
+ }
55
74
}
56
75
57
76
/// App details
@@ -397,31 +416,89 @@ pub struct Component {
397
416
pub dependencies : ComponentDependencies ,
398
417
/// TODO: profile docs
399
418
#[ serde( default , skip_serializing_if = "Map::is_empty" ) ]
400
- pub profile : Map < String , ComponentProfileUp > ,
419
+ pub profile : Map < String , ComponentProfileOverride > ,
401
420
}
402
421
403
- /// Customisations for running a Spin component in a non-default profile.
422
+ /// Customisations for a Spin component in a non-default profile.
404
423
#[ derive( Clone , Debug , Serialize , Deserialize , JsonSchema ) ]
405
424
#[ serde( deny_unknown_fields) ]
406
- pub struct ComponentProfileUp {
425
+ pub struct ComponentProfileOverride {
407
426
/// The file, package, or URL containing the component Wasm binary.
408
427
///
409
- /// Example: `source = "bin/cart.wasm"`
428
+ /// Example: `source = "bin/debug/ cart.wasm"`
410
429
///
411
430
/// Learn more: https://spinframework.dev/writing-apps#the-component-source
412
- pub source : ComponentSource ,
431
+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
432
+ pub source : Option < ComponentSource > ,
433
+
434
+ /// The command or commands for building the component in non-default profiles.
435
+ /// If a component has no special build instructions for a profile, the
436
+ /// default build command is used.
437
+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
438
+ pub build : Option < ComponentProfileBuildOverride > ,
439
+ }
440
+
441
+ /// Customisations for a Spin component build in a non-default profile.
442
+ #[ derive( Clone , Debug , Serialize , Deserialize , JsonSchema ) ]
443
+ #[ serde( deny_unknown_fields) ]
444
+ pub struct ComponentProfileBuildOverride {
445
+ /// The command or commands to build the component in a named profile. If multiple commands
446
+ /// are specified, they are run sequentially from left to right.
447
+ ///
448
+ /// Example: `build.command = "cargo build"`
449
+ ///
450
+ /// Learn more: https://spinframework.dev/build#setting-up-for-spin-build
451
+ pub command : super :: common:: Commands ,
413
452
}
414
453
415
454
impl Component {
416
- /// TODO: docs! docs! docs!
417
- pub fn source ( & self , profile : Option < impl AsRef < str > > ) -> ComponentSource {
418
- let Some ( profile) = profile. as_ref ( ) else {
419
- return self . source . clone ( ) ;
455
+ fn profile ( & self , profile : Option < impl AsRef < str > > ) -> Option < & ComponentProfileOverride > {
456
+ profile. and_then ( |p| self . profile . get ( p. as_ref ( ) ) )
457
+ }
458
+
459
+ /// The commands to execute for the build
460
+ pub fn build_commands ( & self , profile : Option < & str > ) -> Vec < & String > {
461
+ let profile_build = self . profile ( profile) . and_then ( |o| o. build . as_ref ( ) ) ;
462
+
463
+ match profile_build {
464
+ None => match & self . build {
465
+ Some ( b) => b. command . as_vec ( ) ,
466
+ None => vec ! [ ] ,
467
+ } ,
468
+ Some ( b) => b. command . as_vec ( ) ,
469
+ }
470
+ }
471
+
472
+ /// The build configuration for the component
473
+ pub fn build_config ( & self , profile : Option < impl AsRef < str > > ) -> Option < ComponentBuildConfig > {
474
+ let build_config = self . build . clone ( ) ;
475
+ let build_profile = self . profile ( profile) . and_then ( |o| o. build . as_ref ( ) ) ;
476
+
477
+ let Some ( build_profile) = build_profile else {
478
+ return build_config;
420
479
} ;
421
- let Some ( source) = self . profile . get ( profile. as_ref ( ) ) else {
422
- return self . source . clone ( ) ;
480
+
481
+ let Some ( mut build_config) = build_config else {
482
+ return Some ( ComponentBuildConfig {
483
+ command : build_profile. command . clone ( ) ,
484
+ workdir : None ,
485
+ watch : vec ! [ ] ,
486
+ } ) ;
423
487
} ;
424
- source. source . clone ( )
488
+
489
+ build_config. command = build_profile. command . clone ( ) ;
490
+
491
+ Some ( build_config)
492
+ }
493
+
494
+ /// TODO: docs! docs! docs!
495
+ pub fn source ( & self , profile : Option < impl AsRef < str > > ) -> & ComponentSource {
496
+ let profile_source = self . profile ( profile) . and_then ( |o| o. source . as_ref ( ) ) ;
497
+
498
+ match profile_source {
499
+ Some ( s) => s,
500
+ None => & self . source ,
501
+ }
425
502
}
426
503
}
427
504
0 commit comments