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
This commit is contained in:
Wang Ning 2023-01-29 09:41:03 +08:00 committed by GitHub
parent 58316635d4
commit 45c003e6e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 268 additions and 54 deletions

View File

@ -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"
},

View File

@ -0,0 +1,7 @@
export const enum SelectionOfPrompt {
skip = 'skip',
setUp = 'setup',
}
export const enum Status {
done = 'done',
}

View File

@ -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);
}

View File

@ -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`,
];
}

View File

@ -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;
}