11mod app_source;
22
33use std:: {
4- collections:: HashSet ,
54 ffi:: OsString ,
65 fmt:: Debug ,
76 path:: { Path , PathBuf } ,
87} ;
98
10- use anyhow:: { anyhow, bail, ensure , Context , Result } ;
9+ use anyhow:: { anyhow, bail, Context , Result } ;
1110use clap:: { CommandFactory , Parser } ;
1211use reqwest:: Url ;
1312use spin_app:: locked:: LockedApp ;
@@ -18,7 +17,7 @@ use tempfile::TempDir;
1817
1918use crate :: opts:: * ;
2019
21- use self :: app_source:: AppSource ;
20+ use self :: app_source:: { AppSource , ResolvedAppSource } ;
2221
2322const APPLICATION_OPT : & str = "APPLICATION" ;
2423
@@ -124,7 +123,7 @@ impl UpCommand {
124123 }
125124
126125 async fn run_inner ( self ) -> Result < ( ) > {
127- let app_source = self . resolve_app_source ( ) ;
126+ let app_source = self . app_source ( ) ;
128127
129128 if app_source == AppSource :: None {
130129 if self . help {
@@ -148,20 +147,19 @@ impl UpCommand {
148147 . canonicalize ( )
149148 . context ( "Could not canonicalize working directory" ) ?;
150149
151- let mut locked_app = match & app_source {
152- AppSource :: None => bail ! ( "Internal error - should have shown help" ) ,
153- AppSource :: File ( path) => self . prepare_app_from_file ( path, & working_dir) . await ?,
154- AppSource :: OciRegistry ( oci) => self . prepare_app_from_oci ( oci, & working_dir) . await ?,
155- AppSource :: Unresolvable ( err) => bail ! ( "{err}" ) ,
156- } ;
150+ let resolved_app_source = self . resolve_app_source ( & app_source, & working_dir) . await ?;
157151
158- let trigger_cmd = trigger_command_from_locked_app ( & locked_app )
152+ let trigger_cmd = trigger_command_for_resolved_app_source ( & resolved_app_source )
159153 . with_context ( || format ! ( "Couldn't find trigger executor for {app_source}" ) ) ?;
160154
161155 if self . help {
162156 return self . run_trigger ( trigger_cmd, None ) . await ;
163157 }
164158
159+ let mut locked_app = self
160+ . load_resolved_app_source ( resolved_app_source, & working_dir)
161+ . await ?;
162+
165163 self . update_locked_app ( & mut locked_app) ;
166164
167165 let local_app_dir = app_source. local_app_dir ( ) . map ( Into :: into) ;
@@ -244,7 +242,7 @@ impl UpCommand {
244242 }
245243 }
246244
247- fn resolve_app_source ( & self ) -> AppSource {
245+ fn app_source ( & self ) -> AppSource {
248246 match ( & self . app_source , & self . file_source , & self . registry_source ) {
249247 ( None , None , None ) => self . default_manifest_or_none ( ) ,
250248 ( Some ( source) , None , None ) => AppSource :: infer_source ( source) ,
@@ -294,29 +292,54 @@ impl UpCommand {
294292 Ok ( locked_url)
295293 }
296294
297- async fn prepare_app_from_file (
295+ // Take the AppSource and do the minimum amount of work necessary to
296+ // be able to resolve the trigger executor.
297+ async fn resolve_app_source (
298298 & self ,
299- manifest_path : & Path ,
299+ app_source : & AppSource ,
300300 working_dir : & Path ,
301- ) -> Result < LockedApp > {
302- let files_mount_strategy = if self . direct_mounts {
303- FilesMountStrategy :: Direct
304- } else {
305- FilesMountStrategy :: Copy ( working_dir. join ( "assets" ) )
306- } ;
307- spin_loader:: from_file ( manifest_path, files_mount_strategy)
308- . await
309- . with_context ( || format ! ( "Failed to load manifest from {manifest_path:?}" ) )
301+ ) -> anyhow:: Result < ResolvedAppSource > {
302+ Ok ( match & app_source {
303+ AppSource :: File ( path) => ResolvedAppSource :: File {
304+ manifest_path : path. clone ( ) ,
305+ manifest : spin_manifest:: manifest_from_file ( path) ?,
306+ } ,
307+ // TODO: We could make the `--help` experience a little faster if
308+ // we could fetch just the locked app JSON at this stage.
309+ AppSource :: OciRegistry ( reference) => {
310+ let mut client = spin_oci:: Client :: new ( self . insecure , None )
311+ . await
312+ . context ( "cannot create registry client" ) ?;
313+
314+ let locked_app = OciLoader :: new ( working_dir)
315+ . load_app ( & mut client, reference)
316+ . await ?;
317+ ResolvedAppSource :: OciRegistry { locked_app }
318+ }
319+ AppSource :: Unresolvable ( err) => bail ! ( "{err}" ) ,
320+ AppSource :: None => bail ! ( "Internal error - should have shown help" ) ,
321+ } )
310322 }
311323
312- async fn prepare_app_from_oci ( & self , reference : & str , working_dir : & Path ) -> Result < LockedApp > {
313- let mut client = spin_oci:: Client :: new ( self . insecure , None )
314- . await
315- . context ( "cannot create registry client" ) ?;
316-
317- OciLoader :: new ( working_dir)
318- . load_app ( & mut client, reference)
319- . await
324+ // Finish preparing a ResolvedAppSource for execution.
325+ async fn load_resolved_app_source (
326+ & self ,
327+ resolved : ResolvedAppSource ,
328+ working_dir : & Path ,
329+ ) -> anyhow:: Result < LockedApp > {
330+ match resolved {
331+ ResolvedAppSource :: File { manifest_path, .. } => {
332+ let files_mount_strategy = if self . direct_mounts {
333+ FilesMountStrategy :: Direct
334+ } else {
335+ FilesMountStrategy :: Copy ( working_dir. join ( "assets" ) )
336+ } ;
337+ spin_loader:: from_file ( & manifest_path, files_mount_strategy)
338+ . await
339+ . with_context ( || format ! ( "Failed to load manifest from {manifest_path:?}" ) )
340+ }
341+ ResolvedAppSource :: OciRegistry { locked_app } => Ok ( locked_app) ,
342+ }
320343 }
321344
322345 fn update_locked_app ( & self , locked_app : & mut LockedApp ) {
@@ -395,17 +418,8 @@ fn trigger_command(trigger_type: &str) -> Vec<String> {
395418 vec ! [ "trigger" . to_owned( ) , trigger_type. to_owned( ) ]
396419}
397420
398- fn trigger_command_from_locked_app ( locked_app : & LockedApp ) -> Result < Vec < String > > {
399- let trigger_type = {
400- let types = locked_app
401- . triggers
402- . iter ( )
403- . map ( |t| t. trigger_type . as_str ( ) )
404- . collect :: < HashSet < _ > > ( ) ;
405- ensure ! ( !types. is_empty( ) , "no triggers in app" ) ;
406- ensure ! ( types. len( ) == 1 , "multiple trigger types not yet supported" ) ;
407- types. into_iter ( ) . next ( ) . unwrap ( )
408- } ;
421+ fn trigger_command_for_resolved_app_source ( resolved : & ResolvedAppSource ) -> Result < Vec < String > > {
422+ let trigger_type = resolved. trigger_type ( ) ?;
409423
410424 match trigger_type {
411425 "http" | "redis" => Ok ( trigger_command ( trigger_type) ) ,
@@ -436,7 +450,7 @@ mod test {
436450 app_source : Some ( file. clone ( ) ) ,
437451 ..Default :: default ( )
438452 }
439- . resolve_app_source ( ) ;
453+ . app_source ( ) ;
440454
441455 assert_eq ! ( AppSource :: File ( PathBuf :: from( file) ) , source) ;
442456 }
@@ -449,7 +463,7 @@ mod test {
449463 app_source : Some ( dir. clone ( ) ) ,
450464 ..Default :: default ( )
451465 }
452- . resolve_app_source ( ) ;
466+ . app_source ( ) ;
453467
454468 assert_eq ! (
455469 AppSource :: File ( PathBuf :: from( dir) . join( "spin.toml" ) ) ,
@@ -465,7 +479,7 @@ mod test {
465479 app_source : Some ( file) ,
466480 ..Default :: default ( )
467481 }
468- . resolve_app_source ( ) ;
482+ . app_source ( ) ;
469483
470484 assert ! ( matches!( source, AppSource :: Unresolvable ( _) ) ) ;
471485 }
@@ -478,7 +492,7 @@ mod test {
478492 app_source : Some ( file) ,
479493 ..Default :: default ( )
480494 }
481- . resolve_app_source ( ) ;
495+ . app_source ( ) ;
482496
483497 assert ! ( matches!( source, AppSource :: Unresolvable ( _) ) ) ;
484498 }
@@ -491,7 +505,7 @@ mod test {
491505 app_source : Some ( dir) ,
492506 ..Default :: default ( )
493507 }
494- . resolve_app_source ( ) ;
508+ . app_source ( ) ;
495509
496510 assert ! ( matches!( source, AppSource :: Unresolvable ( _) ) ) ;
497511 }
@@ -504,7 +518,7 @@ mod test {
504518 app_source : Some ( reference. clone ( ) ) ,
505519 ..Default :: default ( )
506520 }
507- . resolve_app_source ( ) ;
521+ . app_source ( ) ;
508522
509523 assert_eq ! ( AppSource :: OciRegistry ( reference) , source) ;
510524 }
@@ -518,7 +532,7 @@ mod test {
518532 app_source : Some ( reference. clone ( ) ) ,
519533 ..Default :: default ( )
520534 }
521- . resolve_app_source ( ) ;
535+ . app_source ( ) ;
522536
523537 assert_eq ! ( AppSource :: OciRegistry ( reference) , source) ;
524538 }
@@ -531,7 +545,7 @@ mod test {
531545 app_source : Some ( garbage) ,
532546 ..Default :: default ( )
533547 }
534- . resolve_app_source ( ) ;
548+ . app_source ( ) ;
535549
536550 // Honestly I feel Unresolvable might be a bit weak sauce for this case
537551 assert ! ( matches!( source, AppSource :: Unresolvable ( _) ) ) ;
0 commit comments