This commit is contained in:
Chuck Lantz 2020-01-14 14:53:59 -08:00
Родитель 99d5e5105a
Коммит b645c2fe85
109 изменённых файлов: 3044 добавлений и 572 удалений

68
.github/workflows/push-and-package.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,68 @@
name: Release Containers
on:
#repository_dispatch:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Get Tag Name
id: get_tag_name
uses: olegtarasov/get-tag@v1
- name: Container Registry Login
id: docker_login
uses: azure/docker-login@v1
with:
login-server: ${{ secrets.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Checkout
id: checkout
uses: actions/checkout@v1
- name: Push and Package
id: push_and_package
run: |
# Push images and package
yarn install
build/vscdc pack --release ${{ steps.get_tag_name.outputs.tag }} \
--github-repo ${{ github.repository }} \
--registry ${{ secrets.REGISTRY }} \
--registry-path ${{ secrets.REGISTRY_BASE_PATH }} \
--stub-registry ${{ secrets.STUB_REGISTRY }} \
--stub-registry-path ${{ secrets.STUB_REGISTRY_BASE_PATH }}
# Set an output with the resulting package name for upload
PKG_PREFIX=$(node -p "require('./package.json').name")
echo "::set-output name=package_name::$(ls $PKG_PREFIX-*.tgz)"
- name: Create Release
id: create_release
uses: actions/create-release@v1.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: false
prerelease: false
- name: Upload NPM Package as Release Asset
id: upload_release_asset
uses: actions/upload-release-asset@v1.0.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./${{ steps.push_and_package.outputs.package_name }}
asset_name: ${{ steps.push_and_package.outputs.package_name }}
asset_content_type: application/gzip

69
.github/workflows/push-dev.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,69 @@
name: CI & Push "dev"
on:
repository_dispatch:
push:
branches: master
paths:
- 'containers/**'
- 'script-library/**'
jobs:
build:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, 'Automated update') && !contains(github.event.head_commit.message, 'CI ignore')"
steps:
- name: Container Registry Login
id: docker_login
uses: azure/docker-login@v1
with:
login-server: ${{ secrets.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Checkout
id: checkout
uses: actions/checkout@v1
- name: Push "dev", Package, update CG manifest
id: push_and_package
run: |
# Push dev images and package
set -e
yarn install
GIT_BRANCH=$(echo "${{ github.ref }}" | grep -oP 'refs/(heads|tags)/\K(.+)')
if [ "$GIT_BRANCH" == "" ]; then
GIT_BRANCH=master
fi
build/vscdc pack --release $GIT_BRANCH \
--github-repo ${{ github.repository }} \
--registry ${{ secrets.REGISTRY }} \
--registry-path ${{ secrets.REGISTRY_BASE_PATH }} \
--stub-registry ${{ secrets.STUB_REGISTRY }} \
--stub-registry-path ${{ secrets.STUB_REGISTRY_BASE_PATH }}
# Set an output with the resulting package name for upload
PKG_PREFIX=$(node -p "require('./package.json').name")
mv ./$PKG_PREFIX-*.tgz ./$PKG_PREFIX-${{ github.sha }}.tgz
echo "::set-output name=package_name::$PKG_PREFIX-${{ github.sha }}.tgz"
# Update CG manifest
build/vscdc cg --no-build --release $BRANCH --github-repo ${{ github.repository }} --registry ${{ secrets.REGISTRY }} --registry-path ${{ secrets.REGISTRY_BASE_PATH }}
git config --global user.email "vscr-feedback@microsoft.com"
git config --global user.name "CI"
git add cgmanifest.json
git commit -m 'Automated update' \
&& git push "https://ci:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" "HEAD:${{ github.ref }}" \
|| echo 'No updates to cgmanifest.json'
- name: Upload Package
uses: actions/upload-artifact@v1.0.0
with:
name: ${{ steps.push_and_package.outputs.package_name }}
path: ./${{ steps.push_and_package.outputs.package_name }}

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

@ -0,0 +1,52 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Run Push Script",
"program": "${workspaceFolder}/build/vscdc",
"args": [
"push",
"--release", "clantz/image-generation",
"--github-repo", "microsoft/vscode-dev-containers",
"--registry", "clantz.azurecr.io",
"--registryPath", "vscode/devcontainers",
"--stubRegistry", "clantz.azurecr.io",
"--stubRegistryPath", "vscode/devcontainers"
]
},
{
"type": "node",
"request": "launch",
"name": "Run Pack Script",
"program": "${workspaceFolder}/build/vscdc",
"args": [
"pack",
"--no-clean",
"--release", "clantz/image-generation",
"--github-repo", "microsoft/vscode-dev-containers",
"--registry", "clantz.azurecr.io",
"--registryPath", "vscode/devcontainers",
"--stubRegistry", "clantz.azurecr.io",
"--stubRegistryPath", "vscode/devcontainers"
]
}, {
"type": "node",
"request": "launch",
"name": "Run CG Manifest Script",
"program": "${workspaceFolder}/build/vscdc",
"args": [
"cg",
"--no-build",
"--release", "clantz/image-generation",
"--github-repo", "microsoft/vscode-dev-containers",
"--registry", "clantz.azurecr.io",
"--registryPath", "vscode/devcontainers"
]
}
]
}

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

@ -1,3 +1,13 @@
{
"extensions.ignoreRecommendations": true
"extensions.ignoreRecommendations": true,
"cSpell.words": [
"Distro",
"Dockerfiles",
"copyfiles",
"devcontainer",
"devcontainers",
"dpkg",
"npmignore",
"redhat"
]
}

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

