Skip to content

Commit eb8312f

Browse files
committed
added dockerfile support
Signed-off-by: Jonah Iden <[email protected]>
1 parent 15a5332 commit eb8312f

File tree

4 files changed

+64
-33
lines changed

4 files changed

+64
-33
lines changed

packages/dev-container/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"@theia/remote": "1.46.0",
88
"@theia/workspace": "1.46.0",
99
"dockerode": "^4.0.2",
10-
"uuid": "^8.0.0"
10+
"uuid": "^8.0.0",
11+
"jsonc-parser": "^2.2.0"
1112
},
1213
"publishConfig": {
1314
"access": "public"

packages/dev-container/src/electron-node/devcontainer-contributions/main-container-creation-contributions.ts

+32-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
import * as Docker from 'dockerode';
1717
import { injectable, interfaces } from '@theia/core/shared/inversify';
1818
import { ContainerCreationContribution } from '../docker-container-service';
19-
import { DevContainerConfiguration, ImageContainer } from '../devcontainer-file';
19+
import { DevContainerConfiguration, DockerfileContainer, ImageContainer } from '../devcontainer-file';
2020

2121
export function registerContainerCreationContributions(bind: interfaces.Bind): void {
2222
bind(ContainerCreationContribution).to(ImageFileContribution).inSingletonScope();
23+
bind(ContainerCreationContribution).to(DockerFileContribution).inSingletonScope();
2324
bind(ContainerCreationContribution).to(ForwardPortsContribution).inSingletonScope();
2425
bind(ContainerCreationContribution).to(MountsContribution).inSingletonScope();
2526
}
@@ -35,6 +36,36 @@ export class ImageFileContribution implements ContainerCreationContribution {
3536
}
3637
}
3738

39+
@injectable()
40+
export class DockerFileContribution implements ContainerCreationContribution {
41+
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: DockerfileContainer, api: Docker): Promise<void> {
42+
// check if dockerfile container
43+
if (containerConfig.dockerFile || containerConfig.build?.dockerfile) {
44+
const dockerfile = (containerConfig.dockerFile ?? containerConfig.build?.dockerfile) as string;
45+
const buildStream = await api.buildImage({
46+
context: containerConfig.context ?? containerConfig.location,
47+
src: [dockerfile],
48+
} as Docker.ImageBuildContext, {
49+
buildargs: containerConfig.build?.args
50+
});
51+
// TODO probably have some console windows showing the output of the build
52+
const imageId = await new Promise<string>((res, rej) => api.modem.followProgress(buildStream, (err, ouptuts) => {
53+
if (err) {
54+
rej(err);
55+
} else {
56+
for (let i = ouptuts.length - 1; i >= 0; i--) {
57+
if (ouptuts[i].aux?.ID) {
58+
res(ouptuts[i].aux.ID);
59+
return;
60+
}
61+
}
62+
}
63+
}));
64+
createOptions.Image = imageId;
65+
}
66+
}
67+
}
68+
3869
@injectable()
3970
export class ForwardPortsContribution implements ContainerCreationContribution {
4071
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: DevContainerConfiguration, api: Docker): Promise<void> {

packages/dev-container/src/electron-node/devcontainer-file.ts

+26-29
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* Defines a dev container
1919
* type generated from https://containers.dev/implementors/json_schema/ and modified
2020
*/
21-
export type DevContainerConfiguration = (DockerfileContainer | ImageContainer) & NonComposeContainerBase & DevContainerCommon;
21+
export type DevContainerConfiguration = (DockerfileContainer | ImageContainer) & NonComposeContainerBase & DevContainerCommon & { location?: string };
2222

2323
export type DockerfileContainer = {
2424
/**
@@ -33,43 +33,40 @@ export type DockerfileContainer = {
3333
* The location of the context folder for building the Docker image. The path is relative to the folder containing the `devcontainer.json` file.
3434
*/
3535
context?: string
36-
[k: string]: unknown
3736
} & BuildOptions
3837
[k: string]: unknown
39-
}
40-
| ({
38+
} | {
39+
/**
40+
* The location of the Dockerfile that defines the contents of the container. The path is relative to the folder containing the `devcontainer.json` file.
41+
*/
42+
dockerFile: string
43+
/**
44+
* The location of the context folder for building the Docker image. The path is relative to the folder containing the `devcontainer.json` file.
45+
*/
46+
context?: string
47+
48+
/**
49+
* Docker build-related options.
50+
*/
51+
build?: {
4152
/**
42-
* The location of the Dockerfile that defines the contents of the container. The path is relative to the folder containing the `devcontainer.json` file.
53+
* Target stage in a multi-stage build.
4354
*/
44-
dockerFile: string
55+
target?: string
4556
/**
46-
* The location of the context folder for building the Docker image. The path is relative to the folder containing the `devcontainer.json` file.
57+
* Build arguments.
4758
*/
48-
context?: string
49-
[k: string]: unknown
50-
} & {
59+
args?: {
60+
[k: string]: string
61+
}
5162
/**
52-
* Docker build-related options.
63+
* The image to consider as a cache. Use an array to specify multiple images.
5364
*/
54-
build?: {
55-
/**
56-
* Target stage in a multi-stage build.
57-
*/
58-
target?: string
59-
/**
60-
* Build arguments.
61-
*/
62-
args?: {
63-
[k: string]: string
64-
}
65-
/**
66-
* The image to consider as a cache. Use an array to specify multiple images.
67-
*/
68-
cacheFrom?: string | string[]
69-
[k: string]: unknown
70-
}
65+
cacheFrom?: string | string[]
7166
[k: string]: unknown
72-
});
67+
}
68+
[k: string]: unknown
69+
};
7370

7471
export interface BuildOptions {
7572
/**

packages/dev-container/src/electron-node/docker-container-service.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import { ContributionProvider, URI } from '@theia/core';
1818
import { inject, injectable, named } from '@theia/core/shared/inversify';
1919
import { WorkspaceServer } from '@theia/workspace/lib/common';
20+
import { parse } from 'jsonc-parser';
2021
import * as fs from '@theia/core/shared/fs-extra';
2122
import * as Docker from 'dockerode';
2223
import { LastContainerInfo } from '../electron-common/remote-container-connection-provider';
@@ -51,7 +52,7 @@ export class DockerContainerService {
5152
port = lastContainerInfo.port;
5253
} catch (e) {
5354
container = undefined;
54-
console.warn('DevContainer: could not find last used container ', e);
55+
console.warn('DevContainer: could not find last used container');
5556
}
5657
}
5758
if (!container) {
@@ -67,7 +68,8 @@ export class DockerContainerService {
6768
}
6869

6970
const devcontainerFile = workspace.resolve('.devcontainer/devcontainer.json');
70-
const devcontainerConfig = JSON.parse(await fs.readFile(devcontainerFile.path.fsPath(), 'utf-8').catch(() => '0')) as DevContainerConfiguration;
71+
const devcontainerConfig = parse(await fs.readFile(devcontainerFile.path.fsPath(), 'utf-8').catch(() => '0')) as DevContainerConfiguration;
72+
devcontainerConfig.location = devcontainerFile.path.dir.fsPath();
7173

7274
if (!devcontainerConfig) {
7375
// TODO add ability for user to create new config

0 commit comments

Comments
 (0)