Skip to content

Commit 3b083d5

Browse files
feat: avoid pulling remote images when cached results are available
1 parent f12eb2f commit 3b083d5

File tree

1 file changed

+55
-21
lines changed

1 file changed

+55
-21
lines changed

lib/Lens.js

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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(/^(.+)@sha256:[a-f0-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

Comments
 (0)