@ -1,51 +0,0 @@
trigger:
branches:
include: ['*']
tags:
include: ['*']
steps:
- task: NodeTool@0
inputs:
versionSpec: "10.15.1"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs:
versionSpec: "1.19.1"
- script: |
set -e
yarn
NAME=$(node -p "require('./package.json').name")
VERSION=$(node -p "require('./package.json').version")
TMP_NAME="$NAME-$VERSION.tgz"
if [[ "$BUILD_SOURCEBRANCH" != refs/tags/* ]]; then
VERSION="$VERSION-${BUILD_SOURCEVERSION:0:8}"
fi
TGZ_NAME="$NAME-$VERSION.tgz"
TGZ_PATH="$SYSTEM_ARTIFACTSDIRECTORY/$TGZ_NAME"
npm pack
mv "$TMP_NAME" "$TGZ_PATH"
echo "##vso[task.setvariable variable=TgzName]$TGZ_NAME"
echo "##vso[task.setvariable variable=TgzPath]$TGZ_PATH"
displayName: Build
- task: PublishPipelineArtifact@0
displayName: 'Publish Pipeline Artifact'
inputs:
artifactName: $(TgzName)
targetPath: $(TgzPath)
- task: GitHubRelease@0
displayName: 'Create GitHub Release'
inputs:
gitHubConnection: 'GitHub Connection'
repositoryName: $(Build.Repository.Name)
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))

18
build/.eslintrc.js Normal file
Просмотреть файл

@ -0,0 +1,18 @@
module.exports = {
"env": {
"commonjs": true,
"es6": true,
"node": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018
},
"rules": {
"require-atomic-updates": 0
}
};

282
build/README.md Normal file
Просмотреть файл

@ -0,0 +1,282 @@
# Build and image generation for vscode-dev-containers
This folder contains scripts to build and push images into the Microsoft Container Registry (MCR) from this repository, generate or modify any associated content to use the built image, track dependencies, and create an npm package with the result that is shipped in the VS Code Remote - Containers extension.
## Build CLI
The Node.js based build CLI (`build/vsdc`) has commands to:
1. Build and push to a repository: `build/vsdc push`
2. Build, push, and npm package assets that are modified as described above: `build/vsdc package`
3. Generate cgmanifest.json: `build/vsdc cg`
Run with the `--help` option to see inputs.
## Setting up a container to be built
> **Note:** Only Microsoft VS Code team members can currently onboard an image to this process since it requires access the Microsoft Container Registry. 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:
1. Create a `definition-build.json` file
2. Update the `vscode` config files for MCR as appropriate (MS internal only).
Let's run through the `definition-build.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.
```json
"build": {
"rootDistro": "debian",
"latest": true,
"tags": [
"base:${VERSION}-debian-9",
"base:${VERSION}-stretch"
]
}
```
The **`rootDistro`** property can be `debian`, `alpine`, or `redhat` currently. Ubuntu-based containers should use `debian`.
The **`latest`** and **`tags`** properties affect how tags are applied. For example, here is how several dev container folders map:
```text
debian-9-git => mcr.microsoft.com/vscode/devcontainers/base:debian-9
alpine-3.10-git => mcr.microsoft.com/vscode/devcontainers/base:alpine-3.10
ubnutu-18.04-git => mcr.microsoft.com/vscode/devcontainers/base:ubuntu-18.04
javascript-node-12 => mcr.microsoft.com/vscode/devcontainers/javascript-node:12
typescript-node-10 => mcr.microsoft.com/vscode/devcontainers/typescript-node:12
javascript-node-10 => mcr.microsoft.com/vscode/devcontainers/javascript-node:10
typescript-node-10 => mcr.microsoft.com/vscode/devcontainers/typescript-node:10
```
This results in just three "repositories" in the registry much like you would see for other images in Docker Hub.
- mcr.microsoft.com/vscode/devcontainers/base
- mcr.microsoft.com/vscode/devcontainers/javascript-node
- mcr.microsoft.com/vscode/devcontainers/typescript-node
The package version is then automatically added to these various tags in the `${VERSION}` location for an item in the `tags` property array as a part of the release. For example, release 0.40.0 would result in:
mcr.microsoft.com/vscode/devcontainers/base
- 0.40.0-debian-9
- 0.40-debian-9
- 0-debian-9
- debian-9 <= Equivalent of latest for debian-9 specifically
- 0.40.0-stretch
- 0.40-stretch
- 0-stretch
- stretch <= Equivalent of latest for stretch specifically
In this case, Debian is also the one that is used for `latest` for the `base` repository, so that tag gets applied too. If you ran only the Alpine or Ubuntu versions, the latest tag would not update.
There's a special "dev" version that can be used to build master on CI - I ended up needing this to test and others would if they base an image off of one of the MCR images. e.g. `dev-debian-9`.
Finally, there is a **`parent`** property that can be used to specify if the container depends an image created as a part of another container build. For example, `typescript-node-10` uses the image from `javascript-node-10` and therefore includes the following:
```json
"build" {
"parent": "javascript-node-10"
}
```
### 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.
```json
"dependencies": {
"image": "debian:9",
"imageLink": "https://hub.docker.com/_/debian",
"debian": [
"apt-utils",
"..."
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
```
The **`image`** property is the actual base Docker image either in Docker Hub or MCR. **`imageLink`** is then the link to a dscription of the image.
Following this is a list of libraries installed in the image by its Dockerfile. The following package types are currently supported:
- `debian` - Debian packages (apt-get)
- `ubuntu` - Ubuntu packages (apt-get)
- `alpine` - Alpine Linux packages (apk)
- `npm` - npmjs.com packages installed using npm or yarn
- `manual` - Useful for other types of registrations that do not have a specific type, like `git` in the example above.
For everything but `manual`, the image that is generated is started so the package versions can be queried automatically.
## Details
Currently the vscode-dev-containers repo contains pure Dockerfiles that need to be built when used. While this works well from the perspective of providing samples, some of the images install a significant number of runtimes or tools which can take a long time to build.
We can resolve this by pre-building some of these images, but in-so-doing we want to make sure we:
1. Ensure vscode-dev-containers continues to be a good source of samples
2. Improve the performance using the most popular (or in some cases slowest to build) container images
3. Make it easy for users to add additional software to the images
4. Make it easy for contributors to build, customize, and contribute new definitions
We won't be able to build all images in the repository or publish them under a Microsoft registry, but we would want to allow contributors to build their own images for contributions if they wanted to do so by keeping the ability to use a stand alone Dockerfile, image reference, or docker-compose file like today.
## Image generation for vscode-dev-containers
In order to meet the above requirements, this first phase keeps the way the dev containers deployed as it is now - an npm package. Future phases could introduce a formal registry, but this is overkill current state.
### Versioning
At this phase, versioning of the image can be tied to the release of the npm package. For example, as of this writing, the current version is 0.35.0. All images that are generated would then inherit this version.
We would follow semver rules for bumping up the repository name - any fix that needs to be deployed immediately would be "fix" level semver bump. When released as latest, the image would be tagged as is done in other Docker images. Using the 0.35.0 example, new images would be tagged as:
- 0
- 0.35
- 0.35.0
- latest
In the unlikely event a break fix needed to be deployed and not tagged latest, we would have a facility to tag as follows:
- 0.35
- 0.35.0
This has a few advantages:
1. Tags are generated for each version of the repository that is cut. This allows us to refer directly to the exact version of the source code used to build the container image to avoid confusion. e.g. `https://github.com/microsoft/vscode-dev-containers/tree/v0.35.0/containers/javascript-node-8`
2. Similarly, as containers are deprecated and removed from the repository, you can still refer back to the container source and README.
3. Upstream changes that break existing images can be handled as needed.
4. Developers can opt to use the image tag 0.35 to get the latest break fix version if desired or 0 to always get the latest non-breaking update.
This scheme will work in the near term where we do not have a large number of dev containers in the repository, but over time will not scale. However, to realistically support independent versioning, we'd need to build out a registry service - which may or may not be required. This will be evaluated at a later date.
### Deprecation of container definitions
The versioning scheme above allows us to version dev containers and reference them even when they are removed from `master`. To keep the number of containers in `master` reasonable, we would deprecate and remove containers under the following scenarios:
1. It refers to a runtime that is no longer supported - e.g. Node.js 8 is out of support as of the end of 2019, so we would deprecate `javascript-node-8`. Until that point, we would have containers for node 8, 10, and 12 (which just went LTS).
2. The container is not used enough to maintain and has broken.
3. The container refers to a product that has been deprecated.
4. The container was contributed by a 3rd party, has issues, and the 3rd party is not responsive.
Since the images would continue to exist after this point and the source code is available under the version label, we can safely remove the containers from master without impacting customers.
### Release process and the contents of the npm package
When a release is cut, there are a few things that need to happen. One is obviously releasing the appropriate image. However, to continue to help customers understand how to customize their images, we would want to reference a user modifiable "stub" Dockerfile instead of an image directly. This also is important to help deal with shortcomings and workarounds that require something like specifying a build argument. For example:
```Dockerfile
FROM mcr.microsoft.com/vscode/devcontainer/javascript-node:0.35-10
ARG USER_UID=1000
ARG USER_GID=$USER_UID
ENV DEBIAN_FRONTEND=noninteractive
# [Optional] Update UID/GID if needed and install additional software
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
if [ "$USER_GID" != "1000" ]; then sudo groupmod 1000 --gid $USER_GID; fi \
&& if [ "$USER_UID" != "1000" ]; then sudo usermod --uid $USER_UID 1000; fi; \
fi \
#
# ***************************************************************
# * Add steps for installing any other needed dependencies here *
# ***************************************************************
#
# Clean up
&& sudo apt-get autoremove -y \
&& sudo apt-get clean -y \
&& sudo rm -rf /var/lib/apt/lists/*
# Uncomment to default to non-root user
# USER $USER_UID
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog
```
This retains its value as a sample but minimizes the number of actual build steps. This template would **evolve over time as new features are added**. For example, the above Dockerfile includes a way to make sure the user's GID/UID matches the local operating system - which is critical for Linux users. However, if we introduce a `user` concept in `devcontainer.json`, the template would no longer need to include this part of the file.
Referencing The MAJOR.MINOR version in this Dockerfile allows us to push fixes or upstream updates that do not materially change the definition.
### Repository contents
Consequently, this user stub Dockerfile needs to be versioned with the `devcontainer.json` file and can technically version independently of the actual main Dockerfile and image. Given this tie, it makes sense to keep this file with `devcontainer.json` in the repository. The repository therefore would could contain:
```text
📁 .devcontainer
📄 base.Dockerfile
📄 devcontainer.json
📄 Dockerfile
📁 test-project
📄 README.md
```
Here, `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.
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.
In the vscode-dev-containers repo itself, the `FROM` statement in `Dockerfile` would always point to `latest` or `dev` since it what is in master may not have even been released yet. This would get dynamically updated as a part of the release process - which we will cover next.
```Dockerfile
FROM mcr.microsoft.com/vs/devcontainer/javascript-node:dev-10
```
#### Automated updates of other Dockerfiles
The process also automatically swaps out referenced MCR images for MAJOR.MINOR versions of built images in any Dockerfile that is added to the package. This allows us to push break fix and or security patches as break fix releases and people will get them. The build supports an option to not update `latest` and MAJOR versions, so we can also rev old MAJOR.MINOR versions if we have to, but normally we'd roll forward instead.
#### Common scripts
Another problem the build solves is mass updates - there's a set of things we want in every image and right now it requires ~54 changes to add things. With this new process, images use a tagged version of scripts in `script-library`. The build generates a SHA for script so they can be safely used in Dockerfiles that are not built into images while still allowing people to just grab `.devcontainer` from master and use it if they prefer.
#### Release process
When a release is cut, the contents of vscode-dev-containers repo would staged. The build process would then do the following for the appropriate dev containers:
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 renamed to `base.Dockerfile` and used instead.
2. After the image is built and pushed, `base.Dockerfile` is deleted from staging.
3. Next, `Dockerfile` is updated to point to the correct MAJOR.MINOR version. If no Dockerfile is found, a stub is used based on the root image (Alpine vs Debian).
```Dockerfile
# For information on the contents of the image referenced below, see the Dockerfile at
# https://github.com/microsoft/vscode-dev-containers/tree/v0.35.0/containers/javascript-node-10/.devcontainer/base.Dockerfile
FROM mcr.microsoft.com/vs/devcontainer/javascript-node:0.35-10
```
4. `devcontainer.json` is updated to point to `Dockerfile` instead of `base.Dockerfile` (if required) and add a comment to the source code README for this specific version.
```json
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at
// https://github.com/microsoft/vscode-dev-containers/tree/v0.35.0/containers/javascript-node-10
{
"name": "Node.js 10",
"dockerFile": "user.Dockerfile",
"extensions": [
"dbaeumer.vscode-eslint"
]
}
```
These modified contents are then archived in an npm package exactly as they are today and shipped with the extension (and over time we could dynamically update this between extension releases).
```text
📁 .devcontainer
📄 devcontainer.json
📄 Dockerfile
```

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

@ -0,0 +1,35 @@
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM REPLACE-ME
# The image referenced above includes a non-root user with sudo access. Add
# the "remoteUser" property to devcontainer.json to use it. On Linux, the container
# user's GID/UIDs will be updated to match your local UID/GID when using the image
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
# dockerComposeFile property or want the image itself to start with different ID
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# [Optional] Update UID/GID if needed
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
apk add --no-cache shadow \
&& USERNAME=$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd) \
&& groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi
# ************************************************************************
# * Uncomment this section to use RUN to install other dependencies. *
# * Note that Alpine uses "apk" instead of "apt-get" like Debian/Ubuntu. *
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
# ************************************************************************
# RUN apk update \
# && apk add --no-cache <your-package-list-here>
# Uncomment to default to non-root user
# USER $USER_UID

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

@ -0,0 +1,42 @@
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM REPLACE-ME
# The image referenced above includes a non-root user with sudo access. Add
# the "remoteUser" property to devcontainer.json to use it. On Linux, the container
# user's GID/UIDs will be updated to match your local UID/GID when using the image
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
# dockerComposeFile property or want the image itself to start with different ID
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# [Optional] Update UID/GID if needed
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
USERNAME=$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd) \
&& groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi
# *************************************************************
# * Uncomment this section to use RUN instructions to install *
# * any needed dependencies after executing "apt-get update". *
# * See https://docs.docker.com/engine/reference/builder/#run *
# *************************************************************
# ENV DEBIAN_FRONTEND=noninteractive
# RUN apt-get update \
# && apt-get -y install --no-reccomends <your-package-list-here> \
# #
# # Clean up
# && apt-get autoremove -y \
# && apt-get clean -y \
# && rm -rf /var/lib/apt/lists/*
# ENV DEBIAN_FRONTEND=dialog
# Uncomment to default to non-root user
# USER $USER_UID

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

@ -0,0 +1,36 @@
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM REPLACE-ME
# The image referenced above includes a non-root user with sudo access. Add
# the "remoteUser" property to devcontainer.json to use it. On Linux, the container
# user's GID/UIDs will be updated to match your local UID/GID when using the image
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
# dockerComposeFile property or want the image itself to start with different ID
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# [Optional] Update UID/GID if needed
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
USERNAME=$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd) \
&& groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi
# ************************************************************************
# * Uncomment this section to use RUN to install other dependencies. *
# * Note that RedHat uses "yum" instead of "apt-get" like Debian/Ubuntu. *
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
# ************************************************************************
# RUN yum -y install <your-package-list-here> \
# #
# # Clean up
# && yum clean all
# Uncomment to default to non-root user
# USER $USER_UID

22
build/config.json Normal file
Просмотреть файл

@ -0,0 +1,22 @@
{
"containerRegistry": "devcon.azurecr.io",
"containerRegistryPath": "public/vscode/devcontainers",
"stubRegistry": "mcr.microsoft.com",
"stubRegistryPath": "vscode/devcontainers",
"filesToStage": [
"+(containers|repository-containers)/**/!(test-project)/*",
"LICENSE",
"package.json",
"yarn.lock",
".npmignore"
],
"githubRepoName": "microsoft/vscode-dev-containers",
"containersPathInRepo": "containers",
"scriptLibraryPathInRepo": "script-library",
"definitionBuildConfigFile": "definition-build.json",
"devContainerJsonPreamble": "For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:",
"dockerFilePreamble": "For information on the contents of the container image below, see following Dockerfile:"
}

238
build/src/cgmanifest.js Normal file
Просмотреть файл

@ -0,0 +1,238 @@
const path = require('path');
const push = require('./push').push;
const asyncUtils = require('./utils/async');
const configUtils = require('./utils/config');
// Example manifest: https://dev.azure.com/mseng/AzureDevOps/_git/Governance.Specs?path=%2Fcgmanifest.json&version=GBusers%2Fcajone%2Fcgmanifest.json
// Docker images and native OS libraries need to be registered as "other" while others are scenario dependant
const dependencyLookupConfig = {
debian: {
// Command to get package versions: dpkg-query --show -f='${Package}\t${Version}\n' <package>
// Output: <package> <version>
// Command to get download URLs: apt-get update && apt-get install -y --reinstall --print-uris
namePrefix: 'Debian Package:',
listCommand: "dpkg-query --show -f='${Package}\t${Version}\n'",
lineRegEx: /(.+)\t(.+)/,
getUriCommand: 'apt-get update && apt-get install -y --reinstall --print-uris',
uriMatchRegex: "'(.+)'\\s*${PACKAGE}_${VERSION}"
},
ubuntu: {
// Command to get package versions: dpkg-query --show -f='${Package}\t${Version}\n' <package>
// Output: <package> <version>
// Command to get download URLs: apt-get update && apt-get install -y --reinstall --print-uris
namePrefix: 'Ubuntu Package:',
listCommand: "dpkg-query --show -f='${Package}\t${Version}\n'",
lineRegEx: /(.+)\t(.+)/,
getUriCommand: 'apt-get update && apt-get install -y --reinstall --print-uris',
uriMatchRegex: "'(.+)'\\s*${PACKAGE}_${VERSION}"
},
alpine: {
// Command to get package versions: apk info -e -v <package>
// Output: <package-with-maybe-dashes>-<version-with-dashes>
// Command to get download URLs: apk policy
namePrefix: 'Alpine Package:',
listCommand: "apk info -e -v",
lineRegEx: /(.+)-([0-9].+)/,
getUriCommand: 'apk update && apk policy',
uriMatchRegex: '${PACKAGE} policy:\\n.*${VERSION}:\\n.*lib/apk/db/installed\\n\\s*(.+)\\n',
uriSuffix: '/x86_64/${PACKAGE}-${VERSION}.apk'
}
}
async function generateComponentGovernanceManifest(repo, release, registry, registryPath, buildFirst) {
// Load config files
await configUtils.loadConfig();
if (buildFirst) {
// Simulate the build and push process, but don't actually push
console.log('(*) Simulating push process to trigger image builds...');
await push(repo, release, false, registry, registryPath, registry, registryPath, true);
} else {
console.log('(*) Using existing local images...');
}
const alreadyRegistered = {};
const cgManifest = {
"Registrations": [],
"Version": 1
}
console.log('(*) Generating manifest...');
const definitionDependencies = configUtils.getAllDependencies();
for (let definitionId in definitionDependencies) {
const dependencies = definitionDependencies[definitionId];
if (typeof dependencies === 'object') {
// Add Docker image registration
const [image, imageVersion] = dependencies.image.split(':');
if (typeof alreadyRegistered[dependencies.image] === 'undefined') {
cgManifest.Registrations.push({
"Component": {
"Type": "other",
"Other": {
"Name": `Docker Image: ${image}`,
"Version": imageVersion,
"DownloadUrl": dependencies.imageLink
}
}
});
alreadyRegistered[dependencies.image] = [imageVersion];
}
// Docker image to use to determine installed package versions
const imageTag = configUtils.getTagsForVersion(definitionId, 'dev', registry, registryPath)[0]
// Run commands in the package to pull out needed versions
cgManifest.Registrations = cgManifest.Registrations.concat(
await generatePackageComponentList(dependencyLookupConfig.debian, dependencies.debian, imageTag, alreadyRegistered),
await generatePackageComponentList(dependencyLookupConfig.ubuntu, dependencies.ubuntu, imageTag, alreadyRegistered),
await generatePackageComponentList(dependencyLookupConfig.alpine, dependencies.alpine, imageTag, alreadyRegistered),
await generateNpmComponentList(dependencies.npm, alreadyRegistered),
filteredManualComponentRegistrations(dependencies.manual, alreadyRegistered));
}
}
console.log('(*) Writing manifest...');
await asyncUtils.writeFile(
path.join(__dirname, '..', '..', 'cgmanifest.json'),
JSON.stringify(cgManifest, undefined, 4))
console.log('(*) Done!');
}
async function generatePackageComponentList(config, packageList, imageTag, alreadyRegistered) {
if(!packageList) {
return [];
}
const componentList = [];
console.log(`(*) Generating Linux package registrations for ${imageTag}...`);
// Generate and exec command to get installed package versions
console.log('(*) Getting package versions...');
const packageVersionListCommand = packageList.reduce((prev, current) => {
return prev += ` ${current}`;
}, config.listCommand);
const packageVersionListOutput = await asyncUtils.spawn('docker',
['run', '--rm', imageTag, packageVersionListCommand],
{ shell: true, stdio: 'pipe' });
// Generate and exec command to extract download URIs
console.log('(*) Getting package download URLs...');
const packageUriCommand = packageList.reduce((prev, current) => {
return prev += ` ${current}`;
}, config.getUriCommand);
const packageUriCommandOutput = await asyncUtils.spawn('docker',
['run', '--rm', imageTag, `sh -c '${packageUriCommand}'`],
{ shell: true, stdio: 'pipe' });
const packageVersionList = packageVersionListOutput.split('\n');
packageVersionList.forEach((packageVersion) => {
packageVersion = packageVersion.trim();
if (packageVersion !== '') {
const versionCaptureGroup = new RegExp(config.lineRegEx).exec(packageVersion);
const package = versionCaptureGroup[1];
const version = versionCaptureGroup[2];
const entry = createEntryForLinuxPackage(packageUriCommandOutput, config.namePrefix, package, version, alreadyRegistered, config.uriMatchRegex, config.uriSuffix)
if (entry) {
componentList.push(entry);
}
}
});
return componentList;
}
function createEntryForLinuxPackage(packageUriCommandOutput, entryNamePrefix, package, version, alreadyRegistered, uriMatchRegex, uriSuffix)
{
const uniquePackageName = `${entryNamePrefix} ${package}`;
if (typeof alreadyRegistered[uniquePackageName] === 'undefined'
|| alreadyRegistered[uniquePackageName].indexOf(version) < 0) {
// Handle regex reserved charters in regex strings and that ":" is treaded as "1%3a" on Debian/Ubuntu
const sanitizedPackage = package.replace(/\+/g, '\\+').replace(/\./g, '\\.');
const sanitizedVersion = version.replace(/\+/g, '\\+').replace(/\./g, '\\.').replace(/:/g, '%3a');
const uriCaptureGroup = new RegExp(
uriMatchRegex.replace('${PACKAGE}', sanitizedPackage).replace('${VERSION}', sanitizedVersion), 'm')
.exec(packageUriCommandOutput);
if (!uriCaptureGroup) {
console.log(`(!) No URI found for ${package} ${version}`)
}
const uriString = uriCaptureGroup ? uriCaptureGroup[1] : '';
alreadyRegistered[uniquePackageName] = alreadyRegistered[uniquePackageName] || [];
alreadyRegistered[uniquePackageName].push(version);
return {
"Component": {
"Type": "other",
"Other": {
"Name": uniquePackageName,
"Version": version,
"DownloadUrl": `${uriString}${uriSuffix ?
uriSuffix.replace('${PACKAGE}', package).replace('${VERSION}', version)
: ''}`
}
}
}
}
return null;
}
function filteredManualComponentRegistrations(manualRegistrations, alreadyRegistered) {
if(!manualRegistrations) {
return [];
}
const componentList = [];
manualRegistrations.forEach((component) => {
const key = JSON.stringify(component);
if (typeof alreadyRegistered[key] === 'undefined') {
componentList.push(component);
alreadyRegistered[key] = [key];
}
});
return componentList;
}
async function generateNpmComponentList(packageList, alreadyRegistered) {
if(!packageList) {
return [];
}
console.log(`(*) Generating npm registrations...`);
const componentList = [];
await asyncUtils.forEach(packageList, async (package) => {
let version = '';
if (package.indexOf('@') >= 0) {
[package, version] = package.split('@');
} else {
const npmInfoRaw = await asyncUtils.spawn('npm', ['info', package, '--json'], { shell: true, stdio: 'pipe' });
const npmInfo = JSON.parse(npmInfoRaw);
version = npmInfo['dist-tags'].latest;
}
const uniquePackageName = `npm-${package}`;
if (typeof alreadyRegistered[uniquePackageName] === 'undefined'
|| alreadyRegistered[uniquePackageName].indexOf(version) < 0) {
componentList.push({
"Component": {
"Type": "npm",
"Npm": {
"Name": package,
"Version": version
}
}
});
alreadyRegistered[uniquePackageName] = alreadyRegistered[uniquePackageName] || [];
alreadyRegistered[uniquePackageName].push(version);
}
});
return componentList;
}
module.exports = {
generateComponentGovernanceManifest: generateComponentGovernanceManifest
}

75
build/src/package.js Normal file
Просмотреть файл

@ -0,0 +1,75 @@
/*--------------------------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
*-------------------------------------------------------------------------------------------------------------*/
const path = require('path');
const push = require('./push').push;
const prep = require('./prep');
const asyncUtils = require('./utils/async');
const configUtils = require('./utils/config');
const packageJson = require('../../package.json');
async function package(repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, pushImages, cleanWhenDone, simulate) {
stubRegistry = stubRegistry || registry;
stubRegistryPath = stubRegistryPath || registryPath;
// Load config files
await configUtils.loadConfig();
// Stage content
const stagingFolder = await configUtils.getStagingFolder(release);
const definitionStagingFolder = path.join(stagingFolder, 'containers');
if (pushImages) {
// First, push images, update content
await push(repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate);
}
// Then package
console.log(`\n(*) **** Package ${release} ****`);
console.log(`(*) Updating package.json with release version...`);
const version = configUtils.getVersionFromRelease(release);
const packageJsonVersion = version === 'dev' ? packageJson.version + '-dev' : version;
const packageJsonPath = path.join(stagingFolder, 'package.json');
const packageJsonRaw = await asyncUtils.readFile(packageJsonPath);
const packageJsonModified = packageJsonRaw.replace(/"version".?:.?".+"/, `"version": "${packageJsonVersion}"`);
await asyncUtils.writeFile(packageJsonPath, packageJsonModified);
// Update all definition config files for release (devcontainer.json, Dockerfile)
const allDefinitions = await asyncUtils.readdir(definitionStagingFolder);
await asyncUtils.forEach(allDefinitions, async (currentDefinitionId) => {
await prep.updateConfigForRelease(
path.join(definitionStagingFolder, currentDefinitionId),
currentDefinitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath);
});
console.log('(*) Packaging...');
const opts = { stdio: 'inherit', cwd: stagingFolder, shell: true };
await asyncUtils.spawn('yarn', ['install'], opts);
await asyncUtils.spawn('npm', ['pack'], opts); // Need to use npm due to https://github.com/yarnpkg/yarn/issues/685
let outputPath = null;
if (simulate) {
console.log('(*) Simulating: Skipping package move.');
} else {
console.log('(*) Moving package...');
outputPath = path.join(__dirname, '..', '..', `${packageJson.name}-${packageJsonVersion}.tgz`);
await asyncUtils.rename(path.join(stagingFolder, `${packageJson.name}-${packageJsonVersion}.tgz`), outputPath);
}
if (cleanWhenDone) {
// And finally clean up
console.log('(*) Cleaning up...');
await asyncUtils.rimraf(stagingFolder);
}
console.log('(*) Done!!');
return outputPath;
}
module.exports = {
package: package
}

126
build/src/prep.js Normal file
Просмотреть файл

@ -0,0 +1,126 @@
/*--------------------------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
*-------------------------------------------------------------------------------------------------------------*/
const path = require('path');
const asyncUtils = require('./utils/async');
const configUtils = require('./utils/config');
const scriptSHA = {};
const assetsPath = path.join(__dirname, '..', 'assets');
const stubPromises = {
alpine: asyncUtils.readFile(path.join(assetsPath, 'alpine.Dockerfile')),
debian: asyncUtils.readFile(path.join(assetsPath, 'debian.Dockerfile')),
redhat: asyncUtils.readFile(path.join(assetsPath, 'redhat.Dockerfile'))
}
const containersPathInRepo = configUtils.getConfig('containersPathInRepo');
const scriptLibraryPathInRepo = configUtils.getConfig('scriptLibraryPathInRepo');
async function prepDockerFile(devContainerDockerfilePath, definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath, isForBuild) {
// Use exact version of building, MAJOR.MINOR if not
const version = isForBuild ? configUtils.getVersionFromRelease(release) : configUtils.majorMinorFromRelease(release);
// Read Dockerfile
const devContainerDockerfileRaw = await asyncUtils.readFile(devContainerDockerfilePath);
let devContainerDockerfileModified = devContainerDockerfileRaw;
// Replace script URL and generate SHA if applicable
const scriptCaptureGroups = new RegExp(`COMMON_SCRIPT_SOURCE="(.+)/${scriptLibraryPathInRepo.replace('.', '\\.')}/(.+)"`).exec(devContainerDockerfileRaw);
if (scriptCaptureGroups) {
const scriptName = scriptCaptureGroups[2];
const scriptSource = `https://raw.githubusercontent.com/${repo}/${release}/${scriptLibraryPathInRepo}/${scriptName}`;
let sha = scriptSHA[scriptName];
if (typeof sha === 'undefined') {
const scriptRaw = await asyncUtils.getUrlAsString(scriptSource);
sha = await asyncUtils.shaForString(scriptRaw);
scriptSHA[scriptName] = sha;
}
devContainerDockerfileModified = devContainerDockerfileModified
.replace(/COMMON_SCRIPT_SHA=".+"/, `COMMON_SCRIPT_SHA="${sha}"`)
.replace(/COMMON_SCRIPT_SOURCE=".+"/, `COMMON_SCRIPT_SOURCE="${scriptSource}"`);
}
if (isForBuild) {
// If building, update FROM to target registry and version if definition has a parent
const parentTag = configUtils.getParentTagForVersion(definitionId, version, registry, registryPath);
if (parentTag) {
devContainerDockerfileModified = devContainerDockerfileModified.replace(/FROM .+:.+/, `FROM ${parentTag}`)
}
} else {
// Otherwise update any Dockerfiles that refer to an un-versioned tag of another dev container
// to the MAJOR.MINOR version from this release.
const expectedRegistry = configUtils.getConfig('stubRegistry', 'mcr.microsoft.com');
const expectedRegistryPath = configUtils.getConfig('stubRegistryPath', 'vscode/devcontainers');
const fromCaptureGroups = new RegExp(`FROM (${expectedRegistry}/${expectedRegistryPath}/.+:.+)`).exec(devContainerDockerfileRaw);
if (fromCaptureGroups && fromCaptureGroups.length > 0) {
const fromDefinitionTag = configUtils.getUpdatedTag(
fromCaptureGroups[1],
expectedRegistry,
expectedRegistryPath,
version,
stubRegistry,
stubRegistryPath);
devContainerDockerfileModified = devContainerDockerfileModified
.replace(fromCaptureGroups[0], `FROM ${fromDefinitionTag}`);
}
}
await asyncUtils.writeFile(devContainerDockerfilePath, devContainerDockerfileModified)
}
function getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists) {
return `# ${configUtils.getConfig('dockerFilePreamble')}\n` +
`# https://github.com/${repo}/tree/${release}/${containersPathInRepo}/${definitionId}/.devcontainer/${baseDockerFileExists ? 'base.' : ''}Dockerfile\n` +
`FROM ${imageTag}`;
}
async function createStub(dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, stubRegistry, stubRegistryPath) {
const userDockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
console.log('(*) Generating user Dockerfile...');
const templateDockerfile = await configUtils.objectByDefinitionLinuxDistro(definitionId, stubPromises);
const majorMinor = configUtils.majorMinorFromRelease(release);
const imageTag = configUtils.getTagsForVersion(definitionId, majorMinor, stubRegistry, stubRegistryPath)[0];
const userDockerFile = templateDockerfile.replace(
'FROM REPLACE-ME', getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists));
await asyncUtils.writeFile(userDockerFilePath, userDockerFile);
}
async function updateStub(dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, registry, registryPath) {
console.log('(*) Updating user Dockerfile...');
const userDockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
const userDockerFile = await asyncUtils.readFile(userDockerFilePath);
const majorMinor = configUtils.majorMinorFromRelease(release);
const imageTag = configUtils.getTagsForVersion(definitionId, majorMinor, registry, registryPath)[0];
const userDockerFileModified = userDockerFile.replace(/FROM .+:.+/,
getFromSnippet(definitionId, imageTag, repo, release, baseDockerFileExists));
await asyncUtils.writeFile(userDockerFilePath, userDockerFileModified);
}
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}...`);
const dotDevContainerPath = path.join(definitionPath, '.devcontainer');
const devContainerJsonPath = path.join(dotDevContainerPath, 'devcontainer.json');
const devContainerJsonRaw = await asyncUtils.readFile(devContainerJsonPath);
const devContainerJsonModified =
`// ${configUtils.getConfig('devContainerJsonPreamble')}\n// https://github.com/${repo}/tree/${release}/${containersPathInRepo}/${definitionId}\n` +
devContainerJsonRaw;
await asyncUtils.writeFile(devContainerJsonPath, devContainerJsonModified);
// Replace version specific content in Dockerfile
const dockerFilePath = path.join(dotDevContainerPath, 'Dockerfile');
if (await asyncUtils.exists(dockerFilePath)) {
await prepDockerFile(dockerFilePath, definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath, false);
}
}
module.exports = {
createStub: createStub,
updateStub: updateStub,
updateConfigForRelease: updateConfigForRelease,
prepDockerFile: prepDockerFile
}

