From 45c003e6e44c7e26578dec6fb6eeeee9449902b2 Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Sun, 29 Jan 2023 09:41:03 +0800 Subject: [PATCH] Add docker images auto check and setup support for WAMR-IDE (#1882) 1. Add docker images auto check and setup support for WAMR-IDE 2. Fix bug that the code goes on when user skips install --- .../wamr-ide/VSCode-Extension/package.json | 2 +- .../VSCode-Extension/src/constants.ts | 7 + .../VSCode-Extension/src/extension.ts | 169 +++++++++++++----- .../src/utilities/dockerUtilities.ts | 125 +++++++++++++ .../src/utilities/lldbUtilities.ts | 19 +- 5 files changed, 268 insertions(+), 54 deletions(-) create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/constants.ts create mode 100644 test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts diff --git a/test-tools/wamr-ide/VSCode-Extension/package.json b/test-tools/wamr-ide/VSCode-Extension/package.json index 9b67e3a1e..71cc74871 100644 --- a/test-tools/wamr-ide/VSCode-Extension/package.json +++ b/test-tools/wamr-ide/VSCode-Extension/package.json @@ -6,7 +6,7 @@ }, "displayName": "WAMR-IDE", "description": "An Integrated Development Environment for WASM", - "version": "1.0.0", + "version": "1.1.2", "engines": { "vscode": "^1.59.0" }, diff --git a/test-tools/wamr-ide/VSCode-Extension/src/constants.ts b/test-tools/wamr-ide/VSCode-Extension/src/constants.ts new file mode 100644 index 000000000..cf8bb7103 --- /dev/null +++ b/test-tools/wamr-ide/VSCode-Extension/src/constants.ts @@ -0,0 +1,7 @@ +export const enum SelectionOfPrompt { + skip = 'skip', + setUp = 'setup', +} +export const enum Status { + done = 'done', +} diff --git a/test-tools/wamr-ide/VSCode-Extension/src/extension.ts b/test-tools/wamr-ide/VSCode-Extension/src/extension.ts index 17dda9496..9d979b7ac 100644 --- a/test-tools/wamr-ide/VSCode-Extension/src/extension.ts +++ b/test-tools/wamr-ide/VSCode-Extension/src/extension.ts @@ -24,6 +24,13 @@ import { getWAMRExtensionVersion, } from './utilities/lldbUtilities'; +import { + checkIfDockerStarted, + checkIfDockerImagesExist, + promptSetupDockerImages, +} from './utilities/dockerUtilities'; +import { SelectionOfPrompt } from './constants'; + let wasmTaskProvider: WasmTaskProvider; let wasmDebugConfigProvider: WasmDebugConfigurationProvider; let currentPrjDir = ''; @@ -304,7 +311,7 @@ export async function activate(context: vscode.ExtensionContext) { const disposableBuild = vscode.commands.registerCommand( 'wamride.build', - () => { + async () => { if (!isWasmProject) { vscode.window.showErrorMessage('Build failed', { modal: true, @@ -313,6 +320,28 @@ export async function activate(context: vscode.ExtensionContext) { return; } + try { + /* check if docker images are ready before building */ + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + /**NOTE - if users select to skip install, + * we should return rather than continue + * the execution + */ + if ( + (await promptSetupDockerImages(context)) === + SelectionOfPrompt.skip + ) { + return; + } + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return; + } + generateCMakeFile(includePathArr, excludeFileArr); /* destroy the wasm-toolchain-ctr if it exists */ vscode.commands @@ -382,10 +411,35 @@ export async function activate(context: vscode.ExtensionContext) { /* we should check again whether the user installed lldb, as this can be skipped during activation */ try { if (!isLLDBInstalled(context)) { - await promptInstallLLDB(context); + /**NOTE - if users select to skip install, + * we should return rather than continue + * the execution + */ + if ( + (await promptInstallLLDB(context)) === + SelectionOfPrompt.skip + ) { + return; + } + } + + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + /**NOTE - save as above lldb, should return if + * users select to skip set up + */ + if ( + (await promptSetupDockerImages(context)) === + SelectionOfPrompt.skip + ) { + return; + } } } catch (e) { vscode.window.showWarningMessage((e as Error).message); + return; } /* refuse to debug if build process failed */ @@ -461,48 +515,70 @@ export async function activate(context: vscode.ExtensionContext) { } ); - const disposableRun = vscode.commands.registerCommand('wamride.run', () => { - if (!isWasmProject) { - vscode.window.showErrorMessage('run failed', { - modal: true, - detail: 'Current project is not wasm project, please open wasm project and try again.', - }); - return; - } - - /* refuse to debug if build process failed */ - if (!checkIfBuildSuccess()) { - vscode.window.showErrorMessage('Debug failed', { - modal: true, - detail: 'Can not find WASM binary, please build WASM firstly.', - }); - return; - } - vscode.commands - .executeCommand( - 'workbench.action.tasks.runTask', - 'Destroy: Wasm-Container-Before-Run' - ) - .then(() => { - const disposableAft = vscode.tasks.onDidEndTaskProcess(e => { - if (e.execution.task.name === 'Wasm-Container-Before-Run') { - /* make sure that run wasm task will be executed after destroy task finish */ - vscode.commands - .executeCommand( - 'workbench.action.tasks.runTask', - 'Run: Wasm' - ) - .then(() => { - if (e.exitCode !== 0) { - disposableAft.dispose(); - return; - } - }); - disposableAft.dispose(); - } + const disposableRun = vscode.commands.registerCommand( + 'wamride.run', + async () => { + if (!isWasmProject) { + vscode.window.showErrorMessage('run failed', { + modal: true, + detail: 'Current project is not wasm project, please open wasm project and try again.', }); - }); - }); + return; + } + + try { + /* check if docker images are set up before building */ + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + await promptSetupDockerImages(context); + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return; + } + + /* refuse to debug if build process failed */ + if (!checkIfBuildSuccess()) { + vscode.window.showErrorMessage('Debug failed', { + modal: true, + detail: 'Can not find WASM binary, please build WASM firstly.', + }); + return; + } + + vscode.commands + .executeCommand( + 'workbench.action.tasks.runTask', + 'Destroy: Wasm-Container-Before-Run' + ) + .then(() => { + const disposableAft = vscode.tasks.onDidEndTaskProcess( + e => { + if ( + e.execution.task.name === + 'Wasm-Container-Before-Run' + ) { + /* make sure that run wasm task will be executed when destroy task finish */ + vscode.commands + .executeCommand( + 'workbench.action.tasks.runTask', + 'Run: Wasm' + ) + .then(() => { + if (e.exitCode !== 0) { + disposableAft.dispose(); + return; + } + }); + disposableAft.dispose(); + } + } + ); + }); + } + ); const disposableToggleIncludePath = vscode.commands.registerCommand( 'wamride.build.toggleStateIncludePath', @@ -700,6 +776,13 @@ export async function activate(context: vscode.ExtensionContext) { if (!isLLDBInstalled(context)) { await promptInstallLLDB(context); } + + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + await promptSetupDockerImages(context); + } } catch (e) { vscode.window.showWarningMessage((e as Error).message); } diff --git a/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts b/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts new file mode 100644 index 000000000..0a749ba19 --- /dev/null +++ b/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +import * as vscode from 'vscode'; +import * as cp from 'child_process'; +import * as path from 'path'; +import * as fs from 'fs'; +import { getWAMRExtensionVersion } from './lldbUtilities'; +import { downloadFile, unzipFile } from './directoryUtilities'; +import { SelectionOfPrompt, Status } from '../constants'; + +const DOCKER_IMAGES_TEM_FOLDER_NAME = 'docker-resource'; + +type SelectionStatus = SelectionOfPrompt | Status; + +const execShell = (cmd: string) => + new Promise((resolve, reject) => { + cp.exec(cmd, (error, result) => { + if (error) { + return reject(error); + } + return resolve(result); + }); + }); + +export async function promptSetupDockerImages( + context: vscode.ExtensionContext +): Promise { + const extensionPath = context.extensionPath; + const response = await vscode.window.showWarningMessage( + 'Necessary docker images are not found. Setup now?', + SelectionOfPrompt.setUp, + SelectionOfPrompt.skip + ); + + if (response === SelectionOfPrompt.skip) { + return response; + } + + const downloadUrlArray = getDockerImagesDownloadUrl(context); + + const destinationFolder = path.resolve( + extensionPath, + 'resource', + DOCKER_IMAGES_TEM_FOLDER_NAME + ); + + if (!fs.existsSync(destinationFolder)) { + fs.mkdirSync(destinationFolder); + } + + vscode.window.showInformationMessage(`Downloading Docker Images...`); + + for (const url of downloadUrlArray) { + const imageZipName = path.basename(url); + const imageStorePath = path.join(destinationFolder, imageZipName); + await downloadFile(url, imageStorePath); + + /** + * extract docker image tar package to + * '${destinationFolder}' + */ + const dockerImageFile = await unzipFile(imageStorePath, filename => + path.join(destinationFolder, filename) + ); + /* give access before loading */ + dockerImageFile.forEach(file => fs.chmodSync(file, '0775')); + + /**NOTE - load docker image tar package to host + * right now there are just one file + * `docker-image-name.tar` inside so we can + * directly use files[0] here, should be modified + * if the package's files change + */ + await execShell(`docker load -i ${dockerImageFile[0]}`); + } + + /* remove the DOCKER_IMAGES_TEM_FOLDER */ + fs.rmSync(destinationFolder, { recursive: true, force: true }); + + vscode.window.showInformationMessage( + `Docker images are ready, please run '$docker images' to check.` + ); + + return Status.done; +} + +export async function checkIfDockerStarted(): Promise { + try { + await execShell('docker images'); + return true; + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return false; + } +} + +export async function checkIfDockerImagesExist( + context: vscode.ExtensionContext +): Promise { + try { + /* the tag of images is equal to extension's version */ + const imageTag = getWAMRExtensionVersion(context); + await execShell( + `docker image inspect wasm-debug-server:${imageTag} wasm-toolchain:${imageTag}` + ); + return true; + } catch (e) { + return false; + } +} + +function getDockerImagesDownloadUrl( + context: vscode.ExtensionContext +): string[] { + const wamrVersion = getWAMRExtensionVersion(context); + const wamrReleaseUrl = `https://github.com/bytecodealliance/wasm-micro-runtime/releases/download/WAMR`; + + return [ + `${wamrReleaseUrl}-${wamrVersion}/wasm-debug-server-${wamrVersion}.zip`, + `${wamrReleaseUrl}-${wamrVersion}/wasm-toolchain-${wamrVersion}.zip`, + ]; +} diff --git a/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts b/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts index a1729ab96..210ad0208 100644 --- a/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts +++ b/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts @@ -12,6 +12,7 @@ import { downloadFile, unzipFile, } from './directoryUtilities'; +import { SelectionOfPrompt, Status } from '../constants'; const LLDB_RESOURCE_DIR = 'resource/debug'; const LLDB_OS_DOWNLOAD_URL_SUFFIX_MAP: Partial< @@ -67,18 +68,17 @@ export function isLLDBInstalled(context: vscode.ExtensionContext): boolean { export async function promptInstallLLDB( context: vscode.ExtensionContext -): Promise { +): Promise { const extensionPath = context.extensionPath; - const setupPrompt = 'setup'; - const skipPrompt = 'skip'; + const response = await vscode.window.showWarningMessage( 'No LLDB instance found. Setup now?', - setupPrompt, - skipPrompt + SelectionOfPrompt.setUp, + SelectionOfPrompt.skip ); - if (response === skipPrompt) { - return; + if (response === SelectionOfPrompt.skip) { + return response; } const downloadUrl = getLLDBDownloadUrl(context); @@ -114,7 +114,6 @@ export async function promptInstallLLDB( ); // Remove the bundle.zip - fs.unlink(lldbZipPath, () => { - return; - }); + fs.unlinkSync(lldbZipPath); + return SelectionOfPrompt.setUp; }