diff --git a/deadlock-plugins/deadlock-extension/src/config.prod.ts b/deadlock-plugins/deadlock-extension/src/config.prod.ts index 80c3d02a4657f8ae232f5ce39fe43447cad805d2..40beee92f6ff88f45ecca11fd9946b6da96571cf 100644 --- a/deadlock-plugins/deadlock-extension/src/config.prod.ts +++ b/deadlock-plugins/deadlock-extension/src/config.prod.ts @@ -2,3 +2,4 @@ export const KEYCLOAK_DEVICE_AUTH_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/auth/device'; export const KEYCLOAK_TOKEN_CREATE_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token'; export const KEYCLOAK_USER_INFO_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; +export const REGISTRY_MISSION_URL = 'registry.e-biz.fr/deadlock/deadlock-challenges'; diff --git a/deadlock-plugins/deadlock-extension/src/config.staging.ts b/deadlock-plugins/deadlock-extension/src/config.staging.ts index 757b1b4dfe1e2593f8215cff490499b5000e601d..5030cdd73e8e942bf5f0ebe0906c96b3088feeac 100644 --- a/deadlock-plugins/deadlock-extension/src/config.staging.ts +++ b/deadlock-plugins/deadlock-extension/src/config.staging.ts @@ -4,3 +4,4 @@ export const KEYCLOAK_TOKEN_CREATE_URL = 'https://auth.staging.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token'; export const KEYCLOAK_USER_INFO_URL = 'https://auth.staging.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; +export const REGISTRY_MISSION_URL = 'registry.e-biz.fr/deadlock/deadlock-challenges'; diff --git a/deadlock-plugins/deadlock-extension/src/config.ts b/deadlock-plugins/deadlock-extension/src/config.ts index 4ea235cfab69d493e8eff3d659173a2972fead3f..eb332e792712a5598b88bdab2e38ec43ab137f5a 100644 --- a/deadlock-plugins/deadlock-extension/src/config.ts +++ b/deadlock-plugins/deadlock-extension/src/config.ts @@ -4,3 +4,4 @@ export const KEYCLOAK_TOKEN_CREATE_URL = 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/token'; export const KEYCLOAK_USER_INFO_URL = 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; +export const REGISTRY_MISSION_URL = 'registry.e-biz.fr/deadlock/deadlock-challenges'; diff --git a/deadlock-plugins/deadlock-extension/src/core/mission.ts b/deadlock-plugins/deadlock-extension/src/core/mission.ts new file mode 100644 index 0000000000000000000000000000000000000000..8354996a360f37958654c69a95f5dc25697183b6 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/core/mission.ts @@ -0,0 +1,135 @@ +import { exec as _exec } from 'child_process'; +import * as fs from 'fs'; +import * as util from 'util'; +import * as vscode from 'vscode'; +import { error as err, log } from '../recorder/utils'; +import ExtensionStore from './extensionStore'; + +/** + * {@link https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback} + */ +const exec = util.promisify(_exec); + +export default class Mission { + private readonly hostBaseWorkDir: string; + private readonly dockerImageURL: string; + private readonly hostMissionDir: string; + private readonly hostMissionDevcontainerDir: string; + private readonly hostMissionDevcontainerFileDir: string; + private readonly hostMissionMountDir: string; + private readonly remoteUserHomeDir: string; + private readonly remoteMissionDir: any; + private readonly remoteGiteaWorkDir: string; + constructor(private params: { registryBaseURL: string; missionId: string; missionVersion: string }) { + const { registryBaseURL, missionId, missionVersion } = params; + this.hostBaseWorkDir = ExtensionStore.getInstance().getMissionWorkdir() ?? ''; + this.hostMissionDir = `${this.hostBaseWorkDir}/${missionId}`; + this.hostMissionDevcontainerDir = `${this.hostMissionDir}/.devcontainer`; + this.hostMissionDevcontainerFileDir = `${this.hostMissionDevcontainerDir}/devcontainer.json`; + this.hostMissionMountDir = `${this.hostMissionDir}/mounted`; + this.dockerImageURL = getDockerImageURL(registryBaseURL, missionId, missionVersion); + this.remoteUserHomeDir = '/home/deadlock'; + this.remoteMissionDir = `${this.remoteUserHomeDir}/mission`; + this.remoteGiteaWorkDir = `/project`; + } + + static async pullImage(url) { + const { stdout, stderr } = await exec(`docker pull ${url}`); + log(stdout); + err(stderr); + } + + public async setup(options?: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts>) { + await fs.promises.mkdir(this.hostMissionDevcontainerDir, { recursive: true }); + await fs.promises.mkdir(this.hostMissionMountDir, { recursive: true }); + await fs.promises.writeFile( + this.hostMissionDevcontainerFileDir, + (() => { + const devcontainer: Partial<DockerfileSpecific & Base & VSCodespecific & LifecycleScripts> = { + name: `deadlock-${this.params.missionId}`, + image: this.dockerImageURL, + extensions: ['Deadlock.deadlock-coding'], + remoteUser: 'theia', + // mounts: [ + // `source=${this.hostMissionDir}/workspace,target=${'/workspace'},type=${'volume'},consistency=${'cached'}`, + // ], + userEnvProbe: 'interactiveShell', + settings: { + 'terminal.integrated.defaultProfile.linux': 'bash', + 'terminal.integrated.profiles.linux': { + bash: { + path: '/bin/bash', + }, + }, + }, + overrideCommand: false, + shutdownAction: 'stopContainer', + workspaceMount: `source=${this.hostMissionMountDir},target=${this.remoteMissionDir},type=bind`, + workspaceFolder: `${this.remoteMissionDir}`, + onCreateCommand: `cp -R ${this.remoteGiteaWorkDir} ${this.remoteMissionDir}`, + ...options, + }; + return JSON.stringify(devcontainer, null, 2); + })(), + ); + } + + public async openEditorInFolder(arbitraryPath?: string) { + if (arbitraryPath) { + return vscode.commands.executeCommand('remote-containers.openFolder', vscode.Uri.file(arbitraryPath)); + } + if (!fs.existsSync(this.hostMissionDir)) { + log('WARN missing path ', this.hostMissionDir); + await fs.promises.mkdir(this.hostMissionDir, { recursive: true }); + } + await vscode.commands.executeCommand('remote-containers.openFolder', vscode.Uri.file(this.hostMissionDir)); + } +} + +export function getDockerImageURL(base, missionId, missionVersion) { + return `${base}/${missionId}:${missionVersion}`; +} +interface DockerfileSpecific { + image?; + dockerFile?; + context?; + 'build.args'?; + 'build.target'?; + 'build.cacheFrom'?; + containerEnv?; + containerUser?; + mounts?; + workspaceMount?; + workspaceFolder?; + runArgs?; +} + +interface Base { + name?; + forwardPorts?; + portsAttributes?; + otherPortsAttributes?; + remoteEnv?; + remoteUser?; + updateRemoteUserUID?; + userEnvProbe?; + overrideCommand?; + features?; + shutdownAction?; +} + +interface VSCodespecific { + extensions?; + settings?; + devPort?; +} + +interface LifecycleScripts { + initializeCommand?; + onCreateCommand?; + updateContentCommand?; + postCreateCommand?; + postStartCommand?; + postAttachCommand?; + waitFor?; +}