96
build/src/push.js Normal file
Просмотреть файл

@ -0,0 +1,96 @@
/*--------------------------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
*-------------------------------------------------------------------------------------------------------------*/
const path = require('path');
const jsonc = require('jsonc').jsonc;
const asyncUtils = require('./utils/async');
const configUtils = require('./utils/config');
const prep = require('./prep');
async function push(repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate, definitionId) {
stubRegistry = stubRegistry || registry;
stubRegistryPath = stubRegistryPath || registryPath;
// Load config files
await configUtils.loadConfig();
// Stage content
const stagingFolder = await configUtils.getStagingFolder(release);
const definitionStagingFolder = path.join(stagingFolder, 'containers');
// Build and push subset of images
const definitionsToPush = definitionId ? [definitionId] : configUtils.getSortedDefinitionBuildList();
await asyncUtils.forEach(definitionsToPush, async (currentDefinitionId) => {
console.log(`**** Pushing ${currentDefinitionId} ${release} ****`);
await pushImage(
path.join(definitionStagingFolder, currentDefinitionId),
currentDefinitionId, repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate);
});
return stagingFolder;
}
async function pushImage(definitionPath, definitionId, repo, release, updateLatest, registry, registryPath, stubRegistry, stubRegistryPath, simulate) {
const dotDevContainerPath = path.join(definitionPath, '.devcontainer');
// Use base.Dockerfile for image build if found, otherwise use Dockerfile
const baseDockerFileExists = await asyncUtils.exists(path.join(dotDevContainerPath, 'base.Dockerfile'));
const dockerFilePath = path.join(dotDevContainerPath, `${baseDockerFileExists ? 'base.' : ''}Dockerfile`);
// Make sure there's a Dockerfile present
if (!await asyncUtils.exists(dockerFilePath)) {
throw `Invalid path ${dockerFilePath}`;
}
// Determine tags to use
const versionTags = configUtils.getTagList(definitionId, release, updateLatest, registry, registryPath)
console.log(`(*) Tags:${versionTags.reduce((prev, current) => prev += `\n ${current}`, '')}`);
// Look for context in devcontainer.json and use it to build the Dockerfile
console.log('(*) Reading devcontainer.json...');
const devContainerJsonPath = path.join(dotDevContainerPath, 'devcontainer.json');
const devContainerJsonRaw = await asyncUtils.readFile(devContainerJsonPath);
const devContainerJson = jsonc.parse(devContainerJsonRaw);
// Update common setup script download URL, SHA
console.log(`(*) Prep Dockerfile for ${definitionId}...`);
await prep.prepDockerFile(dockerFilePath,
definitionId, repo, release, registry, registryPath, stubRegistry, stubRegistryPath, true);
// Build image
console.log(`(*) Building image...`);
const workingDir = path.resolve(dotDevContainerPath, devContainerJson.context || '.')
const buildParams = versionTags.reduce((prev, current) => prev.concat(['-t', current]), []);
const spawnOpts = { stdio: 'inherit', cwd: workingDir, shell: true };
await asyncUtils.spawn('docker', ['build', workingDir, '-f', dockerFilePath].concat(buildParams), spawnOpts);
// Push
if (simulate) {
console.log(`(*) Simulating: Skipping push to registry.`);
} else {
console.log(`(*) Pushing ${definitionId}...`);
await asyncUtils.forEach(versionTags, async (versionTag) => {
await asyncUtils.spawn('docker', ['push', versionTag], spawnOpts);
});
}
// If base.Dockerfile found, update stub/devcontainer.json, otherwise create
if (baseDockerFileExists) {
await prep.updateStub(
dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, stubRegistry, stubRegistryPath);
console.log('(*) Updating devcontainer.json...');
await asyncUtils.writeFile(devContainerJsonPath, devContainerJsonRaw.replace('"base.Dockerfile"', '"Dockerfile"'));
console.log('(*) Removing base.Dockerfile...');
await asyncUtils.rimraf(dockerFilePath);
} else {
await prep.createStub(
dotDevContainerPath, definitionId, repo, release, baseDockerFileExists, stubRegistry, stubRegistryPath);
}
console.log('(*) Done!\n');
}
module.exports = {
push: push
}

