@@ -110,33 +110,46 @@ class Lens extends Configurable {
110110 }
111111 }
112112
113- async buildSpecForContainer ( inputTree , config ) {
114- const { container : containerQuery } = config ;
115-
116- // check if image exists locally first
117- let imageHash ;
113+ async getImageHash ( containerQuery ) {
114+ // Try local first (fastest)
118115 try {
119116 const inspectOutput = await Studio . execDocker ( [ 'inspect' , containerQuery ] ) ;
120117 const imageInfo = JSON . parse ( inspectOutput ) [ 0 ] ;
121- imageHash = imageInfo . Id ;
122- logger . info ( `found local image: ${ containerQuery } @ ${ imageHash } ` ) ;
118+ logger . info ( `found local image: ${ containerQuery } @ ${ imageInfo . Id } ` ) ;
119+ return { hash : imageInfo . Id , isLocal : true } ;
123120 } catch ( err ) {
124- // image doesn't exist locally or can't be inspected, try pulling
125- logger . info ( `pulling image: ${ containerQuery } ` ) ;
126-
127- try {
128- await Studio . execDocker ( [ 'pull' , containerQuery ] , { $relayStdout : true } ) ;
129- const inspectOutput = await Studio . execDocker ( [ 'inspect' , containerQuery ] ) ;
130- const imageInfo = JSON . parse ( inspectOutput ) [ 0 ] ;
131- imageHash = imageInfo . Id ;
132- } catch ( err ) {
133- throw new Error ( `failed to pull container image ${ containerQuery } : ${ err . message } ` ) ;
134- }
121+ // Not found locally, try remote manifest
135122 }
136123
137- if ( ! imageHash ) {
138- throw new Error ( `failed to get hash for container image ${ containerQuery } ` ) ;
124+ // Try remote manifest (doesn't pull the image)
125+ try {
126+ logger . info ( `querying remote manifest for: ${ containerQuery } ` ) ;
127+ const manifestOutput = await Studio . execDocker ( [ 'manifest' , 'inspect' , containerQuery ] ) ;
128+ const manifest = JSON . parse ( manifestOutput ) ;
129+
130+ // Extract digest from manifest
131+ // For multi-arch images, manifest.config.digest contains the config digest
132+ // For single-arch images, we may need to look at the digest field
133+ const digest = manifest . config ?. digest || manifest . digest ;
134+
135+ if ( ! digest ) {
136+ throw new Error ( 'No digest found in manifest' ) ;
137+ }
138+
139+ // Ensure the digest is in the format sha256:...
140+ const imageHash = digest . startsWith ( 'sha256:' ) ? digest : `sha256:${ digest } ` ;
141+ logger . info ( `found remote image hash: ${ containerQuery } @${ imageHash } ` ) ;
142+ return { hash : imageHash , isLocal : false } ;
143+ } catch ( err ) {
144+ throw new Error ( `failed to get hash for container image ${ containerQuery } : ${ err . message } ` ) ;
139145 }
146+ }
147+
148+ async buildSpecForContainer ( inputTree , config ) {
149+ const { container : containerQuery } = config ;
150+
151+ // Get image hash without pulling
152+ const { hash : imageHash , isLocal } = await this . getImageHash ( containerQuery ) ;
140153
141154 // build spec
142155 const data = {
@@ -152,7 +165,8 @@ class Lens extends Configurable {
152165 return {
153166 ...await SpecObject . write ( this . workspace . getRepo ( ) , 'lens' , data ) ,
154167 data,
155- type : 'container'
168+ type : 'container' ,
169+ imageIsLocal : isLocal
156170 } ;
157171 }
158172
@@ -317,6 +331,26 @@ class Lens extends Configurable {
317331 }
318332 const [ , sha256Hash ] = containerMatch ;
319333
334+ // Ensure image is available locally
335+ try {
336+ await Studio . execDocker ( [ 'inspect' , sha256Hash ] ) ;
337+ } catch ( err ) {
338+ // Image not found locally, need to pull it
339+ // Extract the original container query from spec to pull by name:tag
340+ const containerQueryMatch = spec . container . match ( / ^ ( .+ ) @ s h a 2 5 6 : [ a - f 0 - 9 ] { 64 } $ / ) ;
341+ if ( containerQueryMatch ) {
342+ const containerQuery = containerQueryMatch [ 1 ] ;
343+ logger . info ( `pulling required image: ${ containerQuery } ` ) ;
344+ try {
345+ await Studio . execDocker ( [ 'pull' , containerQuery ] , { $relayStdout : true } ) ;
346+ } catch ( pullErr ) {
347+ throw new Error ( `failed to pull container image ${ containerQuery } : ${ pullErr . message } ` ) ;
348+ }
349+ } else {
350+ throw new Error ( `cannot extract container query from spec.container: ${ spec . container } ` ) ;
351+ }
352+ }
353+
320354 // create and start container
321355 const persistentDebugContainer = process . env . HOLO_DEBUG_PERSIST_CONTAINER ;
322356 let containerId ;
0 commit comments