@theia/dev-container 1.46.0-next.241
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/lib/dev-container-server/dev-container-server.d.ts +2 -0
- package/lib/dev-container-server/dev-container-server.d.ts.map +1 -0
- package/lib/dev-container-server/dev-container-server.js +48 -0
- package/lib/dev-container-server/dev-container-server.js.map +1 -0
- package/lib/electron-browser/container-connection-contribution.d.ts +28 -0
- package/lib/electron-browser/container-connection-contribution.d.ts.map +1 -0
- package/lib/electron-browser/container-connection-contribution.js +147 -0
- package/lib/electron-browser/container-connection-contribution.js.map +1 -0
- package/lib/electron-browser/container-info-contribution.d.ts +11 -0
- package/lib/electron-browser/container-info-contribution.d.ts.map +1 -0
- package/lib/electron-browser/container-info-contribution.js +51 -0
- package/lib/electron-browser/container-info-contribution.js.map +1 -0
- package/lib/electron-browser/container-output-provider.d.ts +8 -0
- package/lib/electron-browser/container-output-provider.d.ts.map +1 -0
- package/lib/electron-browser/container-output-provider.js +41 -0
- package/lib/electron-browser/container-output-provider.js.map +1 -0
- package/lib/electron-browser/dev-container-frontend-module.d.ts +4 -0
- package/lib/electron-browser/dev-container-frontend-module.d.ts.map +1 -0
- package/lib/electron-browser/dev-container-frontend-module.js +39 -0
- package/lib/electron-browser/dev-container-frontend-module.js.map +1 -0
- package/lib/electron-common/container-output-provider.d.ts +4 -0
- package/lib/electron-common/container-output-provider.d.ts.map +1 -0
- package/lib/electron-common/container-output-provider.js +18 -0
- package/lib/electron-common/container-output-provider.js.map +1 -0
- package/lib/electron-common/dev-container-workspaces.d.ts +3 -0
- package/lib/electron-common/dev-container-workspaces.d.ts.map +1 -0
- package/lib/electron-common/dev-container-workspaces.js +21 -0
- package/lib/electron-common/dev-container-workspaces.js.map +1 -0
- package/lib/electron-common/remote-container-connection-provider.d.ts +30 -0
- package/lib/electron-common/remote-container-connection-provider.d.ts.map +1 -0
- package/lib/electron-common/remote-container-connection-provider.js +21 -0
- package/lib/electron-common/remote-container-connection-provider.js.map +1 -0
- package/lib/electron-node/dev-container-backend-module.d.ts +5 -0
- package/lib/electron-node/dev-container-backend-module.d.ts.map +1 -0
- package/lib/electron-node/dev-container-backend-module.js +58 -0
- package/lib/electron-node/dev-container-backend-module.js.map +1 -0
- package/lib/electron-node/dev-container-file-service.d.ts +10 -0
- package/lib/electron-node/dev-container-file-service.d.ts.map +1 -0
- package/lib/electron-node/dev-container-file-service.js +69 -0
- package/lib/electron-node/dev-container-file-service.js.map +1 -0
- package/lib/electron-node/dev-container-workspace-handler.d.ts +7 -0
- package/lib/electron-node/dev-container-workspace-handler.d.ts.map +1 -0
- package/lib/electron-node/dev-container-workspace-handler.js +21 -0
- package/lib/electron-node/dev-container-workspace-handler.js.map +1 -0
- package/lib/electron-node/devcontainer-contributions/cli-enhancing-creation-contributions.d.ts +17 -0
- package/lib/electron-node/devcontainer-contributions/cli-enhancing-creation-contributions.d.ts.map +1 -0
- package/lib/electron-node/devcontainer-contributions/cli-enhancing-creation-contributions.js +69 -0
- package/lib/electron-node/devcontainer-contributions/cli-enhancing-creation-contributions.js.map +1 -0
- package/lib/electron-node/devcontainer-contributions/main-container-creation-contributions.d.ts +38 -0
- package/lib/electron-node/devcontainer-contributions/main-container-creation-contributions.d.ts.map +1 -0
- package/lib/electron-node/devcontainer-contributions/main-container-creation-contributions.js +192 -0
- package/lib/electron-node/devcontainer-contributions/main-container-creation-contributions.js.map +1 -0
- package/lib/electron-node/devcontainer-contributions/profile-file-modification-contribution.d.ts +11 -0
- package/lib/electron-node/devcontainer-contributions/profile-file-modification-contribution.d.ts.map +1 -0
- package/lib/electron-node/devcontainer-contributions/profile-file-modification-contribution.js +37 -0
- package/lib/electron-node/devcontainer-contributions/profile-file-modification-contribution.js.map +1 -0
- package/lib/electron-node/devcontainer-file.d.ts +350 -0
- package/lib/electron-node/devcontainer-file.d.ts.map +1 -0
- package/lib/electron-node/devcontainer-file.js +18 -0
- package/lib/electron-node/devcontainer-file.js.map +1 -0
- package/lib/electron-node/docker-container-service.d.ts +29 -0
- package/lib/electron-node/docker-container-service.d.ts.map +1 -0
- package/lib/electron-node/docker-container-service.js +106 -0
- package/lib/electron-node/docker-container-service.js.map +1 -0
- package/lib/electron-node/remote-container-connection-provider.d.ts +79 -0
- package/lib/electron-node/remote-container-connection-provider.d.ts.map +1 -0
- package/lib/electron-node/remote-container-connection-provider.js +260 -0
- package/lib/electron-node/remote-container-connection-provider.js.map +1 -0
- package/lib/package.spec.d.ts +1 -0
- package/lib/package.spec.d.ts.map +1 -0
- package/lib/package.spec.js +26 -0
- package/lib/package.spec.js.map +1 -0
- package/package.json +55 -0
- package/src/dev-container-server/dev-container-server.ts +53 -0
- package/src/electron-browser/container-connection-contribution.ts +151 -0
- package/src/electron-browser/container-info-contribution.ts +47 -0
- package/src/electron-browser/container-output-provider.ts +36 -0
- package/src/electron-browser/dev-container-frontend-module.ts +40 -0
- package/src/electron-common/container-output-provider.ts +19 -0
- package/src/electron-common/dev-container-workspaces.ts +18 -0
- package/src/electron-common/remote-container-connection-provider.ts +52 -0
- package/src/electron-node/dev-container-backend-module.ts +63 -0
- package/src/electron-node/dev-container-file-service.ts +67 -0
- package/src/electron-node/dev-container-workspace-handler.ts +33 -0
- package/src/electron-node/devcontainer-contributions/cli-enhancing-creation-contributions.ts +68 -0
- package/src/electron-node/devcontainer-contributions/main-container-creation-contributions.ts +196 -0
- package/src/electron-node/devcontainer-contributions/profile-file-modification-contribution.ts +35 -0
- package/src/electron-node/devcontainer-file.ts +411 -0
- package/src/electron-node/docker-container-service.ts +131 -0
- package/src/electron-node/remote-container-connection-provider.ts +315 -0
- package/src/package.spec.ts +28 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
17
|
+
import { RemoteRegistryContribution } from '@theia/remote/lib/electron-browser/remote-registry-contribution';
|
|
18
|
+
import { RemoteContainerConnectionProvider, RemoteContainerConnectionProviderPath } from '../electron-common/remote-container-connection-provider';
|
|
19
|
+
import { ContainerConnectionContribution } from './container-connection-contribution';
|
|
20
|
+
import { ServiceConnectionProvider } from '@theia/core/lib/browser/messaging/service-connection-provider';
|
|
21
|
+
import { ContainerOutputProvider } from './container-output-provider';
|
|
22
|
+
import { ContainerInfoContribution } from './container-info-contribution';
|
|
23
|
+
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
|
|
24
|
+
import { WorkspaceOpenHandlerContribution } from '@theia/workspace/lib/browser/workspace-service';
|
|
25
|
+
|
|
26
|
+
export default new ContainerModule(bind => {
|
|
27
|
+
bind(ContainerConnectionContribution).toSelf().inSingletonScope();
|
|
28
|
+
bind(RemoteRegistryContribution).toService(ContainerConnectionContribution);
|
|
29
|
+
bind(WorkspaceOpenHandlerContribution).toService(ContainerConnectionContribution);
|
|
30
|
+
|
|
31
|
+
bind(ContainerOutputProvider).toSelf().inSingletonScope();
|
|
32
|
+
|
|
33
|
+
bind(RemoteContainerConnectionProvider).toDynamicValue(ctx => {
|
|
34
|
+
const outputProvider = ctx.container.get(ContainerOutputProvider);
|
|
35
|
+
return ServiceConnectionProvider.createLocalProxy<RemoteContainerConnectionProvider>(ctx.container, RemoteContainerConnectionProviderPath, outputProvider);
|
|
36
|
+
}).inSingletonScope();
|
|
37
|
+
|
|
38
|
+
bind(ContainerInfoContribution).toSelf().inSingletonScope();
|
|
39
|
+
bind(FrontendApplicationContribution).toService(ContainerInfoContribution);
|
|
40
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
export interface ContainerOutputProvider {
|
|
18
|
+
onRemoteOutput(output: string): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
export const DEV_CONTAINER_WORKSPACE_SCHEME = 'devcontainer';
|
|
18
|
+
export const DEV_CONTAINER_PATH_QUERY = 'containerfile';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
|
|
16
|
+
import { RpcServer } from '@theia/core';
|
|
17
|
+
import { ContainerOutputProvider } from './container-output-provider';
|
|
18
|
+
import type { ContainerInspectInfo } from 'dockerode';
|
|
19
|
+
|
|
20
|
+
// *****************************************************************************
|
|
21
|
+
export const RemoteContainerConnectionProviderPath = '/remote/container';
|
|
22
|
+
|
|
23
|
+
export const RemoteContainerConnectionProvider = Symbol('RemoteContainerConnectionProvider');
|
|
24
|
+
|
|
25
|
+
export interface ContainerConnectionOptions {
|
|
26
|
+
nodeDownloadTemplate?: string;
|
|
27
|
+
lastContainerInfo?: LastContainerInfo
|
|
28
|
+
devcontainerFile: string;
|
|
29
|
+
workspaceUri?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface LastContainerInfo {
|
|
33
|
+
id: string;
|
|
34
|
+
lastUsed: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ContainerConnectionResult {
|
|
38
|
+
port: string;
|
|
39
|
+
workspacePath: string;
|
|
40
|
+
containerId: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface DevContainerFile {
|
|
44
|
+
name: string;
|
|
45
|
+
path: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface RemoteContainerConnectionProvider extends RpcServer<ContainerOutputProvider> {
|
|
49
|
+
connectToContainer(options: ContainerConnectionOptions): Promise<ContainerConnectionResult>;
|
|
50
|
+
getDevContainerFiles(workspacePath: string): Promise<DevContainerFile[]>;
|
|
51
|
+
getCurrentContainerInfo(port: number): Promise<ContainerInspectInfo | undefined>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { ContainerModule } from '@theia/core/shared/inversify';
|
|
18
|
+
import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
|
|
19
|
+
import { DevContainerConnectionProvider } from './remote-container-connection-provider';
|
|
20
|
+
import { RemoteContainerConnectionProvider, RemoteContainerConnectionProviderPath } from '../electron-common/remote-container-connection-provider';
|
|
21
|
+
import { ContainerCreationContribution, DockerContainerService } from './docker-container-service';
|
|
22
|
+
import { bindContributionProvider, ConnectionHandler, RpcConnectionHandler } from '@theia/core';
|
|
23
|
+
import { registerContainerCreationContributions } from './devcontainer-contributions/main-container-creation-contributions';
|
|
24
|
+
import { DevContainerFileService } from './dev-container-file-service';
|
|
25
|
+
import { ContainerOutputProvider } from '../electron-common/container-output-provider';
|
|
26
|
+
import { ExtensionsContribution, registerTheiaStartOptionsContributions, SettingsContribution } from './devcontainer-contributions/cli-enhancing-creation-contributions';
|
|
27
|
+
import { RemoteCliContribution } from '@theia/core/lib/node/remote/remote-cli-contribution';
|
|
28
|
+
import { ProfileFileModificationContribution } from './devcontainer-contributions/profile-file-modification-contribution';
|
|
29
|
+
import { DevContainerWorkspaceHandler } from './dev-container-workspace-handler';
|
|
30
|
+
import { WorkspaceHandlerContribution } from '@theia/workspace/lib/node/default-workspace-server';
|
|
31
|
+
|
|
32
|
+
export const remoteConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
|
33
|
+
bindContributionProvider(bind, ContainerCreationContribution);
|
|
34
|
+
registerContainerCreationContributions(bind);
|
|
35
|
+
registerTheiaStartOptionsContributions(bind);
|
|
36
|
+
bind(ProfileFileModificationContribution).toSelf().inSingletonScope();
|
|
37
|
+
bind(ContainerCreationContribution).toService(ProfileFileModificationContribution);
|
|
38
|
+
|
|
39
|
+
bind(DevContainerConnectionProvider).toSelf().inSingletonScope();
|
|
40
|
+
bind(RemoteContainerConnectionProvider).toService(DevContainerConnectionProvider);
|
|
41
|
+
bind(ConnectionHandler).toDynamicValue(ctx =>
|
|
42
|
+
new RpcConnectionHandler<ContainerOutputProvider>(RemoteContainerConnectionProviderPath, client => {
|
|
43
|
+
const server = ctx.container.get<RemoteContainerConnectionProvider>(RemoteContainerConnectionProvider);
|
|
44
|
+
server.setClient(client);
|
|
45
|
+
client.onDidCloseConnection(() => server.dispose());
|
|
46
|
+
return server;
|
|
47
|
+
}));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
|
51
|
+
bind(DockerContainerService).toSelf().inSingletonScope();
|
|
52
|
+
bind(ConnectionContainerModule).toConstantValue(remoteConnectionModule);
|
|
53
|
+
|
|
54
|
+
bind(DevContainerFileService).toSelf().inSingletonScope();
|
|
55
|
+
|
|
56
|
+
bind(ExtensionsContribution).toSelf().inSingletonScope();
|
|
57
|
+
bind(SettingsContribution).toSelf().inSingletonScope();
|
|
58
|
+
bind(RemoteCliContribution).toService(ExtensionsContribution);
|
|
59
|
+
bind(RemoteCliContribution).toService(SettingsContribution);
|
|
60
|
+
|
|
61
|
+
bind(DevContainerWorkspaceHandler).toSelf().inSingletonScope();
|
|
62
|
+
bind(WorkspaceHandlerContribution).toService(DevContainerWorkspaceHandler);
|
|
63
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
18
|
+
import { WorkspaceServer } from '@theia/workspace/lib/common';
|
|
19
|
+
import { DevContainerFile } from '../electron-common/remote-container-connection-provider';
|
|
20
|
+
import { DevContainerConfiguration } from './devcontainer-file';
|
|
21
|
+
import { parse } from 'jsonc-parser';
|
|
22
|
+
import * as fs from '@theia/core/shared/fs-extra';
|
|
23
|
+
import { Path, URI } from '@theia/core';
|
|
24
|
+
|
|
25
|
+
@injectable()
|
|
26
|
+
export class DevContainerFileService {
|
|
27
|
+
|
|
28
|
+
@inject(WorkspaceServer)
|
|
29
|
+
protected readonly workspaceServer: WorkspaceServer;
|
|
30
|
+
|
|
31
|
+
async getConfiguration(path: string): Promise<DevContainerConfiguration> {
|
|
32
|
+
const configuration: DevContainerConfiguration = parse(await fs.readFile(path, 'utf-8').catch(() => '0')) as DevContainerConfiguration;
|
|
33
|
+
if (!configuration) {
|
|
34
|
+
throw new Error(`devcontainer file ${path} could not be parsed`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
configuration.location = path;
|
|
38
|
+
return configuration;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async getAvailableFiles(workspace: string): Promise<DevContainerFile[]> {
|
|
42
|
+
const devcontainerPath = new URI(workspace).path.join('.devcontainer').fsPath();
|
|
43
|
+
|
|
44
|
+
return (await this.searchForDevontainerJsonFiles(devcontainerPath, 1)).map(file => ({
|
|
45
|
+
name: parse(fs.readFileSync(file, 'utf-8')).name ?? 'devcontainer',
|
|
46
|
+
path: file
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected async searchForDevontainerJsonFiles(directory: string, depth: number): Promise<string[]> {
|
|
52
|
+
if (depth < 0 || !await fs.pathExists(directory)) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const filesPaths = (await fs.readdir(directory)).map(file => new Path(directory).join(file).fsPath());
|
|
56
|
+
|
|
57
|
+
const devcontainerFiles = [];
|
|
58
|
+
for (const file of filesPaths) {
|
|
59
|
+
if (file.endsWith('devcontainer.json')) {
|
|
60
|
+
devcontainerFiles.push(file);
|
|
61
|
+
} else if ((await fs.stat(file)).isDirectory()) {
|
|
62
|
+
devcontainerFiles.push(...await this.searchForDevontainerJsonFiles(file, depth - 1));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return devcontainerFiles;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
import { URI } from '@theia/core';
|
|
17
|
+
import * as fs from '@theia/core/shared/fs-extra';
|
|
18
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
19
|
+
import { WorkspaceHandlerContribution } from '@theia/workspace/lib/node/default-workspace-server';
|
|
20
|
+
import { DEV_CONTAINER_PATH_QUERY, DEV_CONTAINER_WORKSPACE_SCHEME } from '../electron-common/dev-container-workspaces';
|
|
21
|
+
|
|
22
|
+
@injectable()
|
|
23
|
+
export class DevContainerWorkspaceHandler implements WorkspaceHandlerContribution {
|
|
24
|
+
|
|
25
|
+
canHandle(uri: URI): boolean {
|
|
26
|
+
return uri.scheme === DEV_CONTAINER_WORKSPACE_SCHEME;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async workspaceStillExists(uri: URI): Promise<boolean> {
|
|
30
|
+
const devcontainerFile = new URLSearchParams(uri.query).get(DEV_CONTAINER_PATH_QUERY);
|
|
31
|
+
return await fs.pathExists(uri.path.fsPath()) && !!devcontainerFile && fs.pathExists(devcontainerFile);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { RemoteCliContext, RemoteCliContribution } from '@theia/core/lib/node/remote/remote-cli-contribution';
|
|
18
|
+
import { ContainerCreationContribution } from '../docker-container-service';
|
|
19
|
+
import * as Docker from 'dockerode';
|
|
20
|
+
import { DevContainerConfiguration, } from '../devcontainer-file';
|
|
21
|
+
import { injectable, interfaces } from '@theia/core/shared/inversify';
|
|
22
|
+
|
|
23
|
+
export function registerTheiaStartOptionsContributions(bind: interfaces.Bind): void {
|
|
24
|
+
bind(ContainerCreationContribution).toService(ExtensionsContribution);
|
|
25
|
+
bind(ContainerCreationContribution).toService(SettingsContribution);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@injectable()
|
|
29
|
+
export class ExtensionsContribution implements RemoteCliContribution, ContainerCreationContribution {
|
|
30
|
+
protected currentConfig: DevContainerConfiguration | undefined;
|
|
31
|
+
|
|
32
|
+
enhanceArgs(context: RemoteCliContext): string[] {
|
|
33
|
+
if (!this.currentConfig) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const extensions = [
|
|
37
|
+
...(this.currentConfig.extensions ?? []),
|
|
38
|
+
...(this.currentConfig.customizations?.vscode?.extensions ?? [])
|
|
39
|
+
];
|
|
40
|
+
this.currentConfig = undefined;
|
|
41
|
+
return extensions?.map(extension => `--install-plugin=${extension}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: DevContainerConfiguration): Promise<void> {
|
|
45
|
+
this.currentConfig = containerConfig;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@injectable()
|
|
50
|
+
export class SettingsContribution implements RemoteCliContribution, ContainerCreationContribution {
|
|
51
|
+
protected currentConfig: DevContainerConfiguration | undefined;
|
|
52
|
+
|
|
53
|
+
enhanceArgs(context: RemoteCliContext): string[] {
|
|
54
|
+
if (!this.currentConfig) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const settings = {
|
|
58
|
+
...(this.currentConfig.settings ?? {}),
|
|
59
|
+
...(this.currentConfig.customizations?.vscode?.settings ?? [])
|
|
60
|
+
};
|
|
61
|
+
this.currentConfig = undefined;
|
|
62
|
+
return Object.entries(settings).map(([key, value]) => `--set-preference=${key}=${JSON.stringify(value)}`) ?? [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: DevContainerConfiguration): Promise<void> {
|
|
66
|
+
this.currentConfig = containerConfig;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
import * as Docker from 'dockerode';
|
|
17
|
+
import { inject, injectable, interfaces } from '@theia/core/shared/inversify';
|
|
18
|
+
import { ContainerCreationContribution } from '../docker-container-service';
|
|
19
|
+
import { DevContainerConfiguration, DockerfileContainer, ImageContainer, NonComposeContainerBase } from '../devcontainer-file';
|
|
20
|
+
import { Path } from '@theia/core';
|
|
21
|
+
import { ContainerOutputProvider } from '../../electron-common/container-output-provider';
|
|
22
|
+
import * as fs from '@theia/core/shared/fs-extra';
|
|
23
|
+
import { RemotePortForwardingProvider } from '@theia/remote/lib/electron-common/remote-port-forwarding-provider';
|
|
24
|
+
import { RemoteDockerContainerConnection } from '../remote-container-connection-provider';
|
|
25
|
+
|
|
26
|
+
export function registerContainerCreationContributions(bind: interfaces.Bind): void {
|
|
27
|
+
bind(ContainerCreationContribution).to(ImageFileContribution).inSingletonScope();
|
|
28
|
+
bind(ContainerCreationContribution).to(DockerFileContribution).inSingletonScope();
|
|
29
|
+
bind(ContainerCreationContribution).to(ForwardPortsContribution).inSingletonScope();
|
|
30
|
+
bind(ContainerCreationContribution).to(MountsContribution).inSingletonScope();
|
|
31
|
+
bind(ContainerCreationContribution).to(RemoteUserContribution).inSingletonScope();
|
|
32
|
+
bind(ContainerCreationContribution).to(PostCreateCommandContribution).inSingletonScope();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@injectable()
|
|
36
|
+
export class ImageFileContribution implements ContainerCreationContribution {
|
|
37
|
+
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: ImageContainer,
|
|
38
|
+
api: Docker, outputprovider: ContainerOutputProvider): Promise<void> {
|
|
39
|
+
if (containerConfig.image) {
|
|
40
|
+
const platform = process.platform;
|
|
41
|
+
const arch = process.arch;
|
|
42
|
+
const options = platform === 'darwin' && arch === 'arm64' ? { platform: 'amd64' } : {};
|
|
43
|
+
await new Promise<void>((res, rej) => api.pull(containerConfig.image, options, (err, stream) => {
|
|
44
|
+
if (err) {
|
|
45
|
+
rej(err);
|
|
46
|
+
} else if (stream === undefined) {
|
|
47
|
+
rej('Stream is undefined');
|
|
48
|
+
} else {
|
|
49
|
+
api.modem.followProgress(stream, (error, output) => error ?
|
|
50
|
+
rej(error) :
|
|
51
|
+
res(), progress => outputprovider.onRemoteOutput(OutputHelper.parseProgress(progress)));
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
createOptions.Image = containerConfig.image;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@injectable()
|
|
60
|
+
export class DockerFileContribution implements ContainerCreationContribution {
|
|
61
|
+
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: DockerfileContainer,
|
|
62
|
+
api: Docker, outputprovider: ContainerOutputProvider): Promise<void> {
|
|
63
|
+
// check if dockerfile container
|
|
64
|
+
if (containerConfig.dockerFile || containerConfig.build?.dockerfile) {
|
|
65
|
+
const dockerfile = (containerConfig.dockerFile ?? containerConfig.build?.dockerfile) as string;
|
|
66
|
+
const context = containerConfig.context ?? new Path(containerConfig.location as string).dir.fsPath();
|
|
67
|
+
try {
|
|
68
|
+
// ensure dockerfile exists
|
|
69
|
+
await fs.lstat(new Path(context as string).join(dockerfile).fsPath());
|
|
70
|
+
|
|
71
|
+
const buildStream = await api.buildImage({
|
|
72
|
+
context,
|
|
73
|
+
src: [dockerfile],
|
|
74
|
+
} as Docker.ImageBuildContext, {
|
|
75
|
+
buildargs: containerConfig.build?.args
|
|
76
|
+
});
|
|
77
|
+
// TODO probably have some console windows showing the output of the build
|
|
78
|
+
const imageId = await new Promise<string>((res, rej) => api.modem.followProgress(buildStream!, (err, outputs) => {
|
|
79
|
+
if (err) {
|
|
80
|
+
rej(err);
|
|
81
|
+
} else {
|
|
82
|
+
for (let i = outputs.length - 1; i >= 0; i--) {
|
|
83
|
+
if (outputs[i].aux?.ID) {
|
|
84
|
+
res(outputs[i].aux.ID);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}, progress => outputprovider.onRemoteOutput(OutputHelper.parseProgress(progress))));
|
|
90
|
+
createOptions.Image = imageId;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
outputprovider.onRemoteOutput(`could not build dockerfile "${dockerfile}" reason: ${error.message}`);
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@injectable()
|
|
100
|
+
export class ForwardPortsContribution implements ContainerCreationContribution {
|
|
101
|
+
|
|
102
|
+
@inject(RemotePortForwardingProvider)
|
|
103
|
+
protected readonly portForwardingProvider: RemotePortForwardingProvider;
|
|
104
|
+
|
|
105
|
+
async handlePostConnect(containerConfig: DevContainerConfiguration, connection: RemoteDockerContainerConnection): Promise<void> {
|
|
106
|
+
if (!containerConfig.forwardPorts) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (const forward of containerConfig.forwardPorts) {
|
|
111
|
+
let port: number;
|
|
112
|
+
let address: string | undefined;
|
|
113
|
+
if (typeof forward === 'string') {
|
|
114
|
+
const parts = forward.split(':');
|
|
115
|
+
address = parts[0];
|
|
116
|
+
port = parseInt(parts[1]);
|
|
117
|
+
} else {
|
|
118
|
+
port = forward;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.portForwardingProvider.forwardPort(connection.localPort, { port, address });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@injectable()
|
|
129
|
+
export class MountsContribution implements ContainerCreationContribution {
|
|
130
|
+
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: DevContainerConfiguration, api: Docker): Promise<void> {
|
|
131
|
+
if (!containerConfig.mounts) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
createOptions.HostConfig!.Mounts!.push(...(containerConfig as NonComposeContainerBase)?.mounts
|
|
136
|
+
?.map(mount => typeof mount === 'string' ?
|
|
137
|
+
this.parseMountString(mount) :
|
|
138
|
+
{ Source: mount.source, Target: mount.target, Type: mount.type ?? 'bind' }) ?? []);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
parseMountString(mount: string): Docker.MountSettings {
|
|
142
|
+
const parts = mount.split(',');
|
|
143
|
+
return {
|
|
144
|
+
Source: parts.find(part => part.startsWith('source=') || part.startsWith('src='))?.split('=')[1]!,
|
|
145
|
+
Target: parts.find(part => part.startsWith('target=') || part.startsWith('dst='))?.split('=')[1]!,
|
|
146
|
+
Type: (parts.find(part => part.startsWith('type='))?.split('=')[1] ?? 'bind') as Docker.MountType
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@injectable()
|
|
152
|
+
export class RemoteUserContribution implements ContainerCreationContribution {
|
|
153
|
+
async handleContainerCreation(createOptions: Docker.ContainerCreateOptions, containerConfig: DevContainerConfiguration, api: Docker): Promise<void> {
|
|
154
|
+
if (containerConfig.remoteUser) {
|
|
155
|
+
createOptions.User = containerConfig.remoteUser;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@injectable()
|
|
161
|
+
export class PostCreateCommandContribution implements ContainerCreationContribution {
|
|
162
|
+
async handlePostCreate?(containerConfig: DevContainerConfiguration, container: Docker.Container, api: Docker, outputprovider: ContainerOutputProvider): Promise<void> {
|
|
163
|
+
if (containerConfig.postCreateCommand) {
|
|
164
|
+
const commands = typeof containerConfig.postCreateCommand === 'object' && !(containerConfig.postCreateCommand instanceof Array) ?
|
|
165
|
+
Object.values(containerConfig.postCreateCommand) : [containerConfig.postCreateCommand];
|
|
166
|
+
for (const command of commands) {
|
|
167
|
+
try {
|
|
168
|
+
let exec;
|
|
169
|
+
if (command instanceof Array) {
|
|
170
|
+
exec = await container.exec({ Cmd: command, AttachStderr: true, AttachStdout: true });
|
|
171
|
+
|
|
172
|
+
} else {
|
|
173
|
+
exec = await container.exec({ Cmd: ['sh', '-c', command], AttachStderr: true, AttachStdout: true });
|
|
174
|
+
}
|
|
175
|
+
const stream = await exec.start({ Tty: true });
|
|
176
|
+
stream.on('data', chunk => outputprovider.onRemoteOutput(chunk.toString()));
|
|
177
|
+
} catch (error) {
|
|
178
|
+
outputprovider.onRemoteOutput('could not execute postCreateCommand ' + JSON.stringify(command) + ' reason:' + error.message);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export namespace OutputHelper {
|
|
186
|
+
export interface Progress {
|
|
187
|
+
id?: string;
|
|
188
|
+
stream: string;
|
|
189
|
+
status?: string;
|
|
190
|
+
progress?: string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function parseProgress(progress: Progress): string {
|
|
194
|
+
return progress.stream ?? progress.progress ?? progress.status ?? '';
|
|
195
|
+
}
|
|
196
|
+
}
|
package/src/electron-node/devcontainer-contributions/profile-file-modification-contribution.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2024 Typefox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { DevContainerConfiguration } from '../devcontainer-file';
|
|
18
|
+
import { ContainerCreationContribution } from '../docker-container-service';
|
|
19
|
+
import * as Docker from 'dockerode';
|
|
20
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
21
|
+
import { ContainerOutputProvider } from '../../electron-common/container-output-provider';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* this contribution changes the /etc/profile file so that it won't overwrite the PATH variable set by docker
|
|
25
|
+
*/
|
|
26
|
+
@injectable()
|
|
27
|
+
export class ProfileFileModificationContribution implements ContainerCreationContribution {
|
|
28
|
+
async handlePostCreate(containerConfig: DevContainerConfiguration, container: Docker.Container, api: Docker, outputprovider: ContainerOutputProvider): Promise<void> {
|
|
29
|
+
const stream = await (await container.exec({
|
|
30
|
+
Cmd: ['sh', '-c', 'sed -i \'s|PATH="\\([^"]*\\)"|PATH=${PATH:-"\\1"}|g\' /etc/profile'], User: 'root',
|
|
31
|
+
AttachStderr: true, AttachStdout: true
|
|
32
|
+
})).start({});
|
|
33
|
+
stream.on('data', data => outputprovider.onRemoteOutput(data.toString()));
|
|
34
|
+
}
|
|
35
|
+
}
|