148
build/src/utils/async.js Normal file
Просмотреть файл

@ -0,0 +1,148 @@
/*--------------------------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
*-------------------------------------------------------------------------------------------------------------*/
const fs = require('fs');
const https = require('https');
const crypto = require('crypto');
const rimrafCb = require('rimraf');
const mkdirpCb = require('mkdirp');
const copyFilesCb = require('copyfiles');
const spawnCb = require('child_process').spawn;
module.exports = {
// async forEach
forEach: async (array, cb) => {
for (let i = 0; i < array.length; i++) {
await cb(array[i], i, array);
}
},
// async spawn
spawn: async (command, args, opts) => {
console.log(`(*) Spawn: ${command}${args.reduce((prev, current) => `${prev} ${current}`, '')}`);
opts = opts || { stdio: 'inherit', shell: true };
return new Promise((resolve, reject) => {
let result = '';
let errorOutput = '';
const proc = spawnCb(command, args, opts);
proc.on('close', (code, signal) => {
if (code !== 0) {
console.log(result);
console.error(errorOutput);
reject(`Non-zero exit code: ${code} ${signal || ''}`);
return;
}
resolve(result);
});
if (proc.stdout) {
proc.stdout.on('data', (chunk) => result += chunk.toString());
}
if (proc.stderr) {
proc.stderr.on('data', (chunk) => result += chunk.toString());
}
proc.on('error', reject);
});
},
// async rename
rename: async (from, to) => {
return new Promise((resolve, reject) => {
fs.rename(from, to, (err) => err ? reject(err) : resolve());
});
},
// async readFile
readFile: async (filePath) => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, data) => err ? reject(err) : resolve(data.toString()));
});
},
// async writeFile
writeFile: async function (filePath, data) {
return new Promise((resolve, reject) => {
fs.writeFile(filePath, data, 'utf8', (err) => err ? reject(err) : resolve(filePath));
});
},
// async mkdirp
mkdirp: async (pathToMake) => {
return new Promise((resolve, reject) => {
mkdirpCb(pathToMake, (err, made) => err ? reject(err) : resolve(made));
});
},
// async rimraf
rimraf: async (pathToRemove, opts) => {
opts = opts || {};
return new Promise((resolve, reject) => {
rimrafCb(pathToRemove, opts, (err) => err ? reject(err) : resolve(pathToRemove));
});
},
// async copyfiles
copyFiles: async (source, blobs, target) => {
return new Promise((resolve, reject) => {
process.chdir(source);
copyFilesCb(
blobs.concat(target),
{ all: true },
(err) => err ? reject(err) : resolve(target));
});
},
// async readdir
readdir: async (dirPath, opts) => {
opts = opts || {};
return new Promise((resolve, reject) => {
fs.readdir(dirPath, opts, (err, files) => err ? reject(err) : resolve(files));
});
},
// async exists
exists: async (filePath) => {
return fs.existsSync(filePath);
},
// async gen SHA 256 hash for file
shaForFile: async (filePath) => {
return new Promise((resolve, reject) => {
const fd = fs.createReadStream(filePath);
const hash = crypto.createHash('sha256');
hash.setEncoding('hex');
fd.on('end', function () {
hash.end();
resolve(hash.read());
});
fd.on('error', (err) => {
reject(err);
});
fd.pipe(hash);
})
},
// async gen SHA 256 hash for string
shaForString: async (content) => {
const hash = crypto.createHash('sha256');
hash.update(content);
return hash.digest('hex');
},
// async HTTPS get
getUrlAsString: async (url) => {
return new Promise((resolve, reject) => {
let content = '';
const req = https.get(url, function (res) {
res.on('data', function (chunk) {
content += chunk.toString();
});
});
req.on("error", reject);
req.on('close', () => resolve(content));
});
}
};

