Просмотр исходного кода

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
Wang Ning 2 лет назад
Родитель
Сommit
45c003e6e4

+ 1 - 1
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"
     },

+ 7 - 0
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',
+}

+ 125 - 42
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;
-        }
+    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;
+            }
 
-        /* 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();
-                    }
+            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);
     }

+ 125 - 0
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<string>((resolve, reject) => {
+        cp.exec(cmd, (error, result) => {
+            if (error) {
+                return reject(error);
+            }
+            return resolve(result);
+        });
+    });
+
+export async function promptSetupDockerImages(
+    context: vscode.ExtensionContext
+): Promise<SelectionStatus> {
+    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<boolean> {
+    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<boolean> {
+    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`,
+    ];
+}

+ 9 - 10
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<void> {
+): Promise<SelectionOfPrompt> {
     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;
 }