Skip to content

Commit 3ef1e10

Browse files
author
Aaron Lehmann
committed
Invoke newt to build devcontainers with cloudbuild
1 parent 8ddcefb commit 3ef1e10

5 files changed

Lines changed: 23 additions & 97 deletions

File tree

example-usage/image-build/build-image.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ push_flag="${2:-false}"
1010
# If more than one plaftorm is specified, then push must be set.
1111
platforms="${3:-linux/amd64}"
1212

13-
devcontainer build --image-name $image_name --platform "$platforms" --push $push_flag --workspace-folder ../workspace
13+
../../devcontainer.js build --image-name $image_name --platform "$platforms" --push $push_flag --workspace-folder ../workspace
1414

15-
echo "\nImage ${image_name} built successfully!"
15+
echo "\nImage ${image_name} built successfully!"

src/spec-node/devContainers.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { LogLevel, LogDimensions, toErrorText, createCombinedLog, createTerminal
1717
import { dockerComposeCLIConfig } from './dockerCompose';
1818
import { Mount } from '../spec-configuration/containerFeaturesConfiguration';
1919
import { getPackageConfig, PackageConfiguration } from '../spec-utils/product';
20-
import { dockerBuildKitVersion } from '../spec-shutdown/dockerUtils';
2120

2221
export const experimentalImageMetadataDefault = true;
2322

@@ -142,13 +141,7 @@ export async function createDockerParams(options: ProvisionOptions, disposables:
142141
env: cliHost.env,
143142
output: common.output,
144143
}, dockerPath, dockerComposePath);
145-
const buildKitVersion = options.useBuildKit === 'never' ? null : (await dockerBuildKitVersion({
146-
cliHost,
147-
dockerCLI: dockerPath,
148-
dockerComposeCLI,
149-
env: cliHost.env,
150-
output
151-
}));
144+
const buildKitVersion = options.useBuildKit === 'never' ? null : 'v0.10.0';
152145
return {
153146
common,
154147
parsedAuthority,

src/spec-node/devContainersSpecCLI.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -397,15 +397,7 @@ async function doBuild({
397397

398398
// Build the base image and extend with features etc.
399399
let { updatedImageName } = await buildNamedImageAndExtend(params, configWithRaw as SubstitutedConfig<DevContainerFromDockerfileConfig>, additionalFeatures, false, imageNames);
400-
401-
if (imageNames) {
402-
if (!buildxPush && !buildxOutput) {
403-
await Promise.all(imageNames.map(imageName => dockerPtyCLI(params, 'tag', updatedImageName[0], imageName)));
404-
}
405-
imageNameResult = imageNames;
406-
} else {
407-
imageNameResult = updatedImageName;
408-
}
400+
imageNameResult = updatedImageName;
409401
} else if ('dockerComposeFile' in config) {
410402

411403
if (buildxPlatform || buildxPush) {

src/spec-node/singleContainer.ts

Lines changed: 15 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
*--------------------------------------------------------------------------------------------*/
55

66

7-
import { createContainerProperties, startEventSeen, ResolverResult, getTunnelInformation, getDockerfilePath, getDockerContextPath, DockerResolverParameters, isDockerFileConfig, uriToWSLFsPath, WorkspaceConfiguration, getFolderImageName, inspectDockerImage, logUMask, SubstitutedConfig, checkDockerSupportForGPU } from './utils';
7+
import { createContainerProperties, startEventSeen, ResolverResult, getTunnelInformation, getDockerfilePath, getDockerContextPath, DockerResolverParameters, isDockerFileConfig, uriToWSLFsPath, WorkspaceConfiguration, getFolderImageName, SubstitutedConfig, checkDockerSupportForGPU } from './utils';
88
import { ContainerProperties, setupInContainer, ResolverProgress, ResolverParameters } from '../spec-common/injectHeadless';
99
import { ContainerError, toErrorText } from '../spec-common/errors';
1010
import { ContainerDetails, listContainers, DockerCLIParameters, inspectContainers, dockerCLI, dockerPtyCLI, toPtyExecParameters, ImageDetails, toExecParameters } from '../spec-shutdown/dockerUtils';
1111
import { DevContainerConfig, DevContainerFromDockerfileConfig, DevContainerFromImageConfig } from '../spec-configuration/configuration';
1212
import { LogLevel, Log, makeLog } from '../spec-utils/log';
13-
import { extendImage, getExtendImageBuildInfo, updateRemoteUserUID } from './containerFeatures';
13+
import { extendImage, getExtendImageBuildInfo } from './containerFeatures';
1414
import { getDevcontainerMetadata, getImageBuildInfoFromDockerfile, getImageMetadataFromContainer, ImageMetadataEntry, mergeConfiguration, MergedDevContainerConfig } from './imageMetadata';
1515
import { ensureDockerfileHasFinalStageName } from './dockerfileUtils';
1616

@@ -40,24 +40,7 @@ export async function openDockerfileDevContainer(params: DockerResolverParameter
4040
const imageMetadata = getImageMetadataFromContainer(container, configWithRaw, undefined, idLabels, common.experimentalImageMetadata, common.output).config;
4141
mergedConfig = mergeConfiguration(config, imageMetadata);
4242
} else {
43-
const res = await buildNamedImageAndExtend(params, configWithRaw, additionalFeatures, true);
44-
const imageMetadata = res.imageMetadata.config;
45-
mergedConfig = mergeConfiguration(config, imageMetadata);
46-
const { containerUser } = mergedConfig;
47-
const updatedImageName = await updateRemoteUserUID(params, mergedConfig, res.updatedImageName[0], res.imageDetails, findUserArg(config.runArgs) || containerUser);
48-
49-
// collapsedFeaturesConfig = async () => res.collapsedFeaturesConfig;
50-
51-
try {
52-
await spawnDevContainer(params, config, mergedConfig, updatedImageName, idLabels, workspaceConfig.workspaceMount, res.imageDetails, containerUser, res.labels || {});
53-
} finally {
54-
// In 'finally' because 'docker run' can fail after creating the container.
55-
// Trying to get it here, so we can offer 'Rebuild Container' as an action later.
56-
container = await findDevContainer(params, idLabels);
57-
}
58-
if (!container) {
59-
return bailOut(common.output, 'Dev container not found.');
60-
}
43+
return bailOut(common.output, 'Code removed.');
6144
}
6245

6346
containerProperties = await createContainerProperties(params, container.Id, workspaceConfig.workspaceFolder, mergedConfig.remoteUser);
@@ -110,7 +93,7 @@ async function setupContainer(container: ContainerDetails, params: DockerResolve
11093
function getDefaultName(config: DevContainerFromDockerfileConfig | DevContainerFromImageConfig, params: DockerResolverParameters) {
11194
return 'image' in config ? config.image : getFolderImageName(params.common);
11295
}
113-
export async function buildNamedImageAndExtend(params: DockerResolverParameters, configWithRaw: SubstitutedConfig<DevContainerFromDockerfileConfig | DevContainerFromImageConfig>, additionalFeatures: Record<string, string | boolean | Record<string, string | boolean>>, canAddLabelsToContainer: boolean, argImageNames?: string[]): Promise<{ updatedImageName: string[]; imageMetadata: SubstitutedConfig<ImageMetadataEntry[]>; imageDetails: () => Promise<ImageDetails>; labels?: Record<string, string> }> {
96+
export async function buildNamedImageAndExtend(params: DockerResolverParameters, configWithRaw: SubstitutedConfig<DevContainerFromDockerfileConfig | DevContainerFromImageConfig>, additionalFeatures: Record<string, string | boolean | Record<string, string | boolean>>, canAddLabelsToContainer: boolean, argImageNames?: string[]): Promise<{ updatedImageName: string[]; imageMetadata: SubstitutedConfig<ImageMetadataEntry[]>; labels?: Record<string, string> }> {
11497
const { config } = configWithRaw;
11598
const imageNames = argImageNames ?? [getDefaultName(config, params)];
11699
params.common.progress(ResolverProgress.BuildingImage);
@@ -167,90 +150,46 @@ async function buildAndExtendImage(buildParams: DockerResolverParameters, config
167150
additionalBuildArgs.push('--build-context', `${buildContext}=${featureBuildInfo.buildKitContexts[buildContext]}`);
168151
}
169152
for (const buildArg in featureBuildInfo.buildArgs) {
170-
additionalBuildArgs.push('--build-arg', `${buildArg}=${featureBuildInfo.buildArgs[buildArg]}`);
153+
additionalBuildArgs.push('--param', `${buildArg}=${featureBuildInfo.buildArgs[buildArg]}`);
171154
}
172155
}
173156

174-
const args: string[] = [];
175-
if (!buildParams.buildKitVersion &&
176-
(buildParams.buildxPlatform || buildParams.buildxPush)) {
177-
throw new ContainerError({ description: '--platform or --push require BuildKit enabled.', data: { fileWithError: dockerfilePath } });
178-
}
179-
if (buildParams.buildKitVersion) {
180-
args.push('buildx', 'build');
181-
if (buildParams.buildxPlatform) {
182-
args.push('--platform', buildParams.buildxPlatform);
183-
}
184-
if (buildParams.buildxPush) {
185-
args.push('--push');
186-
} else {
187-
if (buildParams.buildxOutput) {
188-
args.push('--output', buildParams.buildxOutput);
189-
} else {
190-
args.push('--load'); // (short for --output=docker, i.e. load into normal 'docker images' collection)
191-
}
192-
}
193-
args.push('--build-arg', 'BUILDKIT_INLINE_CACHE=1');
194-
} else {
195-
args.push('build');
196-
}
197-
args.push('-f', finalDockerfilePath);
157+
const args: string[] = ['build'];
158+
args.push('--dockerfile', finalDockerfilePath);
198159

199-
baseImageNames.map(imageName => args.push('-t', imageName));
160+
baseImageNames.map(imageName => args.push('--image-name', imageName));
200161

201162
const target = extendImageBuildInfo?.featureBuildInfo ? extendImageBuildInfo.featureBuildInfo.overrideTarget : config.build?.target;
202163
if (target) {
203164
args.push('--target', target);
204165
}
205-
if (noCache) {
206-
args.push('--no-cache');
207-
// `docker build --pull` pulls local image: https://github.com/devcontainers/cli/issues/60
208-
if (buildParams.buildKitVersion || !extendImageBuildInfo) {
209-
args.push('--pull');
210-
}
211-
} else {
212-
const configCacheFrom = config.build?.cacheFrom;
213-
if (buildParams.additionalCacheFroms.length || (configCacheFrom && (configCacheFrom === 'string' || configCacheFrom.length))) {
214-
await logUMask(buildParams);
215-
}
216-
buildParams.additionalCacheFroms.forEach(cacheFrom => args.push('--cache-from', cacheFrom));
217-
if (config.build && config.build.cacheFrom) {
218-
if (typeof config.build.cacheFrom === 'string') {
219-
args.push('--cache-from', config.build.cacheFrom);
220-
} else {
221-
for (let index = 0; index < config.build.cacheFrom.length; index++) {
222-
const cacheFrom = config.build.cacheFrom[index];
223-
args.push('--cache-from', cacheFrom);
224-
}
225-
}
226-
}
166+
if (!noCache) {
167+
args.push('--cache');
227168
}
228169
const buildArgs = config.build?.args;
229170
if (buildArgs) {
230171
for (const key in buildArgs) {
231-
args.push('--build-arg', `${key}=${buildArgs[key]}`);
172+
args.push('--param', `${key}=${buildArgs[key]}`);
232173
}
233174
}
234175
args.push(...additionalBuildArgs);
235-
args.push(await uriToWSLFsPath(getDockerContextPath(cliHost, config), cliHost));
176+
args.push('--build-path', await uriToWSLFsPath(getDockerContextPath(cliHost, config), cliHost));
236177
try {
178+
buildParams.dockerCLI = 'newt';
237179
if (buildParams.isTTY) {
238180
const infoParams = { ...toPtyExecParameters(buildParams), output: makeLog(output, LogLevel.Info) };
239-
await dockerPtyCLI(infoParams, ...args);
181+
await dockerPtyCLI(infoParams, process.cwd(), ...args);
240182
} else {
241183
const infoParams = { ...toExecParameters(buildParams), output: makeLog(output, LogLevel.Info), print: 'continuous' as 'continuous' };
242-
await dockerCLI(infoParams, ...args);
184+
await dockerCLI(infoParams, process.cwd(), ...args);
243185
}
244186
} catch (err) {
245187
throw new ContainerError({ description: 'An error occurred building the image.', originalError: err, data: { fileWithError: dockerfilePath } });
246188
}
247189

248-
const imageDetails = () => inspectDockerImage(buildParams, baseImageNames[0], false);
249-
250190
return {
251191
updatedImageName: baseImageNames,
252192
imageMetadata: getDevcontainerMetadata(imageBuildInfo.metadata, configWithRaw, extendImageBuildInfo?.featuresConfig),
253-
imageDetails
254193
};
255194
}
256195

src/spec-shutdown/dockerUtils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,11 @@ export async function dockerBuildKitVersion(params: DockerCLIParameters | Partia
247247
}
248248
}
249249

250-
export async function dockerCLI(params: DockerCLIParameters | PartialExecParameters | DockerResolverParameters, ...args: string[]) {
250+
export async function dockerCLI(params: DockerCLIParameters | PartialExecParameters | DockerResolverParameters, cwd?: string, ...args: string[]) {
251251
const partial = toExecParameters(params);
252252
return runCommandNoPty({
253253
...partial,
254+
cwd: cwd,
254255
args: (partial.args || []).concat(args),
255256
});
256257
}
@@ -286,10 +287,11 @@ export async function isPodman(params: DockerCLIParameters | DockerResolverParam
286287
}
287288
}
288289

289-
export async function dockerPtyCLI(params: PartialPtyExecParameters | DockerResolverParameters | DockerCLIParameters, ...args: string[]) {
290+
export async function dockerPtyCLI(params: PartialPtyExecParameters | DockerResolverParameters | DockerCLIParameters, cwd?: string, ...args: string[]) {
290291
const partial = toPtyExecParameters(params);
291292
return runCommand({
292293
...partial,
294+
cwd: cwd,
293295
args: (partial.args || []).concat(args),
294296
});
295297
}

0 commit comments

Comments
 (0)