251
build/src/utils/config.js Normal file
Просмотреть файл

@ -0,0 +1,251 @@
/*--------------------------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
*-------------------------------------------------------------------------------------------------------------*/
const os = require('os');
const path = require('path');
const asyncUtils = require('./async');
const jsonc = require('jsonc').jsonc;
const config = require('../../config.json');
config.definitionDependencies = config.definitionDependencies || {};
config.definitionBuildSettings = config.definitionBuildSettings || {};
const stagingFolders = {};
const definitionTagLookup = {};
// Must be called first
async function loadConfig(repoPath) {
repoPath = repoPath || path.join(__dirname, '..', '..', '..');
const containersPath = path.join(repoPath, getConfig('containersPathInRepo', 'containers'));
const definitions = await asyncUtils.readdir(containersPath, { withFileTypes: true });
await asyncUtils.forEach(definitions, async (definitionFolder) => {
if (!definitionFolder.isDirectory()) {
return;
}
const definitionId = definitionFolder.name;
const possibleDefinitionBuildJson = path.join(containersPath, definitionId, getConfig('definitionBuildConfigFile', 'definition-build.json'));
if (await asyncUtils.exists(possibleDefinitionBuildJson)) {
const buildJson = await jsonc.read(possibleDefinitionBuildJson);
if (buildJson.build) {
config.definitionBuildSettings[definitionId] = buildJson.build;
}
if (buildJson.dependencies) {
config.definitionDependencies[definitionId] = buildJson.dependencies;
}
}
});
// Populate tag lookup
for (let definitionId in config.definitionBuildSettings) {
if (config.definitionBuildSettings[definitionId].tags) {
const blankTagList = getTagsForVersion(definitionId, '', 'ANY', 'ANY');
blankTagList.forEach((blankTag) => {
definitionTagLookup[blankTag] = definitionId;
});
const devTagList = getTagsForVersion(definitionId, 'dev', 'ANY', 'ANY');
devTagList.forEach((devTag) => {
definitionTagLookup[devTag] = definitionId;
});
}
}
}
// Get a value from the config file or a similarly named env var
function getConfig(property, defaultVal) {
defaultVal = defaultVal || null;
// Generate env var name from property - camelCase to CAMEL_CASE
const envVar = property.split('').reduce((prev, next) => {
if (next >= 'A' && next <= 'Z') {
return prev + '_' + next;
} else {
return prev + next.toLocaleUpperCase();
}
}, '');
return process.env[envVar] || config[property] || defaultVal;
}
// Convert a release string (v1.0.0) or branch (master) into a version
function getVersionFromRelease(release) {
// Already is a version
if (!isNaN(parseInt(release.charAt(0)))) {
return release;
}
// Is a release string
if (release.charAt(0) === 'v' && !isNaN(parseInt(release.charAt(1)))) {
return release.substr(1);
}
// Is a branch
return 'dev';
}
// Look up distro and fallback to debian if not specified
function getLinuxDistroForDefinition(definitionId) {
return config.definitionBuildSettings[definitionId].rootDistro || 'debian';
}
// Generate 'latest' flavor of a given definition's tag
function getLatestTag(definitionId, registry, registryPath) {
if (typeof config.definitionBuildSettings[definitionId] === 'undefined') {
return null;
}
return config.definitionBuildSettings[definitionId].tags.reduce((list, tag) => {
list.push(`${registry}/${registryPath}/${tag.replace(/:.+/, ':latest')}`);
return list;
}, []);
}
// Create all the needed variants of the specified version identifier for a given definition
function getTagsForVersion(definitionId, version, registry, registryPath) {
if (typeof config.definitionBuildSettings[definitionId] === 'undefined') {
return null;
}
return config.definitionBuildSettings[definitionId].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.
const baseTag = tag.replace('${VERSION}', version).replace(':-', ':');
if (baseTag.charAt(baseTag.length - 1) !== ':') {
list.push(`${registry}/${registryPath}/${baseTag}`);
}
return list;
}, []);
}
// Generate complete list of tags for a given definition
function getTagList(definitionId, release, updateLatest, registry, registryPath) {
const version = getVersionFromRelease(release);
if (version === 'dev') {
return getTagsForVersion(definitionId, 'dev', registry, registryPath);
}
const versionParts = version.split('.');
if (versionParts.length !== 3) {
throw (`Invalid version format in ${version}.`);
}
const versionList = updateLatest ? [
version,
`${versionParts[0]}.${versionParts[1]}`,
`${versionParts[0]}`,
'' // This is the equivalent of latest for qualified tags- e.g. python:3 instead of python:0.35.0-3
] : [
version,
`${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) : [];
versionList.forEach((tagVersion) => {
tagList = tagList.concat(getTagsForVersion(definitionId, tagVersion, registry, registryPath));
});
return tagList;
}
// Walk the image build config and sort list so parents build before children
function getSortedDefinitionBuildList() {
const sortedList = [];
const settingsCopy = JSON.parse(JSON.stringify(config.definitionBuildSettings));
for (let definitionId in config.definitionBuildSettings) {
const add = (defId) => {
if (typeof settingsCopy[defId] === 'object') {
add(settingsCopy[defId].parent);
sortedList.push(defId);
settingsCopy[defId] = undefined;
}
}
add(definitionId);
}
return sortedList;
}
// Get parent tag for a given child definition
function getParentTagForVersion(definitionId, version, registry, registryPath) {
const parentId = config.definitionBuildSettings[definitionId].parent;
return parentId ? getTagsForVersion(parentId, version, registry, registryPath)[0] : null;
}
function getUpdatedTag(currentTag, currentRegistry, currentRegistryPath, updatedVersion, updatedRegistry, updatedRegistryPath) {
updatedRegistry = updatedRegistry || currentRegistry;
updatedRegistryPath = updatedRegistryPath || currentRegistryPath;
const captureGroups = new RegExp(`${currentRegistry}/${currentRegistryPath}/(.+:.+)`).exec(currentTag);
const updatedTags = getTagsForVersion(definitionTagLookup[`ANY/ANY/${captureGroups[1]}`], updatedVersion, updatedRegistry, updatedRegistryPath);
if (updatedTags && updatedTags.length > 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,
// we won't get an updated tag returned, so we'll just reuse the current tag.
return currentTag;
}
// Return just the manor and minor version of a release number
function majorMinorFromRelease(release) {
const version = getVersionFromRelease(release);
if (version === 'dev') {
return 'dev';
}
const versionParts = version.split('.');
return `${versionParts[0]}.${versionParts[1]}`;
}
// Return an object from a map based on the linux distro for the definition
function objectByDefinitionLinuxDistro(definitionId, objectsByDistro) {
const distro = getLinuxDistroForDefinition(definitionId);
const obj = objectsByDistro[distro];
return obj;
}
function getDefinitionDependencies(definitionId) {
return config.definitionDependencies[definitionId];
}
function getAllDependencies() {
return config.definitionDependencies;
}
async function getStagingFolder(release) {
if (!stagingFolders[release]) {
const stagingFolder = path.join(os.tmpdir(), 'vscode-dev-containers', release);
console.log(`(*) Copying files to ${stagingFolder}\n`);
await asyncUtils.rimraf(stagingFolder); // Clean out folder if it exists
await asyncUtils.mkdirp(stagingFolder); // Create the folder
await asyncUtils.copyFiles(
path.resolve(__dirname, '..', '..', '..'),
getConfig('filesToStage'),
stagingFolder);
stagingFolders[release] = stagingFolder;
}
return stagingFolders[release];
}
module.exports = {
loadConfig: loadConfig,
getTagList: getTagList,
getSortedDefinitionBuildList: getSortedDefinitionBuildList,
getParentTagForVersion: getParentTagForVersion,
getUpdatedTag: getUpdatedTag,
majorMinorFromRelease: majorMinorFromRelease,
objectByDefinitionLinuxDistro: objectByDefinitionLinuxDistro,
getDefinitionDependencies: getDefinitionDependencies,
getAllDependencies: getAllDependencies,
getStagingFolder: getStagingFolder,
getLinuxDistroForDefinition: getLinuxDistroForDefinition,
getVersionFromRelease: getVersionFromRelease,
getTagsForVersion: getTagsForVersion,
getConfig: getConfig
};

202
build/vscdc Executable file
Просмотреть файл

@ -0,0 +1,202 @@
#!/usr/bin/env node
/*--------------------------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
*-------------------------------------------------------------------------------------------------------------*/
const push = require('./src/push').push;
const package = require('./src/package').package;
const createStub = require('./src/prep').createStub;
const generateComponentGovernanceManifest = require('./src/cgmanifest').generateComponentGovernanceManifest;
const configUtils = require('./src/utils/config');
const packageJson = require('../package.json');
console.log('vscode-dev-containers CLI\nCopyright (c) Microsoft Corporation. All rights reserved.\n')
require('yargs')
.command('pack', 'package dev container definitions', (yargs) => {
yargs
.options({
'release': {
describe: 'vscode-dev-containers release tag or a branch',
default: `v${packageJson.version}`
},
'registry': {
describe: 'container registry to push images to',
default: configUtils.getConfig('containerRegistry', 'docker.io')
},
'registry-path': {
describe: 'container registry path',
default: configUtils.getConfig('containerRegistryPath', 'vscode/devcontainers')
},
'stub-registry': {
describe: 'registry to add to stub',
default: configUtils.getConfig('stubRegistry', configUtils.getConfig('containerRegistry', 'docker.io'))
},
'stub-registry-path': {
describe: 'stub registry path',
default: configUtils.getConfig('stubRegistryPath', configUtils.getConfig('containerRegistryPath', ''))
},
'github-repo': {
describe: 'vscode-dev-containers repo name',
default: configUtils.getConfig('githubRepoName', 'microsoft/vscode-dev-containers')
},
'push-images': {
describe: 'whether to push before packaging',
type: 'boolean',
default: true
},
'update-latest': {
describe: 'whether to tag latest and {MAJOR}',
type: 'boolean',
default: true
},
'clean': {
describe: 'whether to clean up staging folder when done',
type: 'boolean',
default: true
},
'simulate': {
describe: 'whether to simulate a push instead of doing it',
type: 'boolean',
default: false
}
})
}, packCommand)
.command('push [devcontainer]', 'push dev container images to a repository', (yargs) => {
yargs
.positional('devcontainer', {
describe: 'ID of dev container to push',
default: null
})
.options({
'release': {
describe: 'vscode-dev-containers release tag or branch',
default: `v${packageJson.version}`
},
'registry': {
describe: 'container registry to push images to',
default: configUtils.getConfig('containerRegistry', 'docker.io')
},
'registry-path': {
describe: 'container registry path',
default: configUtils.getConfig('containerRegistryPath', '')
},
'stub-registry': {
describe: 'registry to add to stub',
default: configUtils.getConfig('stubRegistry', configUtils.getConfig('containerRegistry', 'docker.io'))
},
'stub-registry-path': {
describe: 'stub registry path',
default: configUtils.getConfig('stubRegistryPath', configUtils.getConfig('containerRegistryPath', ''))
},
'github-repo': {
describe: 'vscode-dev-containers repo name',
default: configUtils.getConfig('githubRepoName', 'microsoft/vscode-dev-containers')
},
'update-latest': {
describe: 'whether to tag latest and {MAJOR} if pushing',
type: 'boolean',
default: true
},
'simulate': {
describe: 'whether to simulate a push instead of doing it',
type: 'boolean',
default: false
}
})
}, pushCommand)
.command('stub <devcontainer> [path]', 'generates a stub user.Dockerfile', (yargs) => {
yargs
.positional('devcontainer', {
describe: 'ID of dev container to stub',
})
.positional('path', {
describe: 'path to .devcontainer folder',
default: '.'
})
.options({
'release': {
describe: 'vscode-dev-containers release tag or branch',
default: 'dev'
},
'stub-registry': {
describe: 'registry to add to stub',
default: configUtils.getConfig('stubRegistry', configUtils.getConfig('containerRegistry', 'docker.io'))
},
'stub-registry-path': {
describe: 'stub registry path',
default: configUtils.getConfig('stubRegistryPath', configUtils.getConfig('containerRegistryPath', ''))
},
'github-repo': {
describe: 'vscode-dev-containers repo name',
default: configUtils.getConfig('githubRepoName', 'microsoft/vscode-dev-containers')
},
'has-base-dockerfile': {
describe: 'whether base.Dockerfile exists',
type: 'boolean',
default: true
}
})
}, stubCommand)
.command('cg', 'generate cgmanifest.json', (yargs) => {
yargs
.options({
'release': {
describe: 'vscode-dev-containers release tag or branch',
default: 'master'
},
'registry': {
describe: 'container registry to push images to',
default: configUtils.getConfig('containerRegistry', 'docker.io')
},
'registry-path': {
describe: 'container registry path',
default: configUtils.getConfig('containerRegistryPath', '')
},
'github-repo': {
describe: 'vscode-dev-containers repo name',
default: configUtils.getConfig('vscodeDevContainersRepo', 'https://github.com/microsoft/vscode-dev-containers')
},
'build': {
describe: 'whether to skip the image build step',
default: true
}
})
}, cgCommand)
.demandCommand()
.help()
.argv;
function pushCommand(argv) {
push(argv.githubRepo, argv.release, argv.updateLatest, argv.registry, argv.registryPath, argv.stubRegistry, argv.stubRegistryPath, argv.simulate, argv.devcontainer)
.catch((reason) => {
console.error(`(!) Push failed - ${reason}`);
process.exit(1);
});
}
function packCommand(argv) {
package(argv.githubRepo, argv.release, argv.updateLatest, argv.registry, argv.registryPath, argv.stubRegistry, argv.stubRegistryPath, argv.pushImages, argv.clean, argv.simulate)
.catch((reason) => {
console.error(`(!) Packaging failed - ${reason}`);
process.exit(1);
});
}
function stubCommand(argv) {
createStub(argv.devcontainer, argv.path, argv.githubRepo, argv.release, argv.hasBaseDockerfile, argv.stubRegistry, argv.stubRegistryPath)
.catch((reason) => {
console.error(`(!) Stub generation failed - ${reason}`);
process.exit(1);
});
}
function cgCommand(argv) {
generateComponentGovernanceManifest(argv.githubRepo, argv.release, argv.registry, argv.registryPath, argv.build)
.catch((reason) => {
console.error(`(!) Component governance manifest generation failed - ${reason}`);
process.exit(1);
});
}

1
build/vscdc.cmd Normal file
Просмотреть файл

@ -0,0 +1 @@
@node vscdc %@

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

@ -1,255 +1,5 @@
{
"Registrations": [
{
"Component": {
"Type": "other",
"Other": {
"Name": "Docker Image: debian",
"Version": "9",
"DownloadUrl": "https://hub.docker.com/_/debian"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: apt-transport-https",
"Version": "1.4.9",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-transport-https_1.4.9_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: apt-utils",
"Version": "1.4.9",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-utils_1.4.9_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: ca-certificates",
"Version": "20161130+nmu1+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/ca-certificates/ca-certificates_20161130+nmu1+deb9u1_all.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: curl",
"Version": "7.52.1-5+deb9u9",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/curl/curl_7.52.1-5+deb9u9_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: dialog",
"Version": "1.3-20160828-2",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/d/dialog/dialog_1.3-20160828-2_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: git",
"Version": "1:2.11.0-3+deb9u4",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/git/git_2.11.0-3+deb9u4_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: iproute2",
"Version": "4.9.0-1+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/iproute2/iproute2_4.9.0-1+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libc6",
"Version": "2.24-11+deb9u4",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/glibc/libc6_2.24-11+deb9u4_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libgcc1",
"Version": "1:6.3.0-18+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libgcc1_6.3.0-18+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libgssapi-krb5-2",
"Version": "1.15-1+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/k/krb5/libgssapi-krb5-2_1.15-1+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libicu57",
"Version": "57.1-6+deb9u3",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/icu/libicu57_57.1-6+deb9u3_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: liblttng-ust0",
"Version": "2.9.0-2+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/ust/liblttng-ust0_2.9.0-2+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libssl1.0.2",
"Version": "1.0.2t-1~deb9u1",
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl1.0/libssl1.0.2_1.0.2t-1~deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libssl1.1",
"Version": "1.1.0l-1~deb9u1",
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.1_1.1.0l-1~deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libstdc++6",
"Version": "6.3.0-18+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libstdc++6_6.3.0-18+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: lsb-release",
"Version": "9.20161125",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/l/lsb/lsb-release_9.20161125_all.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: procps",
"Version": "2:3.3.12-3+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/p/procps/procps_3.3.12-3+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: sudo",
"Version": "1.8.19p1-2.1+deb9u1",
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/s/sudo/sudo_1.8.19p1-2.1+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: unzip",
"Version": "6.0-21+deb9u2",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/unzip/unzip_6.0-21+deb9u2_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: wget",
"Version": "1.18-5+deb9u3",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/w/wget/wget_1.18-5+deb9u3_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: zlib1g",
"Version": "1:1.2.8.dfsg-5",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zlib/zlib1g_1.2.8.dfsg-5_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: zsh",
"Version": "5.3.1-4+b3",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zsh/zsh_5.3.1-4+b3_amd64.deb"
}
}
},
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Docker Image: ubuntu",
"Version": "18.04",
"DownloadUrl": "https://hub.docker.com/_/ubuntu"
}
}
},
{
"Component": {
"Type": "other",
@ -265,8 +15,8 @@
"Type": "other",
"Other": {
"Name": "Alpine Package: git",
"Version": "2.22.0-r0",
"DownloadUrl": "http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/git-2.22.0-r0.apk"
"Version": "2.22.2-r0",
"DownloadUrl": "http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/git-2.22.2-r0.apk"
}
}
},
@ -386,7 +136,7 @@
"Other": {
"Name": "Alpine Package: libssl1.1",
"Version": "1.1.1d-r0",
"DownloadUrl": "http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/libssl1.1-1.1.1d-r0.apk"
"DownloadUrl": "1.1.1d-r2:/x86_64/libssl1.1-1.1.1d-r0.apk"
}
}
},
@ -460,6 +210,246 @@
}
}
},
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Docker Image: debian",
"Version": "9",
"DownloadUrl": "https://hub.docker.com/_/debian"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: apt-transport-https",
"Version": "1.4.9",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-transport-https_1.4.9_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: apt-utils",
"Version": "1.4.9",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/a/apt/apt-utils_1.4.9_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: ca-certificates",
"Version": "20161130+nmu1+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/ca-certificates/ca-certificates_20161130+nmu1+deb9u1_all.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: curl",
"Version": "7.52.1-5+deb9u9",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/c/curl/curl_7.52.1-5+deb9u9_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: dialog",
"Version": "1.3-20160828-2",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/d/dialog/dialog_1.3-20160828-2_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: git",
"Version": "1:2.11.0-3+deb9u5",
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/g/git/git_2.11.0-3+deb9u5_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: iproute2",
"Version": "4.9.0-1+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/iproute2/iproute2_4.9.0-1+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libc6",
"Version": "2.24-11+deb9u4",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/glibc/libc6_2.24-11+deb9u4_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libgcc1",
"Version": "1:6.3.0-18+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libgcc1_6.3.0-18+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libgssapi-krb5-2",
"Version": "1.15-1+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/k/krb5/libgssapi-krb5-2_1.15-1+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libicu57",
"Version": "57.1-6+deb9u3",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/i/icu/libicu57_57.1-6+deb9u3_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: liblttng-ust0",
"Version": "2.9.0-2+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/ust/liblttng-ust0_2.9.0-2+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libssl1.0.2",
"Version": "1.0.2u-1~deb9u1",
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl1.0/libssl1.0.2_1.0.2u-1~deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libssl1.1",
"Version": "1.1.0l-1~deb9u1",
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.1_1.1.0l-1~deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: libstdc++6",
"Version": "6.3.0-18+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/g/gcc-6/libstdc++6_6.3.0-18+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: lsb-release",
"Version": "9.20161125",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/l/lsb/lsb-release_9.20161125_all.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: procps",
"Version": "2:3.3.12-3+deb9u1",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/p/procps/procps_3.3.12-3+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: sudo",
"Version": "1.8.19p1-2.1+deb9u1",
"DownloadUrl": "http://security.debian.org/debian-security/pool/updates/main/s/sudo/sudo_1.8.19p1-2.1+deb9u1_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: unzip",
"Version": "6.0-21+deb9u2",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/u/unzip/unzip_6.0-21+deb9u2_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: wget",
"Version": "1.18-5+deb9u3",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/w/wget/wget_1.18-5+deb9u3_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: zlib1g",
"Version": "1:1.2.8.dfsg-5",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zlib/zlib1g_1.2.8.dfsg-5_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Debian Package: zsh",
"Version": "5.3.1-4+b3",
"DownloadUrl": "http://deb.debian.org/debian/pool/main/z/zsh/zsh_5.3.1-4+b3_amd64.deb"
}
}
},
{
"Component": {
"Type": "other",
@ -475,8 +465,8 @@
"Type": "other",
"Other": {
"Name": "Debian Package: yarn",
"Version": "1.19.1-1",
"DownloadUrl": "https://dl.yarnpkg.com/debian/pool/main/y/yarn/yarn_1.19.1_all.deb"
"Version": "1.21.1-1",
"DownloadUrl": "https://dl.yarnpkg.com/debian/pool/main/y/yarn/yarn_1.21.1_all.deb"
}
}
},
@ -485,7 +475,7 @@
"Type": "npm",
"Npm": {
"Name": "eslint",
"Version": "6.6.0"
"Version": "6.8.0"
}
}
},
@ -513,7 +503,17 @@
"Type": "npm",
"Npm": {
"Name": "typescript",
"Version": "3.7.2"
"Version": "3.7.4"
}
}
},
{
"Component": {
"Type": "other",
"Other": {
"Name": "Docker Image: ubuntu",
"Version": "18.04",
"DownloadUrl": "https://hub.docker.com/_/ubuntu"
}
}
}

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

@ -0,0 +1,11 @@
# Development Container Contribution Templates
This folder contains a set of templates that you can use to contribute a new development container to this repository. See [CONTRIBUTING.md](../CONTRIBUTING.md) for details on contributing a container.
If you are looking for a list of dev container definitions that are included in the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension, see the [containers](../containers) folder instead.
## License
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See [LICENSE](https://github.com/Microsoft/vscode-dev-containers/blob/master/LICENSE)

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

@ -13,32 +13,39 @@ FROM debian:9
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
# The node image includes a non-root user with sudo access. Use the
# "remoteUser" property in devcontainer.json to use it. On Linux, update
# these values to ensure the container user's UID/GID matches your local values.
# 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
# will be updated to match your local UID/GID (when using the dockerFile property).
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
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 2>&1 \
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
#
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
&& apt-get -y install git iproute2 procps lsb-release \
# 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/ash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
&& rm /tmp/common-setup.sh \
#
# *****************************************************
# * Add steps for installing needed dependencies here *
# *****************************************************
#
# Create a non-root user
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# [Optional] Add sudo support for the non-root user
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME \
# *********************************************************************
# * Uncomment this section to use RUN to install other dependencies. *
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
# *********************************************************************
# && apt-get -y install --no-reccomends <your-package-name-here>
#
# Clean up
&& apt-get autoremove -y \
@ -46,5 +53,5 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=
ENV DEBIAN_FRONTEND=dialog

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

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

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

@ -2,7 +2,6 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM debian:9
# Avoid warnings by switching to noninteractive
@ -16,24 +15,31 @@ ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
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 2>&1 \
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
#
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
&& apt-get -y install git iproute2 procps lsb-release \
# 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/ash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
&& rm /tmp/common-setup.sh \
#
# *****************************************************
# * Add steps for installing needed dependencies here *
# *****************************************************
#
# Create a non-root user
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# [Optional] Add sudo support for the non-root user
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME \
# *********************************************************************
# * Uncomment this section to use RUN to install other dependencies. *
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
# *********************************************************************
# && apt-get -y install --no-reccomends <your-package-list-here>
#
# Clean up
&& apt-get autoremove -y \
@ -41,4 +47,5 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=
ENV DEBIAN_FRONTEND=dialog

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

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

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

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

13
containers/README.md Normal file
Просмотреть файл

@ -0,0 +1,13 @@
# Development Container Definitions
This folder contains a set of development container configuration files or "definitions" that are included with the [Remote - Containers](https://aka.ms/vscode-remote/download/containers) extension. This list is presented when you open a folder in a container that does not already have a `.devcontainer.json` or `.devcontainer/devcontainer.json` file in it.
Each folder contains a README with more details on the contents of the definition and how to use it.
See [CONTRIBUTING.md](../CONTRIBUTING.md) for details on contributing to this repository.
## License
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See [LICENSE](https://github.com/Microsoft/vscode-dev-containers/blob/master/LICENSE)

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

@ -12,13 +12,19 @@ ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-alpine.sh"
ARG COMMON_SCRIPT_SHA="dev-mode"
# Install git, bash, dependencies, and add a non-root user
RUN apk add --no-cache git bash libgcc libstdc++ \
RUN apk update \
&& apk add --no-cache wget coreutils ca-certificates \
#
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
&& addgroup -g $USER_GID $USERNAME \
&& adduser -S -s /bin/bash -u $USER_UID -G $USERNAME $USERNAME \
# [Optional] Add sudo support for the non-root user
&& apk add --no-cache sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME
# 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/ash /tmp/common-setup.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
&& rm /tmp/common-setup.sh

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

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

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

@ -0,0 +1,46 @@
{
"build": {
"rootDistro": "alpine",
"tags": [
"base:${VERSION}-alpine-3.10"
]
},
"dependencies": {
"image": "alpine:3.10",
"imageLink": "https://hub.docker.com/_/alpine",
"alpine": [
"git",
"bash",
"libgcc",
"libstdc++",
"curl",
"wget",
"unzip",
"procps",
"coreutils",
"ca-certificates",
"krb5-libs",
"libintl",
"libssl1.1",
"lttng-ust",
"tzdata",
"userspace-rcu",
"zlib",
"shadow",
"sudo",
"zsh"
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -15,20 +15,25 @@ ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
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 2>&1 \
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
#
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
&& apt-get -y install git iproute2 procps lsb-release \
#
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# [Optional] Add sudo support for the non-root user
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME \
# 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" \
&& rm /tmp/common-setup.sh \
#
# Clean up
&& apt-get autoremove -y \

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

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

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

@ -0,0 +1,50 @@
{
"build": {
"latest": true,
"rootDistro": "debian",
"tags": [
"base:${VERSION}-debian-9",
"base:${VERSION}-stretch"
]
},
"dependencies": {
"image": "debian:9",
"imageLink": "https://hub.docker.com/_/debian",
"debian": [
"apt-utils",
"dialog",
"ca-certificates",
"git",
"iproute2",
"procps",
"curl",
"wget",
"unzip",
"lsb-release",
"apt-transport-https",
"libc6",
"libgcc1",
"libgssapi-krb5-2",
"libicu57",
"liblttng-ust0",
"libssl1.1",
"libstdc++6",
"zlib1g",
"libssl1.0.2",
"sudo",
"zsh"
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -16,7 +16,7 @@ ARG USER_GID=$USER_UID
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# [Optional] Add sudo support for the non-root user
&& yum install -y sudo \
&& yum install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME

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

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

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

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

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

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

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

@ -16,12 +16,25 @@ ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
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 2>&1 \
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
#
# Verify git and needed tools are installed
&& apt-get -y install git iproute2 procps \
# 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" \
&& rm /tmp/common-setup.sh \
#
# Remove outdated yarn from /opt and install via package
# so it can be easily updated via apt-get upgrade yarn
@ -37,17 +50,6 @@ RUN apt-get update \
# Install eslint globally
&& npm install -g eslint \
#
# [Optional] Update a non-root user to UID/GID if needed.
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi \
# [Optional] Add add sudo support for non-root user
&& apt-get install -y sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \

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

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

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

@ -0,0 +1,51 @@
{
"build": {
"rootDistro": "debian",
"tags": [
"javascript-node:${VERSION}-10"
]
},
"dependencies": {
"image": "node:10",
"imageLink": "https://hub.docker.com/_/node",
"debian": [
"apt-utils",
"dialog",
"ca-certificates",
"git",
"iproute2",
"procps",
"curl",
"wget",
"unzip",
"lsb-release",
"apt-transport-https",
"libc6",
"libgcc1",
"libgssapi-krb5-2",
"libicu57",
"libssl1.1",
"libstdc++6",
"zlib1g",
"libssl1.0.2",
"sudo",
"yarn",
"zsh"
],
"npm": [
"eslint"
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

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

@ -3,10 +3,7 @@
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM node:12
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:12
# The node image includes a non-root user with sudo access. Use the
# "remoteUser" property in devcontainer.json to use it. On Linux, update
@ -16,42 +13,27 @@ ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Configure apt and install packages
RUN apt-get update \
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
#
# Verify git and needed tools are installed
&& apt-get -y install git iproute2 procps \
#
# Remove outdated yarn from /opt and install via package
# so it can be easily updated via apt-get upgrade yarn
&& rm -rf /opt/yarn-* \
&& rm -f /usr/local/bin/yarn \
&& rm -f /usr/local/bin/yarnpkg \
&& apt-get install -y curl apt-transport-https lsb-release \
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends yarn \
#
# Install eslint globally
&& npm install -g eslint \
#
# [Optional] Update a non-root user to UID/GID if needed.
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
# [Optional] Update UID/GID if needed
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi \
# [Optional] Add add sudo support for non-root user
&& apt-get install -y sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
&& chmod -R $USER_UID:$USER_GID /home/$USERNAME; \
fi
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog
# *************************************************************
# * Uncomment this section to use RUN instructions to install *
# * any needed dependencies after executing "apt-get update". *
# * See https://docs.docker.com/engine/reference/builder/#run *
# *************************************************************
# ENV DEBIAN_FRONTEND=noninteractive
# RUN apt-get update \
# && apt-get -y install --no-reccomends <your-package-list-here> \
# #
# # Clean up
# && apt-get autoremove -y \
# && apt-get clean -y \
# && rm -rf /var/lib/apt/lists/*
# ENV DEBIAN_FRONTEND=dialog
# Uncomment to default to non-root user
# USER $USER_UID

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

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

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

@ -3,10 +3,7 @@
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM node:12
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:12
# The node image includes a non-root user with sudo access. Use the
# "remoteUser" property in devcontainer.json to use it. On Linux, update
@ -16,42 +13,27 @@ ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Configure apt and install packages
RUN apt-get update \
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
#
# Verify git and needed tools are installed
&& apt-get -y install git iproute2 procps \
#
# Remove outdated yarn from /opt and install via package
# so it can be easily updated via apt-get upgrade yarn
&& rm -rf /opt/yarn-* \
&& rm -f /usr/local/bin/yarn \
&& rm -f /usr/local/bin/yarnpkg \
&& apt-get install -y curl apt-transport-https lsb-release \
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends yarn \
#
# Install eslint globally
&& npm install -g eslint \
#
# [Optional] Update a non-root user to UID/GID if needed.
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
# [Optional] Update UID/GID if needed
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi \
# [Optional] Add add sudo support for non-root user
&& apt-get install -y sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
&& chmod -R $USER_UID:$USER_GID /home/$USERNAME; \
fi
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog
# *************************************************************
# * Uncomment this section to use RUN instructions to install *
# * any needed dependencies after executing "apt-get update". *
# * See https://docs.docker.com/engine/reference/builder/#run *
# *************************************************************
# ENV DEBIAN_FRONTEND=noninteractive
# RUN apt-get update \
# && apt-get -y install --no-reccomends <your-package-list-here> \
# #
# # Clean up
# && apt-get autoremove -y \
# && apt-get clean -y \
# && rm -rf /var/lib/apt/lists/*
# ENV DEBIAN_FRONTEND=dialog
# Uncomment to default to non-root user
# USER $USER_UID

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

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

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

@ -16,12 +16,25 @@ ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
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 2>&1 \
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
#
# Verify git and needed tools are installed
&& apt-get -y install git iproute2 procps \
# 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" \
&& rm /tmp/common-setup.sh \
#
# Remove outdated yarn from /opt and install via package
# so it can be easily updated via apt-get upgrade yarn
@ -37,17 +50,6 @@ RUN apt-get update \
# Install eslint globally
&& npm install -g eslint \
#
# [Optional] Update a non-root user to UID/GID if needed.
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi \
# [Optional] Add add sudo support for non-root user
&& apt-get install -y sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \

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

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

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

@ -0,0 +1,52 @@
{
"build": {
"latest": true,
"rootDistro": "debian",
"tags": [
"javascript-node:${VERSION}-12"
]
},
"dependencies": {
"image": "node:12",
"imageLink": "https://hub.docker.com/_/node",
"debian": [
"apt-utils",
"dialog",
"ca-certificates",
"git",
"iproute2",
"procps",
"curl",
"wget",
"unzip",
"lsb-release",
"apt-transport-https",
"libc6",
"libgcc1",
"libgssapi-krb5-2",
"libicu57",
"libssl1.1",
"libstdc++6",
"zlib1g",
"libssl1.0.2",
"sudo",
"yarn",
"zsh"
],
"npm": [
"eslint"
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,5 +1,7 @@
README.md
.vscode
test-project
definition-build.json
.vscode
.npmignore
Cargo.lock
Cargo.toml

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

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

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

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

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

@ -3,55 +3,43 @@
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM node:10
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:10
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
# The node image includes 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
# will be updated to match your local UID/GID (when using the dockerFile property).
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
# The javascript-node image includes a non-root node user with sudo access. Use
# the "remoteUser" property in devcontainer.json to use it. On Linux, the container
# user's GID/UIDs will be updated to match your local UID/GID when using the image
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
# dockerComposeFile property or want the image itself to start with different ID
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Configure apt and install packages
RUN apt-get update \
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
#
# Verify git and needed tools are installed
&& apt-get -y install git iproute2 procps \
#
# Remove outdated yarn from /opt and install via package
# so it can be easily updated via apt-get upgrade yarn
&& rm -rf /opt/yarn-* \
&& rm -f /usr/local/bin/yarn \
&& rm -f /usr/local/bin/yarnpkg \
&& apt-get install -y curl apt-transport-https lsb-release \
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends yarn \
#
# Install tslint and typescript globally
&& npm install -g tslint eslint typescript \
#
# [Optional] Update a non-root user to UID/GID if needed.
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
# Alter node user as needed, install tslint, typescript. eslint is installed by javascript image
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi \
# [Optional] Add add sudo support for non-root user
&& apt-get install -y sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
# Install tslint, typescript. eslint is installed by javascript image
&& npm install -g tslint typescript
# *********************************************************************
# * Uncomment this section to use RUN to install other dependencies. *
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
# *********************************************************************
# ENV DEBIAN_FRONTEND=noninteractive
# RUN apt-get update \
# && apt-get -y install --no-reccomends <your-package-list-here> \
# #
# # Clean up
# && apt-get autoremove -y \
# && apt-get clean -y \
# && rm -rf /var/lib/apt/lists/*
# ENV DEBIAN_FRONTEND=dialog
# Uncomment to default to non-root user
# USER $USER_UID
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog

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

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

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

@ -0,0 +1,56 @@
{
"build": {
"latest": true,
"rootDistro": "debian",
"parent": "javascript-node-10",
"tags": [
"typescript-node:${VERSION}-10"
]
},
"dependencies": {
"image": "node:10",
"imageLink": "https://hub.docker.com/_/node",
"debian": [
"apt-utils",
"dialog",
"ca-certificates",
"git",
"iproute2",
"procps",
"curl",
"wget",
"unzip",
"lsb-release",
"apt-transport-https",
"libc6",
"libgcc1",
"libgssapi-krb5-2",
"libicu57",
"libssl1.1",
"libstdc++6",
"zlib1g",
"libssl1.0.2",
"sudo",
"yarn",
"zsh"
],
"npm": [
"eslint",
"tslint",
"typescript"
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

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

@ -3,55 +3,42 @@
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
FROM node:12
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:12
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
# The node image includes 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
# will be updated to match your local UID/GID (when using the dockerFile property).
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
# The javascript-node image includes a non-root node user with sudo access. Use
# the "remoteUser" property in devcontainer.json to use it. On Linux, the container
# user's GID/UIDs will be updated to match your local UID/GID when using the image
# or dockerFile property. Update USER_UID/USER_GID below if you are using the
# dockerComposeFile property or want the image itself to start with different ID
# values. See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Configure apt and install packages
RUN apt-get update \
&& apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
#
# Verify git and needed tools are installed
&& apt-get -y install git iproute2 procps \
#
# Remove outdated yarn from /opt and install via package
# so it can be easily updated via apt-get upgrade yarn
&& rm -rf /opt/yarn-* \
&& rm -f /usr/local/bin/yarn \
&& rm -f /usr/local/bin/yarnpkg \
&& apt-get install -y curl apt-transport-https lsb-release \
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends yarn \
#
# Install tslint and typescript globally
&& npm install -g tslint eslint typescript \
#
# [Optional] Update a non-root user to UID/GID if needed.
&& if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
# Alter node user as needed, install tslint, typescript. eslint is installed by javascript image
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME; \
fi \
# [Optional] Add add sudo support for non-root user
&& apt-get install -y sudo \
&& echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME \
#
# Clean up
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
# Install tslint, typescript. eslint is installed by javascript image
&& npm install -g tslint typescript
# *********************************************************************
# * Uncomment this section to use RUN to install other dependencies. *
# * See https://aka.ms/vscode-remote/containers/dockerfile-run *
# *********************************************************************
# ENV DEBIAN_FRONTEND=noninteractive
# RUN apt-get update \
# && apt-get -y install --no-reccomends <your-package-list-here> \
# #
# # Clean up
# && apt-get autoremove -y \
# && apt-get clean -y \
# && rm -rf /var/lib/apt/lists/*
# ENV DEBIAN_FRONTEND=dialog
# Uncomment to default to non-root user
# USER $USER_UID
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog

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

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

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

@ -0,0 +1,54 @@
{
"build": {
"rootDistro": "debian",
"parent": "javascript-node-12",
"tags": [
"typescript-node:${VERSION}-12"
]
},
"dependencies": {
"image": "node:12",
"imageLink": "https://hub.docker.com/_/node",
"debian": [
"apt-utils",
"dialog",
"ca-certificates",
"git",
"iproute2",
"procps",
"curl",
"wget",
"unzip",
"lsb-release",
"apt-transport-https",
"libc6",
"libgcc1",
"libgssapi-krb5-2",
"libicu57",
"libssl1.1",
"libstdc++6",
"zlib1g",
"libssl1.0.2",
"sudo",
"yarn",
"zsh"
],
"npm": [
"eslint",
"tslint",
"typescript"
],
"manual": [
{
"Component": {
"Type": "git",
"git": {
"Name": "Oh My Zsh!",
"repositoryUrl": "https://github.com/robbyrussell/oh-my-zsh",
"commitHash": "c130aadb6a66aa680a322c08d87ad773316f713d"
}
}
}
]
}
}

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

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

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

@ -2,10 +2,7 @@
# 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:bionic
# Avoid warnings by switching to noninteractive
ENV DEBIAN_FRONTEND=noninteractive
FROM ubuntu:18.04
# 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
@ -15,20 +12,25 @@ ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Set to false to skip installing zsh and Oh My ZSH!
ARG INSTALL_ZSH="true"
# Location and expected SHA for common setup script - SHA generated on release
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 2>&1 \
&& apt-get -y install --no-install-recommends apt-utils dialog wget ca-certificates 2>&1 \
#
# Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
&& apt-get -y install git iproute2 procps lsb-release \
#
# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
&& groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# [Optional] Add sudo support for the non-root user
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME \
# 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" \
&& rm /tmp/common-setup.sh \
#
# Clean up
&& apt-get autoremove -y \
@ -36,4 +38,4 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
# Switch back to dialog for any ad-hoc use of apt-get
ENV DEBIAN_FRONTEND=dialog
ENV DEBIAN_FRONTEND=dialog

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше