|
3 | 3 | * Licensed under the MIT License. See License.txt in the project root for license information. |
4 | 4 | *--------------------------------------------------------------------------------------------*/ |
5 | 5 |
|
6 | | -import { PlatformInfo } from '../spec-common/commonUtils'; |
| 6 | +import { GoARCH, GoOS, PlatformInfo } from '../spec-common/commonUtils'; |
7 | 7 | import { ContainerError } from '../spec-common/errors'; |
8 | 8 | import { LifecycleCommand, LifecycleHooksInstallMap } from '../spec-common/injectHeadless'; |
9 | 9 | import { DevContainerConfig, DevContainerConfigCommand, DevContainerFromDockerComposeConfig, DevContainerFromDockerfileConfig, DevContainerFromImageConfig, getDockerComposeFilePaths, getDockerfilePath, HostGPURequirements, HostRequirements, isDockerFileConfig, PortAttributes, UserEnvProbe } from '../spec-configuration/configuration'; |
@@ -395,21 +395,45 @@ export async function getImageBuildInfoFromImage(params: DockerResolverParameter |
395 | 395 | export async function getImageBuildInfoFromDockerfile(params: DockerResolverParameters | DockerCLIParameters, dockerfile: string, dockerBuildArgs: Record<string, string>, targetStage: string | undefined, substitute: SubstituteConfig) { |
396 | 396 | const { output } = 'output' in params ? params : params.common; |
397 | 397 | const omitSyntaxDirective = 'common' in params ? !!params.common.omitSyntaxDirective : false; |
398 | | - return internalGetImageBuildInfoFromDockerfile(imageName => inspectDockerImage(params, imageName, true), dockerfile, dockerBuildArgs, targetStage, substitute, output, omitSyntaxDirective, params.platformInfo); |
| 398 | + const buildxPlatform = 'common' in params ? params.common.buildxPlatform : undefined; |
| 399 | + const buildxPlatforms = buildxPlatform?.split(',').map(platform => { |
| 400 | + const slash1 = platform.indexOf('/'); |
| 401 | + const slash2 = platform.indexOf('/', slash1 + 1); |
| 402 | + // `--platform linux/amd64/v3` `--platform linux/arm64/v8` |
| 403 | + if (slash2 !== -1) { |
| 404 | + return { |
| 405 | + os: <GoOS>platform.slice(0, slash1), |
| 406 | + arch: <GoARCH>platform.slice(slash1 + 1, slash2), |
| 407 | + variant: platform.slice(slash2 + 1), |
| 408 | + }; |
| 409 | + } |
| 410 | + // `--platform linux/amd64` and `--platform linux/arm64` |
| 411 | + return { |
| 412 | + os: <GoOS>platform.slice(0, slash1), |
| 413 | + arch: <GoARCH>platform.slice(slash1 + 1), |
| 414 | + }; |
| 415 | + }) ?? [] satisfies PlatformInfo[]; |
| 416 | + return internalGetImageBuildInfoFromDockerfile(imageName => inspectDockerImage(params, imageName, true), dockerfile, dockerBuildArgs, targetStage, substitute, output, omitSyntaxDirective, params.platformInfo, buildxPlatforms); |
399 | 417 | } |
400 | 418 |
|
401 | | -export async function internalGetImageBuildInfoFromDockerfile(inspectDockerImage: (imageName: string) => Promise<ImageDetails>, dockerfileText: string, dockerBuildArgs: Record<string, string>, targetStage: string | undefined, substitute: SubstituteConfig, output: Log, omitSyntaxDirective: boolean, platformInfo: PlatformInfo): Promise<ImageBuildInfo> { |
| 419 | +export async function internalGetImageBuildInfoFromDockerfile(inspectDockerImage: (imageName: string) => Promise<ImageDetails>, dockerfileText: string, dockerBuildArgs: Record<string, string>, targetStage: string | undefined, substitute: SubstituteConfig, output: Log, omitSyntaxDirective: boolean, platformInfo: PlatformInfo, buildxPlatforms: PlatformInfo[]): Promise<ImageBuildInfo> { |
402 | 420 | const dockerfile = extractDockerfile(dockerfileText); |
403 | 421 | if (dockerfile.preamble.directives.syntax && omitSyntaxDirective) { |
404 | 422 | output.write(`Omitting syntax directive '${dockerfile.preamble.directives.syntax}' from Dockerfile.`, LogLevel.Trace); |
405 | 423 | delete dockerfile.preamble.directives.syntax; |
406 | 424 | } |
407 | | - const baseImage = findBaseImage(dockerfile, dockerBuildArgs, targetStage, platformInfo); |
408 | | - const dummyBaseImage = findBaseImage(dockerfile, dockerBuildArgs, targetStage, { os: 'unknown', arch: 'unknown' }); |
409 | | - if (baseImage !== dummyBaseImage) { |
| 425 | + const images: string[] = []; |
| 426 | + for (const platform of buildxPlatforms) { |
| 427 | + const image = findBaseImage(dockerfile, dockerBuildArgs, targetStage, platform); |
| 428 | + if (image) { |
| 429 | + images.push(image); |
| 430 | + } |
| 431 | + } |
| 432 | + if (images.length !== 0 && !images.every(image => image === images[0])) { |
410 | 433 | throw new Error(`Inconsistent base image used for multi-platform builds. Please check your Dockerfile.`); |
411 | 434 | } |
412 | | - const imageDetails = baseImage && await inspectDockerImage(baseImage) || undefined; |
| 435 | + const image = findBaseImage(dockerfile, dockerBuildArgs, targetStage, platformInfo); |
| 436 | + const imageDetails = image && await inspectDockerImage(image) || undefined; |
413 | 437 | const dockerfileUser = findUserStatement(dockerfile, dockerBuildArgs, envListToObj(imageDetails?.Config.Env), targetStage); |
414 | 438 | const user = dockerfileUser || imageDetails?.Config.User || 'root'; |
415 | 439 | const metadata = imageDetails ? getImageMetadata(imageDetails, substitute, output) : { config: [], raw: [], substitute }; |
|
0 commit comments