(params: DockerResolverParameters, devContainerConfig: SubstitutedConfig<DevContainerConfig>, featuresConfig: FeaturesConfig, baseName: string, imageBuildInfo: ImageBuildInfo, composeServiceUser: string | undefined)
| 225 | } |
| 226 | |
| 227 | async function getFeaturesBuildOptions(params: DockerResolverParameters, devContainerConfig: SubstitutedConfig<DevContainerConfig>, featuresConfig: FeaturesConfig, baseName: string, imageBuildInfo: ImageBuildInfo, composeServiceUser: string | undefined): Promise<ImageBuildOptions | undefined> { |
| 228 | const { common } = params; |
| 229 | const { cliHost, output } = common; |
| 230 | const { dstFolder } = featuresConfig; |
| 231 | |
| 232 | if (!dstFolder || dstFolder === '') { |
| 233 | output.write('dstFolder is undefined or empty in addContainerFeatures', LogLevel.Error); |
| 234 | return undefined; |
| 235 | } |
| 236 | |
| 237 | // With Buildkit (0.8.0 or later), we can supply an additional build context to provide access to |
| 238 | // the container-features content. |
| 239 | // For non-Buildkit, we build a temporary image to hold the container-features content in a way |
| 240 | // that is accessible from the docker build for non-BuiltKit builds |
| 241 | // TODO generate an image name that is specific to this dev container? |
| 242 | const buildKitVersionParsed = params.buildKitVersion?.versionMatch ? parseVersion(params.buildKitVersion.versionMatch) : undefined; |
| 243 | const minRequiredVersion = [0, 8, 0]; |
| 244 | const useBuildKitBuildContexts = buildKitVersionParsed ? !isEarlierVersion(buildKitVersionParsed, minRequiredVersion) : false; |
| 245 | const buildContentImageName = 'dev_container_feature_content_temp'; |
| 246 | const disableSELinuxLabels = useBuildKitBuildContexts && await isUsingSELinuxLabels(params); |
| 247 | // Access Docker engine version |
| 248 | const dockerEngineVersionParsed = params.dockerEngineVersion?.versionMatch ? parseVersion(params.dockerEngineVersion.versionMatch) : undefined; |
| 249 | const minDockerEngineVersion = [23, 0, 0]; |
| 250 | const skipDefaultSyntax = dockerEngineVersionParsed ? !isEarlierVersion(dockerEngineVersionParsed, minDockerEngineVersion) : false; |
| 251 | const omitPropertyOverride = params.common.skipPersistingCustomizationsFromFeatures ? ['customizations'] : []; |
| 252 | const imageMetadata = getDevcontainerMetadata(imageBuildInfo.metadata, devContainerConfig, featuresConfig, omitPropertyOverride, getOmitDevcontainerPropertyOverride(params.common)); |
| 253 | const { containerUser, remoteUser } = findContainerUsers(imageMetadata, composeServiceUser, imageBuildInfo.user); |
| 254 | const builtinVariables = [ |
| 255 | `_CONTAINER_USER=${containerUser}`, |
| 256 | `_REMOTE_USER=${remoteUser}`, |
| 257 | ]; |
| 258 | const envPath = cliHost.path.join(dstFolder, 'devcontainer-features.builtin.env'); |
| 259 | await cliHost.writeFile(envPath, Buffer.from(builtinVariables.join('\n') + '\n')); |
| 260 | |
| 261 | // When copying via buildkit, the content is accessed via '.' (i.e. in the context root) |
| 262 | // When copying via temp image, the content is in '/tmp/build-features' |
| 263 | const contentSourceRootPath = useBuildKitBuildContexts ? '.' : '/tmp/build-features/'; |
| 264 | const dockerfile = getContainerFeaturesBaseDockerFile(contentSourceRootPath) |
| 265 | .replace('#{nonBuildKitFeatureContentFallback}', useBuildKitBuildContexts ? '' : `FROM ${buildContentImageName} as dev_containers_feature_content_source`) |
| 266 | .replace('#{featureLayer}', getFeatureLayers(featuresConfig, containerUser, remoteUser, useBuildKitBuildContexts, contentSourceRootPath)) |
| 267 | .replace('#{containerEnv}', generateContainerEnvsV1(featuresConfig)) |
| 268 | .replace('#{devcontainerMetadata}', getDevcontainerMetadataLabel(imageMetadata)) |
| 269 | .replace('#{containerEnvMetadata}', generateContainerEnvs(devContainerConfig.config.containerEnv, true)) |
| 270 | ; |
| 271 | const syntax = imageBuildInfo.dockerfile?.preamble.directives.syntax; |
| 272 | const omitSyntaxDirective = common.omitSyntaxDirective; // Can be removed when https://github.com/moby/buildkit/issues/4556 is fixed |
| 273 | const dockerfilePrefixContent = `${omitSyntaxDirective ? '' : |
| 274 | skipDefaultSyntax ? (syntax ? `# syntax=${syntax}` : '') : |
| 275 | useBuildKitBuildContexts && !(imageBuildInfo.dockerfile && supportsBuildContexts(imageBuildInfo.dockerfile)) ? '# syntax=docker/dockerfile:1.4' : |
| 276 | syntax ? `# syntax=${syntax}` : ''} |
| 277 | ARG _DEV_CONTAINERS_BASE_IMAGE=placeholder |
| 278 | `; |
| 279 | |
| 280 | // Build devcontainer-features.env and devcontainer-features-install.sh file(s) for each features source folder |
| 281 | for await (const fSet of featuresConfig.featureSets) { |
| 282 | if (fSet.internalVersion === '2') |
| 283 | { |
| 284 | for await (const fe of fSet.features) { |
no test coverage detected