@@ -14,6 +14,14 @@ pub struct OciLoader {
1414 working_dir : PathBuf ,
1515}
1616
17+ /// The artifact loaded by the `OciLoader`
18+ pub enum ExecutableArtifact {
19+ /// The OCI reference contained a Spin application
20+ Application ( LockedApp ) ,
21+ /// The OCI reference contained a Wasm package
22+ Package ( PathBuf ) ,
23+ }
24+
1725impl OciLoader {
1826 /// Creates a new OciLoader which builds temporary mount directory(s) in
1927 /// the given working_dir.
@@ -23,9 +31,13 @@ impl OciLoader {
2331 }
2432
2533 /// Pulls and loads an OCI Artifact and returns a LockedApp with the given OCI client and reference
26- pub async fn load_app ( & self , client : & mut Client , reference : & str ) -> Result < LockedApp > {
34+ pub async fn load_app (
35+ & self ,
36+ client : & mut Client ,
37+ reference : & str ,
38+ ) -> Result < ExecutableArtifact > {
2739 // Fetch app
28- client. pull ( reference) . await . with_context ( || {
40+ let manifest = client. pull ( reference) . await . with_context ( || {
2941 format ! ( "cannot pull Spin application from registry reference {reference:?}" )
3042 } ) ?;
3143
@@ -34,42 +46,58 @@ impl OciLoader {
3446 . lockfile_path ( & reference)
3547 . await
3648 . context ( "cannot get path to spin.lock" ) ?;
37- self . load_from_cache ( lockfile_path, reference, & client. cache )
49+ self . load_from_cache ( manifest , lockfile_path, reference, & client. cache )
3850 . await
3951 }
4052
4153 /// Loads an OCI Artifact from the given cache and returns a LockedApp with the given reference
4254 pub async fn load_from_cache (
4355 & self ,
56+ manifest : oci_distribution:: manifest:: OciImageManifest ,
4457 lockfile_path : PathBuf ,
4558 reference : & str ,
4659 cache : & Cache ,
47- ) -> std:: result:: Result < LockedApp , anyhow:: Error > {
60+ ) -> std:: result:: Result < ExecutableArtifact , anyhow:: Error > {
4861 let locked_content = tokio:: fs:: read ( & lockfile_path)
4962 . await
5063 . with_context ( || format ! ( "failed to read from {}" , quoted_path( & lockfile_path) ) ) ?;
51- let mut locked_app = LockedApp :: from_json ( & locked_content) . with_context ( || {
52- format ! (
53- "failed to decode locked app from {}" ,
54- quoted_path( & lockfile_path)
55- )
56- } ) ?;
57-
58- // Update origin metadata
59- let resolved_reference = Reference :: try_from ( reference) . context ( "invalid reference" ) ?;
60- let origin_uri = format ! ( "{ORIGIN_URL_SCHEME}:{resolved_reference}" ) ;
61- locked_app
62- . metadata
63- . insert ( "origin" . to_string ( ) , origin_uri. into ( ) ) ;
64-
65- for component in & mut locked_app. components {
66- self . resolve_component_content_refs ( component, cache)
67- . await
68- . with_context ( || {
69- format ! ( "failed to resolve content for component {:?}" , component. id)
70- } ) ?;
64+ let locked_json: serde_json:: Value = serde_json:: from_slice ( & locked_content)
65+ . with_context ( || format ! ( "OCI config {} is not JSON" , quoted_path( & lockfile_path) ) ) ?;
66+
67+ if locked_json. get ( "spin_lock_version" ) . is_some ( ) {
68+ let mut locked_app = LockedApp :: from_json ( & locked_content) . with_context ( || {
69+ format ! (
70+ "failed to decode locked app from {}" ,
71+ quoted_path( & lockfile_path)
72+ )
73+ } ) ?;
74+
75+ // Update origin metadata
76+ let resolved_reference = Reference :: try_from ( reference) . context ( "invalid reference" ) ?;
77+ let origin_uri = format ! ( "{ORIGIN_URL_SCHEME}:{resolved_reference}" ) ;
78+ locked_app
79+ . metadata
80+ . insert ( "origin" . to_string ( ) , origin_uri. into ( ) ) ;
81+
82+ for component in & mut locked_app. components {
83+ self . resolve_component_content_refs ( component, cache)
84+ . await
85+ . with_context ( || {
86+ format ! ( "failed to resolve content for component {:?}" , component. id)
87+ } ) ?;
88+ }
89+ Ok ( ExecutableArtifact :: Application ( locked_app) )
90+ } else {
91+ if manifest. layers . len ( ) != 1 {
92+ anyhow:: bail!(
93+ "expected single layer in OCI package, found {} layers" ,
94+ manifest. layers. len( )
95+ ) ;
96+ }
97+ let layer = & manifest. layers [ 0 ] ; // guaranteed safe by previous check
98+ let wasm_path = cache. wasm_path ( & layer. digest ) ;
99+ Ok ( ExecutableArtifact :: Package ( wasm_path) )
71100 }
72- Ok ( locked_app)
73101 }
74102
75103 async fn resolve_component_content_refs (
0 commit comments