Skip to content
Snippets Groups Projects
Commit 93e1b7d8 authored by Christian ZHENG's avatar Christian ZHENG
Browse files

feat(devcontainer): student can open mission inside devcontainer on xdg link click

parent 52fb640f
No related branches found
No related tags found
3 merge requests!14feat: added mounted, .bashrc, .zshrc, added tests, added keycloak tests,!8feat(extension): login, open in devcontainer, automaticly save code, open briefing, publish extension,!3feat: devcontainer support
......@@ -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';
......@@ -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';
......@@ -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';
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?;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment