diff --git a/src/spec-configuration/containerFeaturesConfiguration.ts b/src/spec-configuration/containerFeaturesConfiguration.ts index 7b2f638ef..2e673dc66 100644 --- a/src/spec-configuration/containerFeaturesConfiguration.ts +++ b/src/spec-configuration/containerFeaturesConfiguration.ts @@ -226,7 +226,7 @@ export function getContainerFeaturesBaseDockerFile() { FROM $_DEV_CONTAINERS_BASE_IMAGE AS dev_containers_feature_content_normalize USER root -COPY --from=dev_containers_feature_content_source {contentSourceRootPath} /tmp/build-features/ +COPY --from=dev_containers_feature_content_source {contentSourceRootPath}/devcontainer-features.builtin.env /tmp/build-features/ RUN chmod -R 0700 /tmp/build-features FROM $_DEV_CONTAINERS_BASE_IMAGE AS dev_containers_target_stage @@ -312,7 +312,7 @@ function escapeQuotesForShell(input: string) { return input.replace(new RegExp(`'`, 'g'), `'\\''`); } -export function getFeatureLayers(featuresConfig: FeaturesConfig, containerUser: string, remoteUser: string) { +export function getFeatureLayers(featuresConfig: FeaturesConfig, containerUser: string, remoteUser: string, useBuildKitBuildContexts = false, contentSourceRootPath = '/tmp/build-features/') { let result = `RUN \\ echo "_CONTAINER_USER_HOME=$(getent passwd ${containerUser} | cut -d: -f6)" >> /tmp/build-features/devcontainer-features.builtin.env && \\ echo "_REMOTE_USER_HOME=$(getent passwd ${remoteUser} | cut -d: -f6)" >> /tmp/build-features/devcontainer-features.builtin.env @@ -322,22 +322,53 @@ echo "_REMOTE_USER_HOME=$(getent passwd ${remoteUser} | cut -d: -f6)" >> /tmp/bu // Features version 1 const folders = (featuresConfig.featureSets || []).filter(y => y.internalVersion !== '2').map(x => x.features[0].consecutiveId); folders.forEach(folder => { - result += `RUN cd /tmp/build-features/${folder} \\ + const source = path.posix.join(contentSourceRootPath, folder!); + if (!useBuildKitBuildContexts) { + result += `COPY --chown=root:root --from=dev_containers_feature_content_source ${source} /tmp/build-features/${folder} +RUN chmod -R 0700 /tmp/build-features/${folder} \\ +&& cd /tmp/build-features/${folder} \\ && chmod +x ./install.sh \\ && ./install.sh `; + } else { + result += `RUN --mount=type=bind,from=dev_containers_feature_content_source,source=${source},target=/tmp/build-features-src/${folder} \\ + cp -ar /tmp/build-features-src/${folder} /tmp/build-features/ \\ + && chmod -R 0700 /tmp/build-features/${folder} \\ + && cd /tmp/build-features/${folder} \\ + && chmod +x ./install.sh \\ + && ./install.sh \\ + && rm -rf /tmp/build-features/${folder} + +`; + } }); // Features version 2 featuresConfig.featureSets.filter(y => y.internalVersion === '2').forEach(featureSet => { featureSet.features.forEach(feature => { result += generateContainerEnvs(feature); - result += ` -RUN cd /tmp/build-features/${feature.consecutiveId} \\ + const source = path.posix.join(contentSourceRootPath, feature.consecutiveId!); + if (!useBuildKitBuildContexts) { + result += ` +COPY --chown=root:root --from=dev_containers_feature_content_source ${source} /tmp/build-features/${feature.consecutiveId} +RUN chmod -R 0700 /tmp/build-features/${feature.consecutiveId} \\ +&& cd /tmp/build-features/${feature.consecutiveId} \\ && chmod +x ./devcontainer-features-install.sh \\ && ./devcontainer-features-install.sh `; + } else { + result += ` +RUN --mount=type=bind,from=dev_containers_feature_content_source,source=${source},target=/tmp/build-features-src/${feature.consecutiveId} \\ + cp -ar /tmp/build-features-src/${feature.consecutiveId} /tmp/build-features/ \\ + && chmod -R 0700 /tmp/build-features/${feature.consecutiveId} \\ + && cd /tmp/build-features/${feature.consecutiveId} \\ + && chmod +x ./devcontainer-features-install.sh \\ + && ./devcontainer-features-install.sh \\ + && rm -rf /tmp/build-features/${feature.consecutiveId} + +`; + } }); }); return result; diff --git a/src/spec-node/containerFeatures.ts b/src/spec-node/containerFeatures.ts index 0a4ab06cd..6640284d5 100644 --- a/src/spec-node/containerFeatures.ts +++ b/src/spec-node/containerFeatures.ts @@ -289,7 +289,7 @@ async function getFeaturesBuildOptions(params: DockerResolverParameters, devCont .replace('#{nonBuildKitFeatureContentFallback}', useBuildKitBuildContexts ? '' : `FROM ${buildContentImageName} as dev_containers_feature_content_source`) .replace('{contentSourceRootPath}', contentSourceRootPath) .replace('#{featureBuildStages}', getFeatureBuildStages(featuresConfig, buildStageScripts, contentSourceRootPath)) - .replace('#{featureLayer}', getFeatureLayers(featuresConfig, containerUser, remoteUser)) + .replace('#{featureLayer}', getFeatureLayers(featuresConfig, containerUser, remoteUser, useBuildKitBuildContexts, contentSourceRootPath)) .replace('#{containerEnv}', generateContainerEnvs(featuresConfig)) .replace('#{copyFeatureBuildStages}', getCopyFeatureBuildStages(featuresConfig, buildStageScripts)) .replace('#{devcontainerMetadata}', getDevcontainerMetadataLabel(imageMetadata, common.experimentalImageMetadata)) diff --git a/src/test/container-features/generateFeaturesConfig.test.ts b/src/test/container-features/generateFeaturesConfig.test.ts index ddd7c687f..e36af4bf3 100644 --- a/src/test/container-features/generateFeaturesConfig.test.ts +++ b/src/test/container-features/generateFeaturesConfig.test.ts @@ -75,11 +75,15 @@ describe('validate generateFeaturesConfig()', function () { echo "_CONTAINER_USER_HOME=$(getent passwd testContainerUser | cut -d: -f6)" >> /tmp/build-features/devcontainer-features.builtin.env && \\ echo "_REMOTE_USER_HOME=$(getent passwd testRemoteUser | cut -d: -f6)" >> /tmp/build-features/devcontainer-features.builtin.env -RUN cd /tmp/build-features/first_1 \\ +COPY --chown=root:root --from=dev_containers_feature_content_source /tmp/build-features/first_1 /tmp/build-features/first_1 +RUN chmod -R 0700 /tmp/build-features/first_1 \\ +&& cd /tmp/build-features/first_1 \\ && chmod +x ./install.sh \\ && ./install.sh -RUN cd /tmp/build-features/second_2 \\ +COPY --chown=root:root --from=dev_containers_feature_content_source /tmp/build-features/second_2 /tmp/build-features/second_2 +RUN chmod -R 0700 /tmp/build-features/second_2 \\ +&& cd /tmp/build-features/second_2 \\ && chmod +x ./install.sh \\ && ./install.sh @@ -134,12 +138,16 @@ echo "_CONTAINER_USER_HOME=$(getent passwd testContainerUser | cut -d: -f6)" >> echo "_REMOTE_USER_HOME=$(getent passwd testRemoteUser | cut -d: -f6)" >> /tmp/build-features/devcontainer-features.builtin.env -RUN cd /tmp/build-features/color_3 \\ +COPY --chown=root:root --from=dev_containers_feature_content_source /tmp/build-features/color_3 /tmp/build-features/color_3 +RUN chmod -R 0700 /tmp/build-features/color_3 \\ +&& cd /tmp/build-features/color_3 \\ && chmod +x ./devcontainer-features-install.sh \\ && ./devcontainer-features-install.sh -RUN cd /tmp/build-features/hello_4 \\ +COPY --chown=root:root --from=dev_containers_feature_content_source /tmp/build-features/hello_4 /tmp/build-features/hello_4 +RUN chmod -R 0700 /tmp/build-features/hello_4 \\ +&& cd /tmp/build-features/hello_4 \\ && chmod +x ./devcontainer-features-install.sh \\ && ./devcontainer-features-install.sh