Ubuntu 18.04 => Ubuntu mutli-variant definition with 20.04 (#345)

* Add support for variant specific tags
* Switch ubuntu-git to use variants
* ubuntu-git => ubuntu
* Switch to buildpack-deps:curl
* definition-build => definition-manifest
This commit is contained in:
Chuck Lantz 2020-05-21 09:09:01 -07:00 коммит произвёл GitHub
Родитель 7fa627c0b8
Коммит cb8fdf99a1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
86 изменённых файлов: 299 добавлений и 171 удалений

3
.vscode/launch.json поставляемый
Просмотреть файл

@ -11,6 +11,7 @@
"program": "${workspaceFolder}/build/vscdc",
"args": [
"push",
"--no-push",
"--release", "master",
"--github-repo", "microsoft/vscode-dev-containers",
"--registry", "clantz.azurecr.io",
@ -42,8 +43,6 @@
"program": "${workspaceFolder}/build/vscdc",
"args": [
"cg",
"python-3",
"--no-build",
"--release", "master",
"--github-repo", "microsoft/vscode-dev-containers",
"--registry", "clantz.azurecr.io",

Просмотреть файл

@ -25,16 +25,16 @@ This CLI is used in the GitHub Actions workflows in this repository.
>
> However, if you have your own pre-built image or build process, you can simply reference it directly in you contributed container.
Image build/push to MCR is managed using config in `definition-build.json` files that are located in the container definition folder. The config lets you set dependencies between definitions and map actual image tags to multiple definitions. So, the steps to onboard an image are:
Image build/push to MCR is managed using config in `definition-manifest.json` files that are located in the container definition folder. The config lets you set dependencies between definitions and map actual image tags to multiple definitions. So, the steps to onboard an image are:
1. Create a `definition-build.json` file
1. Create a `definition-manifest.json` file
2. Update the `vscode` config files for MCR as appropriate (MS internal only).
Let's run through the `definition-build.json` file.
Let's run through the `definition-manifest.json` file.
### The build property
The `build` property defines how the definition maps to image tags and what type of "stub" should be used. Consider the Debian 9 [definition-build.json](../containers/debian-9-git/definition-build.json) file.
The `build` property defines how the definition maps to image tags and what type of "stub" should be used. Consider the Debian 9 [definition-manifest.json](../containers/debian-9-git/definition-manifest.json) file.
```json
"build": {
@ -98,7 +98,7 @@ Finally, there is a **`parent`** property that can be used to specify if the con
While in most cases it makes sense to version the contents of a definition with the repository, there may be scenarios where you want to be able to version independantly. A good example of this [is the `vsonline-linux` defintion](../containers/vsonline-linux) where upstream edits could cause breaking changes in this image. Rather than increasing the major version of the extension and all defintions whenever this happens, the definition has its own version number.
When this is necisary, the `definitionVersion` property in the `definition-build.json` file can be set.
When this is necessary, the `definitionVersion` property in the `definition-manifest.json` file can be set.
```json
"definitionVersion": "0.1.0"
@ -108,7 +108,7 @@ When this is necisary, the `definitionVersion` property in the `definition-build
In many cases, you will only need to create one image per dev container definition. Even if there is only one or two versions of a given runtime available at a given time, it can be useful to simply have different definitions to aid discoverability.
In other cases, you may want to generate multiple images from the same definition but with one small change. This is where the variants property comes in. Consider this `definition-build.json`:
In other cases, you may want to generate multiple images from the same definition but with one small change. This is where the variants property comes in. Consider this `definition-manifest.json`:
```json
"build": {
@ -120,6 +120,8 @@ In other cases, you may want to generate multiple images from the same definitio
}
```
The **left-most** item in the list is the one that will have the `latest` tag applied if applicable.
And in its corresponding Dockerfile:
```Dockerfile
@ -172,7 +174,7 @@ In `devcontainer.json`:
### The dependencies property
The dependencies property is used for dependency and version tracking. Consider the Debian 9 [definition-build.json](../containers/debian-9-git/definition-build.json) file.
The dependencies property is used for dependency and version tracking. Consider the Debian 9 [definition-manifest.json](../containers/debian-9-git/definition-manifest.json) file.
```json
"dependencies": {
@ -328,11 +330,11 @@ Consequently, this user stub Dockerfile needs to be versioned with the `devconta
📄 devcontainer.json
📄 Dockerfile
📁 test-project
📄 definition-build.json
📄 definition-manifest.json
📄 README.md
```
The `definition-build.json` file dictates how the build process should behave as [dscribed above](#setting-up-a-container-to-be-built). In this case, `devcontainer.json` points to `base.Dockerfile`, but this is the Dockerfile used to generate the actual image rather than the stub Dockerfile. The stub that references the image is in `base.Dockerfile`. To make things easy, we can also automatically generate this stub at release time if only a Dockerfile is present. If no `base.Dockerfile` is found, the build process falls back to using `Dockerfile`.
The `definition-manifest.json` file dictates how the build process should behave as [dscribed above](#setting-up-a-container-to-be-built). In this case, `devcontainer.json` points to `base.Dockerfile`, but this is the Dockerfile used to generate the actual image rather than the stub Dockerfile. The stub that references the image is in `base.Dockerfile`. To make things easy, we can also automatically generate this stub at release time if only a Dockerfile is present. If no `base.Dockerfile` is found, the build process falls back to using `Dockerfile`.
Testing, then, is as simple as it is now - open the folder in `vscode-dev-containers` in a container and edit / test as required. Anyone simply copying the folder contents then gets a fully working version of the container even if in-flight and there is no image for it yet.
@ -358,7 +360,7 @@ When a release is cut, the contents of vscode-dev-containers repo are staged. Th
1. Build an image using the `base.Dockerfile` and push it to a container registry with the appropriate version tags. If no `base.Dockerfile` is found, `Dockerfile` is used instead. If the `variants` property is set, one image is built per variant, with the variant value being passed in as the `VARIANT` build argument.
2. After the image is built and pushed, `base.Dockerfile` is deleted from staging if present. If no `base.Dockerrfile`, a `Dockerfile` is replaced with stub is used based on the configured rootDistro in `definition-build.json` (Alpine vs Debian).
2. After the image is built and pushed, `base.Dockerfile` is deleted from staging if present. If no `base.Dockerrfile`, a `Dockerfile` is replaced with stub is used based on the configured rootDistro in `definition-manifest.json` (Alpine vs Debian).
3. Next, `Dockerfile` is updated to point to the correct MAJOR version and a link is added to the Dockerfile used to build the referenced image.

Просмотреть файл

@ -19,7 +19,7 @@
"githubRepoName": "microsoft/vscode-dev-containers",
"containersPathInRepo": "containers",
"scriptLibraryPathInRepo": "script-library",
"definitionBuildConfigFile": "definition-build.json",
"definitionBuildConfigFile": "definition-manifest.json",
"devContainerJsonPreamble": "For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:",
"dockerFilePreamble": "To fully customize the contents of this image, use the following Dockerfile instead:"

Просмотреть файл

@ -58,14 +58,16 @@ async function prepDockerFile(devContainerDockerfilePath, definitionId, repo, re
await asyncUtils.writeFile(devContainerDockerfilePath, devContainerDockerfileModified)
}
function getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists, useVariantArg) {
function getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists, useVariantArg, registry, registryPath) {
if (useVariantArg) {
// The VARIANT arg allows this value to be set from devcontainer.json
const tagCaptureGroup = /^(.+:.+-)(.+)/.exec(imageTag);
const version = configUtils.getVersionFromRelease(release);
const variant = configUtils.getDefinitionFromTag(imageTag).variant;
const tagWithVariant = configUtils.getTagsForVersion(definitionId, version, registry, registryPath, '${VARIANT}')[0];
return `# ${configUtils.getConfig('dockerFilePreamble')}\n` +
`# https://github.com/${repo}/tree/${release}/${containersPathInRepo}/${definitionId}/.devcontainer/${baseDockerFileExists ? 'base.' : ''}Dockerfile\n` +
`ARG VARIANT="${tagCaptureGroup[2]}"\n` +
`FROM ${tagCaptureGroup[1]}\${VARIANT}`;
`ARG VARIANT="${variant}"\n` +
`FROM ${tagWithVariant}`;
}
return `# ${configUtils.getConfig('dockerFilePreamble')}\n` +
`# https://github.com/${repo}/tree/${release}/${containersPathInRepo}/${definitionId}/.devcontainer/${baseDockerFileExists ? 'base.' : ''}Dockerfile\n` +
@ -76,10 +78,7 @@ async function createStub(dotDevContainerPath, definitionId, repo, release, base
const userDockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
console.log('(*) Generating user Dockerfile...');
const templateDockerfile = await configUtils.objectByDefinitionLinuxDistro(definitionId, stubPromises);
const devContainerImageVersion = configUtils.majorFromRelease(release, definitionId);
const imageTag = configUtils.getTagsForVersion(definitionId, devContainerImageVersion, stubRegistry, stubRegistryPath)[0];
const userDockerFile = templateDockerfile.replace(
'FROM REPLACE-ME', getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists));
const userDockerFile = processStub(templateDockerfile, definitionId, repo, release, baseDockerFileExists, stubRegistry, stubRegistryPath);
await asyncUtils.writeFile(userDockerFilePath, userDockerFile);
}
@ -87,15 +86,27 @@ async function updateStub(dotDevContainerPath, definitionId, repo, release, base
console.log('(*) Updating user Dockerfile...');
const userDockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
const userDockerFile = await asyncUtils.readFile(userDockerFilePath);
const devContainerImageVersion = configUtils.majorFromRelease(release, definitionId);
const imageTag = configUtils.getTagsForVersion(definitionId, devContainerImageVersion, registry, registryPath)[0];
const hasVariantArg = (/ARG\s+VARIANT\s*=/.exec(userDockerFile) != null);
const userDockerFileModified = userDockerFile.replace(/(ARG\s+VARIANT\s*=\s*.+\n)?(FROM\s+.+:.+)/,
getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists, hasVariantArg));
const userDockerFileModified = processStub(userDockerFile, definitionId, repo, release, baseDockerFileExists, registry, registryPath);
await asyncUtils.writeFile(userDockerFilePath, userDockerFileModified);
}
async function processStub(userDockerFile, definitionId, repo, release, baseDockerFileExists, registry, registryPath) {
const devContainerImageVersion = configUtils.majorFromRelease(release, definitionId);
let fromSection = `# ${configUtils.getConfig('dockerFilePreamble')}\n` +
`# https://github.com/${repo}/tree/${release}/${containersPathInRepo}/${definitionId}/.devcontainer/${baseDockerFileExists ? 'base.' : ''}Dockerfile\n`;
// The VARIANT arg allows this value to be set from devcontainer.json, handle it if found
if (/ARG\s+VARIANT\s*=/.exec(userDockerFile) !== null) {
const variant = configUtils.getVariants(definitionId)[0];
const tagWithVariant = configUtils.getTagsForVersion(definitionId, devContainerImageVersion, registry, registryPath, '${VARIANT}')[0];
fromSection += `ARG VARIANT="${variant}"\nFROM ${tagWithVariant}`;
} else {
const imageTag = configUtils.getTagsForVersion(definitionId, devContainerImageVersion, registry, registryPath)[0];
fromSection += `FROM ${imageTag}`;
}
return userDockerFile.replace(/(ARG\s+VARIANT\s*=\s*.+\n)?(FROM\s+.+:.+)/, fromSection);
}
async function updateConfigForRelease(definitionPath, definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath) {
// Look for context in devcontainer.json and use it to build the Dockerfile
console.log(`(*) Making version specific updates to ${definitionId}...`);

Просмотреть файл

@ -12,6 +12,7 @@ const config = require('../../config.json');
config.definitionDependencies = config.definitionDependencies || {};
config.definitionBuildSettings = config.definitionBuildSettings || {};
config.definitionVersions = config.definitionVersions || {};
config.definitionVariants = config.definitionVariants || {};
const stagingFolders = {};
const definitionTagLookup = {};
@ -28,10 +29,13 @@ async function loadConfig(repoPath) {
return;
}
const definitionId = definitionFolder.name;
// If definition-build.json exists, load it
const possibleDefinitionBuildJson = path.join(containersPath, definitionId, getConfig('definitionBuildConfigFile', 'definition-build.json'));
// If definition-manifest.json exists, load it
const possibleDefinitionBuildJson = path.join(containersPath, definitionId, getConfig('definitionBuildConfigFile', 'definition-manifest.json'));
if (await asyncUtils.exists(possibleDefinitionBuildJson)) {
const buildJson = await jsonc.read(possibleDefinitionBuildJson);
if (buildJson.variants) {
config.definitionVariants[definitionId] = buildJson.variants;
}
if (buildJson.build) {
config.definitionBuildSettings[definitionId] = buildJson.build;
}
@ -47,25 +51,32 @@ async function loadConfig(repoPath) {
// Populate image variants and tag lookup
for (let definitionId in config.definitionBuildSettings) {
const buildSettings = config.definitionBuildSettings[definitionId];
const definitionVariants = config.definitionVariants[definitionId];
const dependencies = config.definitionDependencies[definitionId];
// Populate images list for variants
dependencies.imageVariants = buildSettings.variants ?
buildSettings.variants.map((variant) => dependencies.image.replace('${VARIANT}', variant)) :
dependencies.imageVariants = definitionVariants ?
definitionVariants.map((variant) => dependencies.image.replace('${VARIANT}', variant)) :
[dependencies.image];
// Populate image tag lookup
if (buildSettings.tags) {
// Variants can be used as a VARAINT arg in tags, so support that too
const variants = buildSettings.variants ? buildSettings.variants.concat(['${VARIANT}', '$VARIANT']) : [undefined];
const variants = definitionVariants ? definitionVariants.concat(['${VARIANT}', '$VARIANT']) : [undefined];
variants.forEach((variant) => {
const blankTagList = getTagsForVersion(definitionId, '', 'ANY', 'ANY', variant);
blankTagList.forEach((blankTag) => {
definitionTagLookup[blankTag] = definitionId;
definitionTagLookup[blankTag] = {
id: definitionId,
variant: variant
};
});
const devTagList = getTagsForVersion(definitionId, 'dev', 'ANY', 'ANY', variant);
devTagList.forEach((devTag) => {
definitionTagLookup[devTag] = definitionId;
definitionTagLookup[devTag] = {
id: definitionId,
variant: variant
}
});
})
}
@ -119,16 +130,20 @@ function getLatestTag(definitionId, registry, registryPath) {
if (typeof config.definitionBuildSettings[definitionId] === 'undefined') {
return null;
}
// Given there could be multiple registries in the tag list, get all the different latest variations
return config.definitionBuildSettings[definitionId].tags.reduce((list, tag) => {
list.push(`${registry}/${registryPath}/${tag.replace(/:.+/, ':latest')}`);
const latest = `${registry}/${registryPath}/${tag.replace(/:.+/, ':latest')}`
if(list.indexOf(latest) < 0) {
list.push(latest);
}
return list;
}, []);
}
function getVariants(definitionId) {
const buildSettings = config.definitionBuildSettings[definitionId];
return buildSettings ? buildSettings.variants : null;
return config.definitionVariants[definitionId] || null;
}
// Create all the needed variants of the specified version identifier for a given definition
@ -136,19 +151,35 @@ function getTagsForVersion(definitionId, version, registry, registryPath, varian
if (typeof config.definitionBuildSettings[definitionId] === 'undefined') {
return null;
}
// Use the first variant if none passed in, unless there isn't one
if (!variant) {
const variants = getVariants(definitionId);
variant = variants ? variants[0] : 'NOVARIANT';
}
return config.definitionBuildSettings[definitionId].tags.reduce((list, tag) => {
let tags = config.definitionBuildSettings[definitionId].tags;
// See if there are any variant specific tags that should be added to the output
const variantTags = config.definitionBuildSettings[definitionId].variantTags;
if(variantTags) {
// ${VARIANT} or $VARIANT may be passed in as a way to do lookups. Add all in this case.
if(['${VARIANT}', '$VARIANT'].indexOf(variant) > -1 ) {
for(let variantEntry in variantTags) {
tags = tags.concat(variantTags[variantEntry]);
}
} else {
tags = tags.concat(variantTags[variant]);
}
}
return tags.reduce((list, tag) => {
// One of the tags that needs to be supported is one where there is no version, but there
// are other attributes. For example, python:3 in addition to python:0.35.0-3. So, a version
// of '' is allowed. However, there are also instances that are just the version, so in
// these cases latest would be used instead. However, latest is passed in separately.
let baseTag = tag.replace('${VERSION}', version)
.replace(':-', ':')
.replace('${VARIANT}', variant || 'NOVARIANT')
.replace(/\$\{?VARIANT\}?/, variant || 'NOVARIANT')
.replace('-NOVARIANT', '');
if (baseTag.charAt(baseTag.length - 1) !== ':') {
list.push(`${registry}/${registryPath}/${baseTag}`);
@ -179,8 +210,15 @@ function getTagList(definitionId, release, updateLatest, registry, registryPath,
`${versionParts[0]}.${versionParts[1]}`
];
// If this variant should actually be the latest tag, use it
let tagList = (updateLatest && config.definitionBuildSettings[definitionId].latest) ? getLatestTag(definitionId, registry, registryPath) : [];
// If this variant should actually be the latest tag (it's the left most in the list), use it
const allVariants = getVariants(definitionId);
const firstVariant = allVariants ? allVariants[0] : variant;
let tagList = (updateLatest
&& config.definitionBuildSettings[definitionId].latest
&& variant === firstVariant)
? getLatestTag(definitionId, registry, registryPath)
: [];
versionList.forEach((tagVersion) => {
tagList = tagList.concat(getTagsForVersion(definitionId, tagVersion, registry, registryPath, variant));
});
@ -277,13 +315,13 @@ function getParentTagForVersion(definitionId, version, registry, registryPath, v
return parentId ? getTagsForVersion(parentId, version, registry, registryPath, variant)[0] : null;
}
// Takes an existing tag and updates it with a new registry version and optionally a variant
function getUpdatedTag(currentTag, currentRegistry, currentRegistryPath, updatedVersion, updatedRegistry, updatedRegistryPath, variant) {
updatedRegistry = updatedRegistry || currentRegistry;
updatedRegistryPath = updatedRegistryPath || currentRegistryPath;
const captureGroups = new RegExp(`${currentRegistry}/${currentRegistryPath}/(.+):(.+)`).exec(currentTag);
const definitionId = definitionTagLookup[`ANY/ANY/${captureGroups[1]}:${captureGroups[2]}`];
const definitionId = getDefinitionFromTag(currentTag, currentRegistry, currentRegistryPath).id;
// See if no variant passed in, see definition has any and use one if it matches
if (!variant) {
let variants = getVariants(definitionId);
@ -291,15 +329,16 @@ function getUpdatedTag(currentTag, currentRegistry, currentRegistryPath, updated
// The variant may be passed in as an ARG instead, support that too
variants = variants.concat(['${VARIANT}', '$VARIANT']);
// Find the best match if any exist
const tagPart = /.+:(.+)/.exec(currentTag)[1];
variant = variants.reduce((prev, current) => {
return new RegExp(`^.*-?${current.replace('$','\\$')}$`).exec(captureGroups[2]) ? current : prev;
}, false);
return new RegExp(`^.*-?${current.replace('$','\\$')}$`).exec(tagPart) ? current : prev;
}, false);
}
}
const updatedTags = getTagsForVersion(definitionId, updatedVersion, updatedRegistry, updatedRegistryPath, variant);
if (updatedTags && updatedTags.length > 0) {
console.log(` Updating ${currentTag}\n to ${updatedTags[0]}`);
console.log(` Updating ${currentTag}\n to ${updatedTags[0]}`);
return updatedTags[0];
}
// In the case where this is already a tag with a version number in it,
@ -307,6 +346,14 @@ function getUpdatedTag(currentTag, currentRegistry, currentRegistryPath, updated
return currentTag;
}
// Lookup definition from a tag
function getDefinitionFromTag(tag, registry, registryPath) {
registry = registry || '.+';
registryPath = registryPath || '.+';
const captureGroups = new RegExp(`${registry}/${registryPath}/(.+):(.+)`).exec(tag);
return definitionTagLookup[`ANY/ANY/${captureGroups[1]}:${captureGroups[2]}`];
}
// Return just the major version of a release number
function majorFromRelease(release, definitionId) {
const version = getVersionFromRelease(release, definitionId);
@ -354,6 +401,7 @@ module.exports = {
loadConfig: loadConfig,
getTagList: getTagList,
getVariants: getVariants,
getDefinitionFromTag: getDefinitionFromTag,
getSortedDefinitionBuildList: getSortedDefinitionBuildList,
getParentTagForVersion: getParentTagForVersion,
getUpdatedTag: getUpdatedTag,

Просмотреть файл

@ -169,7 +169,7 @@ require('yargs')
},
'github-repo': {
describe: 'vscode-dev-containers repo name',
default: configUtils.getConfig('vscodeDevContainersRepo', 'https://github.com/microsoft/vscode-dev-containers')
default: configUtils.getConfig('githubRepoName', 'microsoft/vscode-dev-containers')
},
'build': {
describe: 'whether to to build the image first step',

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,3 +1,3 @@
definition-build.json
definition-manifest.json
.npmignore
README.md

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -2,7 +2,9 @@
"build": {
"rootDistro": "alpine",
"tags": [
"base:${VERSION}-alpine-3.10"
"base:${VERSION}-alpine3.10",
"base:${VERSION}-alpine-3.10",
"base:${VERSION}-alpine"
]
},
"dependencies": {

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,6 +1,6 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore
WORKSPACE

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,6 +1,6 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -3,7 +3,9 @@
"latest": true,
"rootDistro": "debian",
"tags": [
"base:${VERSION}-debian10",
"base:${VERSION}-debian-10",
"base:${VERSION}-debian",
"base:${VERSION}-buster"
]
},

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,8 +1,8 @@
{
"build": {
"latest": true,
"rootDistro": "debian",
"tags": [
"base:${VERSION}-debian9",
"base:${VERSION}-debian-9",
"base:${VERSION}-stretch"
]

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,6 +1,6 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore
.ionide

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,6 +1,6 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore
environment.yml

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,11 +1,11 @@
{
"variants": ["3", "3.8", "3.7", "3.6"],
"build": {
"latest": true,
"rootDistro": "debian",
"tags": [
"python:${VERSION}-${VARIANT}"
],
"variants": ["3", "3.8", "3.7", "3.6"]
]
},
"dependencies": {
"image": "python:${VARIANT}",

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Двоичные данные
containers/ruby-2-rails-5/.npmignore

Двоичный файл не отображается.

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,6 +1,6 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore
Cargo.lock

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,6 +1,6 @@
{
"latest": false,
"build": {
"latest": true,
"rootDistro": "debian",
"parent": "javascript-node-12",
"tags": [

Просмотреть файл

@ -1,25 +0,0 @@
{
"build": {
"rootDistro": "debian",
"tags": [
"base:${VERSION}-ubuntu-18.04",
"base:${VERSION}-bionic"
]
},
"dependencies": {
"image": "ubuntu:18.04",
"imageLink": "https://hub.docker.com/_/ubuntu",
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

Просмотреть файл

@ -0,0 +1,15 @@
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
# Update the VARIANT arg in devcontainer.json to pick an Ubuntu version: 20.04, 18.04
ARG VARIANT=20.04
FROM mcr.microsoft.com/vscode/devcontainers/base:ubuntu${VARIANT}
# ** [Optional] Uncomment this section to install additional packages. **
#
# RUN apt-get update \
# && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>

Просмотреть файл

@ -2,7 +2,10 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM ubuntu:18.04
# Update the VARIANT arg in devcontainer.json to pick an Ubuntu version: 20.04, 18.04
ARG VARIANT="20.04"
FROM buildpack-deps:${VARIANT}-curl
# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
@ -12,30 +15,24 @@ ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
# Options for common package install script - SHA generated on release
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
ARG UPGRADE_PACKAGES="true"
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh"
ARG COMMON_SCRIPT_SHA="dev-mode"
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
# Configure apt and install packages
RUN apt-get update \
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
&& export DEBIAN_FRONTEND=noninteractive \
#
# Verify git, common tools / libs installed, add/modify non-root user, optionally install zsh
&& wget -q -O /tmp/common-setup.sh $COMMON_SCRIPT_SOURCE \
&& if [ "$COMMON_SCRIPT_SHA" != "dev-mode" ]; then echo "$COMMON_SCRIPT_SHA /tmp/common-setup.sh" | sha256sum -c - ; fi \
&& /bin/bash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
&& apt-get -y install --no-install-recommends curl ca-certificates 2>&1 \
&& curl -sSL ${COMMON_SCRIPT_SOURCE} -o /tmp/common-setup.sh \
&& ([ "${COMMON_SCRIPT_SHA}" = "dev-mode" ] || (echo "${COMMON_SCRIPT_SHA} /tmp/common-setup.sh" | sha256sum -c -)) \
&& /bin/bash /tmp/common-setup.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" \
&& rm /tmp/common-setup.sh \
#
# Clean up
# Clean ups
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog

Просмотреть файл

@ -1,6 +1,11 @@
{
"name": "Ubuntu 18.04 & Git",
"dockerFile": "Dockerfile",
"name": "Ubuntu",
"build": {
"dockerfile": "base.Dockerfile",
// Update 'VARIANT' to pick an Ubuntu version. Rebuild the container
// if it already exists to update. Available variants: 18.04, 20.04
"args": { "VARIANT": "20.04" }
},
// Set *default* container specific settings.json values on container create.
"settings": {

Просмотреть файл

@ -1,5 +1,5 @@
README.md
test-project
definition-build.json
definition-manifest.json
.vscode
.npmignore

Просмотреть файл

@ -1,14 +1,15 @@
# Ubuntu 18.04 & Git
# Ubuntu
## Summary
*Simple Ubuntu 18.04 container with Git installed.*
*A simple Ubuntu container with Git and other common utilities installed.*
| Metadata | Value |
|----------|-------|
| *Contributors* | The VS Code Team |
| *Definition type* | Dockerfile |
| *Published image* | mcr.microsoft.com/vscode/devcontainers/base:ubuntu-18.04 |
| *Published images* | mcr.microsoft.com/vscode/devcontainers/base:ubuntu |
| *Available image variants* | mcr.microsoft.com/vscode/devcontainers/base:ubuntu18.04 <br /> mcr.microsoft.com/vscode/devcontainers/base:ubuntu20.04 |
| *Published image architecture(s)* | x86-64 |
| *Works in Codespaces* | Yes |
| *Container host OS support* | Linux, macOS, Windows |
@ -16,11 +17,13 @@
## Using this definition with an existing folder
While the definition itself works unmodified, you can also directly reference pre-built versions of `.devcontainer/Dockerfile` by using the `image` property in `.devcontainer/devcontainer.json` or updating the `FROM` statement in your own `Dockerfile` to:
While the definition itself works unmodified, you can also directly reference pre-built versions of `.devcontainer/base.Dockerfile` by using the `image` property in `.devcontainer/devcontainer.json` or updating the `FROM` statement in your own `Dockerfile` to one of the following:
`mcr.microsoft.com/vscode/devcontainers/base:ubuntu-18.04`
- `mcr.microsoft.com/vscode/devcontainers/base:ubuntu`
- `mcr.microsoft.com/vscode/devcontainers/base:ubuntu20.04`
- `mcr.microsoft.com/vscode/devcontainers/base:ubuntu18.04`
Alternatively, you can use the contents of the `Dockerfile` to fully customize your container's contents or to build it for a container host architecture not supported by the image.
Alternatively, you can use the contents of the `base.Dockerfile` to fully customize your container's contents or to build it for a container host architecture not supported by the image.
Beyond `git`, this image / `Dockerfile` includes `zsh`, [Oh My Zsh!](https://ohmyz.sh/), a non-root `vscode` user with `sudo` access, and a set of common dependencies for development.
@ -37,7 +40,7 @@ Just follow these steps:
3. To use the Dockerfile for this definition (*rather than the pre-built image*):
1. Clone this repository.
2. Copy the contents of `containers/ubuntu-18.04-git/.devcontainer` to the root of your project folder.
2. Copy the contents of `containers/ubuntu-git/.devcontainer` to the root of your project folder.
3. Start VS Code and open your project folder.
4. After following step 2 or 3, the contents of the `.devcontainer` folder in your project can be adapted to meet your needs.
@ -51,8 +54,8 @@ This definition includes some test code that will help you verify it is working
1. If this is your first time using a development container, please follow the [getting started steps](https://aka.ms/vscode-remote/containers/getting-started) to set up your machine.
2. Clone this repository.
3. Start VS Code, press <kbd>F1</kbd>, and select **Remote-Containers: Open Folder in Container...**
4. Select the `containers/ubuntu-18.04-git` folder.
5. Press <kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>\`</kbd> and type the following command to verify installation: `apt-get update && apt-get install -y lsb-release && git --version && lsb_release -a`
4. Select the `containers/ubuntu-git` folder.
5. Press <kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>\`</kbd> and type the following command to verify installation: `git --version && lsb_release -a`
6. After lsb_release installs, you should see the Git version and details about the version of Linux in the container.
## License

Просмотреть файл

@ -0,0 +1,62 @@
{
"variants": ["20.04", "18.04"],
"build": {
"rootDistro": "debian",
"tags": [
"base:${VERSION}-ubuntu${VARIANT}",
"base:${VERSION}-ubuntu-${VARIANT}"
],
"variantTags": {
"20.04": [
"base:${VERSION}-focal",
"base:${VERSION}-ubuntu"
],
"18.04": [
"base:${VERSION}-bionic"
]
}
},
"dependencies": {
"image": "buildpack-deps:${VARIANT}-curl",
"imageLink": "https://hub.docker.com/_/buildpack-deps",
"debian": [
"apt-utils",
"dialog",
"ca-certificates",
"git",
"iproute2",
"procps",
"curl",
"openssh-client",
"less",
"nano",
"gnupg",
"jq",
"wget",
"unzip",
"lsb-release",
"apt-transport-https",
"libc6",
"libgcc1",
"libgssapi-krb5-2",
"libicu[0-9][0-9]",
"libssl1.1",
"libstdc++6",
"zlib1g",
"sudo",
"zsh"
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

Просмотреть файл

@ -11,10 +11,11 @@
"files": [
"containers",
"containers-readmes",
"repository-containers"
"repository-containers",
"manifests"
],
"scripts": {
"prepack": "rimraf containers-readmes && copyfiles --up 1 containers/**/README.md containers-readmes"
"prepack": "rimraf containers-readmes manifests && copyfiles --up 1 containers/**/README.md containers-readmes && copyfiles --up 1 containers/**/definition-manifest.json manifests"
},
"devDependencies": {
"copyfiles": "^2.1.1",

Просмотреть файл

@ -3,17 +3,23 @@
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
ARG IMAGE_TO_TEST=debian:9
ARG IMAGE_TO_TEST=debian:10
FROM ${IMAGE_TO_TEST}
ARG DISTRO="debian"
ARG USERNAME="vscode"
ARG INSTALL_DOCKER="true"
ARG UPGRADE_PACKAGES="true"
ARG DEBIAN_FRONTEND=noninteractive
COPY *.sh /tmp/
RUN chmod +x /tmp/*.sh \
&& if [ "${DISTRO}" = "debian" ]; then \
apt-get update; \
fi
RUN if [ "${DISTRO}" = "debian" ]; then apt-get update; fi
RUN chmod +x /tmp/*.sh
# Run common script
RUN /tmp/common-${DISTRO}.sh true ${USERNAME} 1000 1000 ${UPGRADE_PACKAGES}
RUN export DEBIAN_FRONTEND=noninteractive && /tmp/common-${DISTRO}.sh true ${USERNAME} 1000 1000