From d58e123e7013208ff3f03d07d2c336ff2950b617 Mon Sep 17 00:00:00 2001 From: Guillaume WEBER <gweber@takima.fr> Date: Wed, 29 Jun 2022 14:44:44 +0000 Subject: [PATCH] feat: make mission workdir constant --- .../deadlock-extension/package.json | 16 +------ .../src/core/commandHandler.ts | 5 -- .../deadlock-extension/src/core/config.ts | 1 + .../deadlock-extension/src/core/controller.ts | 46 +++---------------- .../src/core/extensionStore.ts | 33 +------------ .../src/core/mission/missionDevContainer.ts | 5 +- .../src/recorder/utils/workdir.ts | 21 +++++---- .../src/view/quickSetupView.ts | 16 +------ .../src/view/startedMissionsView.ts | 15 +++--- 9 files changed, 31 insertions(+), 127 deletions(-) diff --git a/deadlock-plugins/deadlock-extension/package.json b/deadlock-plugins/deadlock-extension/package.json index 162f9db1..5cacb477 100644 --- a/deadlock-plugins/deadlock-extension/package.json +++ b/deadlock-plugins/deadlock-extension/package.json @@ -30,11 +30,6 @@ "title": "Open Deadlock quick setup page", "category": "Deadlock Coding" }, - { - "command": "deadlock.chooseMissionWorkdir", - "title": "Choose mission workdir", - "category": "Deadlock Coding" - }, { "command": "deadlock.disconnect", "title": "Clear cache", @@ -83,16 +78,7 @@ "view": "help", "contents": "[Quick Setup](command:deadlock.openQuickSetup)\n" } - ], - "menus": { - "view/title": [ - { - "command": "deadlock.chooseMissionWorkdir", - "when": "view == deadlockPanel" - } - ], - "view/item/context": [] - } + ] }, "scripts": { "vsce-package": "vsce package --allow-missing-repository", diff --git a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts index fe216cce..85a89d5c 100644 --- a/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts +++ b/deadlock-plugins/deadlock-extension/src/core/commandHandler.ts @@ -7,16 +7,11 @@ export class CommandHandler { } initCommandHandler() { - commands.registerCommand( - chooseMissionWorkdirCommand.cmd, - this.controller.chooseMissionWorkdir.bind(this.controller), - ); commands.registerCommand(disconnectCommand.cmd, this.controller.disconnect.bind(this.controller)); commands.registerCommand(authenticateCommand.cmd, this.controller.authenticate.bind(this.controller)); } } -export const chooseMissionWorkdirCommand = new Command('Choose mission workdir', 'deadlock.chooseMissionWorkdir'); export const disconnectCommand = new Command('Disconnect', 'deadlock.disconnect'); export const authenticateCommand = new Command('Authenticate', 'deadlock.authenticate'); export const openUrlInBrowserCommand = new Command('Open url in browser', 'vscode.open'); diff --git a/deadlock-plugins/deadlock-extension/src/core/config.ts b/deadlock-plugins/deadlock-extension/src/core/config.ts index 9dbf60ba..93934ffa 100644 --- a/deadlock-plugins/deadlock-extension/src/core/config.ts +++ b/deadlock-plugins/deadlock-extension/src/core/config.ts @@ -10,6 +10,7 @@ const deadlockExtensionPath = path.join(homeDir, 'deadlock-extension'); const deadlockConfigPath = path.join(homeDir, '.deadlock'); export const userSshKeyFolderPath = path.join(deadlockConfigPath, '.ssh'); +export const missionWorkdir = path.join(deadlockConfigPath, 'workspace'); export const PROJECT_SRC_PATH = onContainer ? '/project' : path.join(homeDir, 'deadlock-extension', '/project'); diff --git a/deadlock-plugins/deadlock-extension/src/core/controller.ts b/deadlock-plugins/deadlock-extension/src/core/controller.ts index 70a7e01f..90076cca 100644 --- a/deadlock-plugins/deadlock-extension/src/core/controller.ts +++ b/deadlock-plugins/deadlock-extension/src/core/controller.ts @@ -1,7 +1,7 @@ import { KEYCLOAK_DEVICE_AUTH_URL, KEYCLOAK_TOKEN_CREATE_URL, KEYCLOAK_USER_INFO_URL } from '../config'; import BriefingView from '../view/briefingView'; import QuickSetupView from '../view/quickSetupView'; -import { chooseMissionWorkdirCommand, CommandHandler, openUrlInBrowserCommand } from './commandHandler'; +import { CommandHandler, openUrlInBrowserCommand } from './commandHandler'; import ExtensionStore from './extensionStore'; import KeycloakOAuth2DeviceFlowConnection from './keycloakOAuth2DeviceFlowConnection'; import ApiService from './api.service'; @@ -11,8 +11,8 @@ import { MissionDevContainer } from './mission/missionDevContainer'; import { extensionLog as log } from '../recorder/utils/log'; import { commands, ExtensionContext, Uri, window } from 'vscode'; import { createSshKeyFiles } from './sshKeyManager'; -import { removeFiles } from '../recorder/utils/workdir'; -import { userSshKeyFolderPath } from './config'; +import { emptyDirectories, removeFilesOrDirectories } from '../recorder/utils/workdir'; +import { missionWorkdir, userSshKeyFolderPath } from './config'; import { hasStatusNumber } from './utils/typeguards'; import { User } from './mission/models/userChallenge'; @@ -79,28 +79,9 @@ export default class Controller { this.quickSetupView.isAlreadyConnected = (await this.extensionStore.getAccessToken()) !== undefined; } - async chooseMissionWorkdir() { - const actualMissionWorkDir = this.extensionStore.getMissionWorkdir(); - - const folderUri = await window.showOpenDialog({ - defaultUri: actualMissionWorkDir ? Uri.file(actualMissionWorkDir) : undefined, - canSelectFolders: true, - canSelectFiles: false, - title: 'Choisis le dossier qui contiendra tes missions', - }); - - if (!folderUri) { - if (this.extensionStore.getMissionWorkdir()) { - return; - } - this.chooseMissionWorkdir(); - } else { - this.extensionStore.setMissionWorkdir(folderUri[0].path); - } - } - public async disconnect() { - await removeFiles(`${userSshKeyFolderPath}/id_rsa`, `${userSshKeyFolderPath}/id_rsa.pub`); + await removeFilesOrDirectories(`${userSshKeyFolderPath}/id_rsa`, `${userSshKeyFolderPath}/id_rsa.pub`); + await emptyDirectories(missionWorkdir); await this.extensionStore.clear(); this.quickSetupView.isAlreadyConnected = false; } @@ -125,10 +106,6 @@ export default class Controller { public async launchMission(missionId: string, missionVersion: string, userId?: string) { window.showInformationMessage(`vous lancez la mission ${missionId}`); - const hadMissionWorkdir = this.extensionStore.getMissionWorkdir() !== undefined; - if (!hadMissionWorkdir) { - await commands.executeCommand(chooseMissionWorkdirCommand.cmd); - } const hadBeenConnected = (await this.extensionStore.getAccessToken()) !== undefined; @@ -139,8 +116,6 @@ export default class Controller { const mission = new Mission(missionId, missionVersion); - const missionsWorkdir = this.extensionStore.getMissionWorkdir() ?? ''; - const currentUser = await this.apiService.getCurrentUser(); const user: User = userId ? await this.apiService.getUser(userId) : currentUser; @@ -162,17 +137,8 @@ export default class Controller { const giteaPublicProperties: GiteaPublicProperties = await this.apiService.getGiteaPublicProperties(); - const missionDevcontainer = new MissionDevContainer( - missionsWorkdir, - user, - currentUser, - mission, - giteaPublicProperties, - ); + const missionDevcontainer = new MissionDevContainer(user, currentUser, mission, giteaPublicProperties); - window.showInformationMessage( - 'opening inside folder ' + this.extensionStore.getMissionWorkdir()! + '/' + missionId, - ); try { await missionDevcontainer.open(); } catch { diff --git a/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts index 17cd1edf..2ccb8749 100644 --- a/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts +++ b/deadlock-plugins/deadlock-extension/src/core/extensionStore.ts @@ -1,25 +1,15 @@ -import { ExtensionContext, Memento, SecretStorage, window } from 'vscode'; +import { ExtensionContext, SecretStorage } from 'vscode'; import { extensionLog as log } from '../recorder/utils/log'; -type GlobalStorageType = Memento & { setKeysForSync(keys: readonly string[]): void }; - export default class ExtensionStore { private static instance: ExtensionStore; - - private globalStorage: GlobalStorageType; private secretStorage: SecretStorage; private constructor(context: ExtensionContext) { - this.globalStorage = context.globalState; this.secretStorage = context.secrets; } public async clear() { - if (this.globalStorage.keys()) { - for (const key of this.globalStorage.keys()) { - this.globalStorage.update(key, undefined); - } - } if (await this.secretStorage.get(SecretStoreKey.AccessTokenKey)) this.secretStorage.delete(SecretStoreKey.AccessTokenKey); if (await this.secretStorage.get(SecretStoreKey.RefreshTokenKey)) @@ -35,23 +25,6 @@ export default class ExtensionStore { return ExtensionStore.instance; } - public getMissionWorkdir(): string | undefined { - return this.readStringKey(GlobalStoreKey.MissionWorkdirKey); - } - - public setMissionWorkdir(path: string) { - this.storeStringKey(GlobalStoreKey.MissionWorkdirKey, path); - window.showInformationMessage(`Nouveau dossier de stockage des missions: ${path}`); - } - - private readStringKey(key: GlobalStoreKey): string | undefined { - return this.globalStorage.get<string>(key); - } - - private storeStringKey(key: GlobalStoreKey, value: string) { - this.globalStorage.update(key, value); - } - public getAccessToken(): Thenable<string | undefined> { return this.readSecret(SecretStoreKey.AccessTokenKey); } @@ -89,7 +62,3 @@ enum SecretStoreKey { AccessTokenKey = 'access-token-key', RefreshTokenKey = 'refresh-token-key', } - -enum GlobalStoreKey { - MissionWorkdirKey = 'mission-workdir-key', -} diff --git a/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts index 9b2e8a6c..cffd1d2b 100644 --- a/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts +++ b/deadlock-plugins/deadlock-extension/src/core/mission/missionDevContainer.ts @@ -1,4 +1,4 @@ -import { userSshKeyFolderPath } from '../config'; +import { missionWorkdir, userSshKeyFolderPath } from '../config'; import { Base, DockerfileSpecific, LifecycleScripts, VSCodespecific } from './models/devContainer'; import { mkdir, writeFile } from 'fs/promises'; import { Mission } from './models/mission'; @@ -31,13 +31,12 @@ export class MissionDevContainer { private readonly dirs: { missionWorkdir: string; config: string; devcontainer: string; mounted: string }; constructor( - private readonly missionsWorkdir: string, private readonly user: User, private readonly currentUser: User, private readonly mission: Mission, private readonly giteaProperties: GiteaPublicProperties, ) { - let prefix = `${this.missionsWorkdir}`; + let prefix = missionWorkdir; if (this.isReviewingStudent()) { prefix += `/students/${this.user.details.lastName}_${this.user.details.firstName}_${this.user.id}`; } diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts index f528864d..c81a9abe 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/utils/workdir.ts @@ -1,10 +1,10 @@ import { exec as execCallback, execSync } from 'child_process'; -import { copyFileSync, existsSync, lstatSync, PathLike, readdirSync, renameSync, rmdirSync, promises } from 'fs'; +import { copyFileSync, existsSync, lstatSync, PathLike, readdirSync, renameSync, rmdirSync } from 'fs'; import { join } from 'path'; import { log } from './log'; import { promisify } from 'util'; +import { mkdir, rmdir, unlink, rm } from 'fs/promises'; -const { unlink } = promises; const exec = promisify(execCallback); const PREFIX = '[DEADLOCK-RECORDER]'; @@ -82,10 +82,15 @@ export function copyGitUserFiles(srcPath: string, destPath: string, userId: stri copyFileIfExistsSync(join(srcPath, '.gitignore'), join(destPath, `user-gitignore-${userId}`)); } -export async function removeFiles(...paths: string[]) { - for (const path of paths) { - if (existsSync(path)) { - await unlink(path); - } - } +export async function removeFilesOrDirectories(...paths: string[]) { + paths.filter(existsSync).forEach(async (path) => { + await rm(path, { recursive: true }); + }); +} + +export async function emptyDirectories(...directoryPaths: string[]) { + directoryPaths.forEach(async (directoryPath) => { + await rmdir(directoryPath, { recursive: true }); + await mkdir(directoryPath); + }); } diff --git a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts index 5fb0bc98..c64d69c1 100644 --- a/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts +++ b/deadlock-plugins/deadlock-extension/src/view/quickSetupView.ts @@ -1,5 +1,5 @@ import { commands, Uri } from 'vscode'; -import { authenticateCommand, chooseMissionWorkdirCommand, disconnectCommand } from '../core/commandHandler'; +import { authenticateCommand, disconnectCommand } from '../core/commandHandler'; import ExtensionStore from '../core/extensionStore'; import { extensionLog as log } from '../recorder/utils/log'; import { openQuickSetupCommand } from '../theia/command'; @@ -38,8 +38,6 @@ export default class QuickSetupView extends WebviewBase { } renderHtmlBody() { - const hadMissionWorkdir = this.extensionStore.getMissionWorkdir() !== undefined; - return ` <h1>Quick Setup</h1> <div class="deadlock-getting-started-card-container"> @@ -58,15 +56,6 @@ export default class QuickSetupView extends WebviewBase { }, this._isAlreadyConnected, )} - ${this.renderCardHtml( - 'Dossier contenant tes exercices', - 'Choisis le dossier qui contiendra tous les exercices Deadlock.', - { - name: 'Choisir un dossier', - onClickFunctionName: 'launchChooseMissionWorkdirAction', - }, - hadMissionWorkdir, - )} </div> `; } @@ -124,9 +113,6 @@ export default class QuickSetupView extends WebviewBase { onMessageReceive(message: any): void { switch (message.command) { - case 'launchChooseMissionWorkdirAction': - commands.executeCommand(chooseMissionWorkdirCommand.cmd).then(() => this.reload()); - return; case 'openAuthenticationPageAction': commands.executeCommand(authenticateCommand.cmd); return; diff --git a/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts b/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts index 463d15df..75378b46 100644 --- a/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts +++ b/deadlock-plugins/deadlock-extension/src/view/startedMissionsView.ts @@ -2,17 +2,15 @@ import { randomBytes } from 'crypto'; import { existsSync, readdirSync, readFileSync } from 'fs'; import { join } from 'path'; import { ExtensionContext, Webview, WebviewView, WebviewViewProvider, window } from 'vscode'; +import { missionWorkdir } from '../core/config'; import Controller from '../core/controller'; -import ExtensionStore from '../core/extensionStore'; import UserChallenge from '../core/mission/models/userChallenge'; import { extensionWarn } from '../recorder/utils/log'; import { getUri } from './webviewBase'; export default class StartedMissionsView implements WebviewViewProvider { private readonly controller: Controller; - private readonly missionsWorkdir: string; constructor(private context: ExtensionContext) { - this.missionsWorkdir = ExtensionStore.getInstance(this.context).getMissionWorkdir() ?? ''; this.controller = Controller.getInstance(context); } @@ -30,7 +28,7 @@ export default class StartedMissionsView implements WebviewViewProvider { switch (message.command) { case 'openMission': { window.showInformationMessage('click received: ' + message.mission); - const path = join(this.missionsWorkdir, message.mission, '.config', 'user-challenge.json'); + const path = join(missionWorkdir, message.mission, '.config', 'user-challenge.json'); const userChallenge: UserChallenge = JSON.parse(readFileSync(path, 'utf8')); this.controller.launchMission(userChallenge.missionId, userChallenge.missionVersion); return; @@ -52,14 +50,13 @@ export default class StartedMissionsView implements WebviewViewProvider { const js = getUri(webview, this.context.extensionUri, ['resources', 'js', 'startedMissionsView.js']); // find all folders in mission directory - const path = this.missionsWorkdir; let missionsHtml = ''; - existsSync(path) && - readdirSync(path).forEach((mission) => { - if (existsSync(join(path, mission, '.config', 'user-challenge.json'))) { + existsSync(missionWorkdir) && + readdirSync(missionWorkdir).forEach((mission) => { + if (existsSync(join(missionWorkdir, mission, '.config', 'user-challenge.json'))) { try { const userChallenge: UserChallenge = JSON.parse( - readFileSync(join(path, mission, '.config', 'user-challenge.json'), 'utf8'), + readFileSync(join(missionWorkdir, mission, '.config', 'user-challenge.json'), 'utf8'), ); missionsHtml += `<vscode-button onclick="openMission('${userChallenge.missionId}')" class="item" appearance="primary">${userChallenge.missionId}</vscode-button>`; } catch (e) { -- GitLab