This commit is contained in:
dilin-MS 2020-01-10 00:12:06 +08:00
Родитель f81123de5a
Коммит afdd0dad0f
93 изменённых файлов: 22282 добавлений и 22453 удалений

7
.eslintignore Normal file
Просмотреть файл

@ -0,0 +1,7 @@
# don't ever lint node_modules
node_modules
# don't lint build output (make sure it's set to your correct build folder name)
out
assets
views
vendor/node-usb-native

41
.eslintrc.json Normal file
Просмотреть файл

@ -0,0 +1,41 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"env": {
"browser": true,
"es6": true,
"node": true,
"mocha": true,
"amd": true,
"commonjs": true
},
"plugins": [
"@typescript-eslint/eslint-plugin"
],
"rules": {
"no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
"no-dupe-class-members": "off",
"@typescript-eslint/no-empty-function": ["error", { "allow": ["constructors"] }],
"object-curly-spacing": ["error", "always"],
"indent": ["error", 2],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-use-before-define": "off"
},
"overrides": [
{
// enable the rule specifically for TypeScript files
"files": ["*.ts", "*.tsx"],
"rules": {
"@typescript-eslint/explicit-function-return-type": ["error"]
}
}
]
}

20
.vscode/settings.json поставляемый
Просмотреть файл

@ -6,5 +6,25 @@
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
},
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
{"language": "typescript", "autoFix": true },
{"language": "typescriptreact", "autoFix": true }
],
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": false,
},
"[javascriptreact]": {
"editor.formatOnSave": false,
},
"[typescript]": {
"editor.formatOnSave": false,
},
"[typescriptreact]": {
"editor.formatOnSave": false,
}
}

Просмотреть файл

@ -5,7 +5,7 @@ function command(cmd, callback) {
if (!cmd) {
return;
}
let args = Array.from(arguments);
const args = Array.from(arguments);
if (typeof args[args.length - 1] === 'function') {
callback = args[args.length - 1];
args.length = args.length - 1;

Просмотреть файл

@ -4,7 +4,7 @@ const IS_PUBLIC_URL = "?public";
const VALUE = "value";
const ALL = "All";
var repository = new Vue({
const repository = new Vue({
el: "#main",
data: {
companyName: _location.search === IS_PUBLIC_URL ? "Public repository" : "Company repository",

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1 +0,0 @@
node node_modules/gts/build/src/cli.js %*

1749
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -229,9 +229,8 @@
"watch": "tsc -watch -p ./ && node scripts/copyVendor.js",
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "npm run compile && node ./node_modules/vscode/bin/test",
"check": "gts check",
"clean": "gts clean",
"fix": "gts fix",
"check": "eslint . --ext .js,.jsx,.ts,.tsx",
"fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"prepare": "npm run compile",
"pretest": "npm run compile",
"posttest": "npm run check",
@ -241,26 +240,28 @@
"@types/adm-zip": "^0.4.31",
"@types/crc": "^3.4.0",
"@types/extract-zip": "^1.6.2",
"@types/fs-extra": "^7.0.0",
"@types/fs-plus": "^3.0.0",
"@types/glob": "^7.1.1",
"@types/lodash.filter": "^4.6.6",
"@types/lodash.foreach": "^4.5.6",
"@types/lodash.trimstart": "^4.5.6",
"@types/lodash.uniq": "^4.5.4",
"@types/mocha": "^2.2.42",
"@types/node": "^10.14.20",
"@types/node": "^10.17.13",
"@types/opn": "3.0.28",
"@types/request-promise": "^4.1.44",
"@types/ssh2": "^0.5.39",
"@types/unzip": "^0.1.0",
"@types/winreg": "^1.2.30",
"@types/request-promise": "^4.1.44",
"@types/glob": "^7.1.1",
"@typescript-eslint/eslint-plugin": "^2.15.0",
"@typescript-eslint/parser": "^2.15.0",
"eslint": "^6.8.0",
"glob": "^7.1.4",
"gts": "^0.5.4",
"typescript": "^2.6.2",
"typescript": "^3.2.1",
"vscode": "^1.1.33",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"@types/fs-extra": "^7.0.0"
"webpack": "^4.41.5",
"webpack-cli": "^3.3.9"
},
"dependencies": {
"adm-zip": "^0.4.11",

Просмотреть файл

@ -1,34 +1,5 @@
const fs = require('fs');
/**
* If Nightly Build or Production release or RC release, modify package.json and related template files.
* If common PR, do no modification.
* TRAVIS_EVENT_TYPE === "cron" : Nightly Build
* TRAVIS_TAG =~ /^v?[0-9]+\.[0-9]+\.[0-9]+$/: Production release (eg. v0.10.18)
* TRAVIS_TAG =~ /^v?[0-9]+\.[0-9]+\.[0-9]+-[rR][cC]/: RC release (eg. v0.10.18-rc, v0.10.18-rc2, etc.)
*/
const packageJson = JSON.parse(fs.readFileSync('package.json'));
// Nightly Build
if (process.env.BUILD_REASON === "Schedule") {
const nightlyBuildName = "test-owl-project-nightly";
const nightlyBuildDisplayName = "Test OWL Project (Nightly)";
updateConfigForNonProduction(packageJson, nightlyBuildName, nightlyBuildDisplayName);
} else if (process.env.IS_PROD) {
// Update resource link
const codeGenUrl = "https://aka.ms/iot-codegen-cli-for-workbench";
packageJson.codeGenConfigUrl = codeGenUrl;
// Update production AI Key
packageJson.aiKey = process.env.PROD_AIKEY;
} else if (process.env.IS_TEST) {
const testName = "test-owl-project";
const testDisplayName = "Test OWL Project RC";
updateConfigForNonProduction(packageJson, testName, testDisplayName);
}
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2) + '\n');
/**
* Update package.json with test name, displayName, publisher, ai aky.
* Trim version number. Delete extension icon.
@ -65,4 +36,32 @@ function updateConfigForNonProduction(packageJson, testName, testDisplayName) {
const replaceJson = originalJsonFile.replace(extensionIdPattern, testExtensionId.toLowerCase());
fs.writeFileSync(filePath, replaceJson);
});
}
}
/**
* If Nightly Build or Production release or RC release, modify package.json and related template files.
* If common PR, do no modification.
* TRAVIS_EVENT_TYPE === "cron" : Nightly Build
* TRAVIS_TAG =~ /^v?[0-9]+\.[0-9]+\.[0-9]+$/: Production release (eg. v0.10.18)
* TRAVIS_TAG =~ /^v?[0-9]+\.[0-9]+\.[0-9]+-[rR][cC]/: RC release (eg. v0.10.18-rc, v0.10.18-rc2, etc.)
*/
const packageJson = JSON.parse(fs.readFileSync('package.json'));
// Nightly Build
if (process.env.BUILD_REASON === "Schedule") {
const nightlyBuildName = "test-owl-project-nightly";
const nightlyBuildDisplayName = "Test OWL Project (Nightly)";
updateConfigForNonProduction(packageJson, nightlyBuildName, nightlyBuildDisplayName);
} else if (process.env.IS_PROD) {
// Update resource link
const codeGenUrl = "https://aka.ms/iot-codegen-cli-for-workbench";
packageJson.codeGenConfigUrl = codeGenUrl;
// Update production AI Key
packageJson.aiKey = process.env.PROD_AIKEY;
} else if (process.env.IS_TEST) {
const testName = "test-owl-project";
const testDisplayName = "Test OWL Project RC";
updateConfigForNonProduction(packageJson, testName, testDisplayName);
}
fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2) + '\n');

Просмотреть файл

@ -3,18 +3,18 @@
import * as vscode from 'vscode';
import {ArduinoCommands} from './common/Commands';
import {Board, BoardInstallation} from './Models/Interfaces/Board';
import { ArduinoCommands } from './common/Commands';
import { Board, BoardInstallation } from './Models/Interfaces/Board';
export class ArduinoPackageManager {
private static INSTALLED_BOARDS: Board[] = [];
private static async setAdditionalUrl(url: string) {
private static async setAdditionalUrl(url: string): Promise<void> {
const existedUrls =
vscode.workspace.getConfiguration().get<string[]|string>(
'arduino.additionalUrls');
'arduino.additionalUrls');
if (!existedUrls || existedUrls.length === 0) {
await vscode.workspace.getConfiguration().update(
'arduino.additionalUrls', url, vscode.ConfigurationTarget.Global);
'arduino.additionalUrls', url, vscode.ConfigurationTarget.Global);
} else {
let _existedUrls: string[];
if (typeof existedUrls === 'string') {
@ -30,17 +30,17 @@ export class ArduinoPackageManager {
_existedUrls.push(url);
if (typeof existedUrls === 'string') {
await vscode.workspace.getConfiguration().update(
'arduino.additionalUrls', _existedUrls.join(','),
vscode.ConfigurationTarget.Global);
'arduino.additionalUrls', _existedUrls.join(','),
vscode.ConfigurationTarget.Global);
} else {
await vscode.workspace.getConfiguration().update(
'arduino.additionalUrls', _existedUrls,
vscode.ConfigurationTarget.Global);
'arduino.additionalUrls', _existedUrls,
vscode.ConfigurationTarget.Global);
}
}
}
static async installBoard(board: Board) {
static async installBoard(board: Board): Promise<void> {
if (!board || !board.installation) {
return;
}
@ -58,10 +58,10 @@ export class ArduinoPackageManager {
try {
await ArduinoPackageManager.setAdditionalUrl(
board.installation.additionalUrl);
board.installation.additionalUrl);
await vscode.commands.executeCommand(
ArduinoCommands.InstallBoard, board.installation.packageName,
board.installation.architecture);
ArduinoCommands.InstallBoard, board.installation.packageName,
board.installation.architecture);
ArduinoPackageManager.INSTALLED_BOARDS.push(board);
} catch (ignore) {
// If we failed to install board package,

Просмотреть файл

@ -5,16 +5,12 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import {TelemetryContext} from './telemetry';
import {constructAndLoadIoTProject} from './utils';
import {RemoteExtension} from './Models/RemoteExtension';
import {CancelOperationError} from './CancelOperationError';
import { TelemetryContext } from './telemetry';
import { constructAndLoadIoTProject } from './utils';
import { RemoteExtension } from './Models/RemoteExtension';
export class AzureOperator {
async provision(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
async provision(context: vscode.ExtensionContext, channel: vscode.OutputChannel, telemetryContext: TelemetryContext): Promise<void> {
const iotProject =
await constructAndLoadIoTProject(context, channel, telemetryContext);
if (!iotProject) {
@ -26,9 +22,7 @@ export class AzureOperator {
}
}
async deploy(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
async deploy(context: vscode.ExtensionContext, channel: vscode.OutputChannel, telemetryContext: TelemetryContext): Promise<void> {
// Azure deploy command can be executed only in local environment
const isLocal = RemoteExtension.checkLocalBeforeRunCommand(context);
if (!isLocal) {

Просмотреть файл

@ -6,13 +6,11 @@
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import {TelemetryContext} from './telemetry';
import {constructAndLoadIoTProject} from './utils';
import { TelemetryContext } from './telemetry';
import { constructAndLoadIoTProject } from './utils';
export class DeviceOperator {
async compile(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
async compile(context: vscode.ExtensionContext, channel: vscode.OutputChannel, telemetryContext: TelemetryContext): Promise<void> {
const iotProject =
await constructAndLoadIoTProject(context, channel, telemetryContext);
if (!iotProject) {
@ -21,9 +19,7 @@ export class DeviceOperator {
await iotProject.compile();
}
async upload(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
async upload(context: vscode.ExtensionContext, channel: vscode.OutputChannel, telemetryContext: TelemetryContext): Promise<void> {
const iotProject =
await constructAndLoadIoTProject(context, channel, telemetryContext);
if (!iotProject) {
@ -32,9 +28,7 @@ export class DeviceOperator {
await iotProject.upload();
}
async configDeviceSettings(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
async configDeviceSettings(context: vscode.ExtensionContext, channel: vscode.OutputChannel, telemetryContext: TelemetryContext): Promise<void> {
const iotProject =
await constructAndLoadIoTProject(context, channel, telemetryContext);
if (!iotProject) {

Просмотреть файл

@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {MessageItem} from 'vscode';
import { MessageItem } from 'vscode';
export class DialogResponses {
static skipForNow: MessageItem = {title: 'Skip for now'};
static all: MessageItem = {title: 'All'};
static yes: MessageItem = {title: 'Yes'};
static no: MessageItem = {title: 'No'};
static cancel: MessageItem = {title: 'Cancel', isCloseAffordance: true};
static skipForNow: MessageItem = { title: 'Skip for now' };
static all: MessageItem = { title: 'All' };
static yes: MessageItem = { title: 'Yes' };
static no: MessageItem = { title: 'No' };
static cancel: MessageItem = { title: 'Cancel', isCloseAffordance: true };
}

Просмотреть файл

@ -11,20 +11,20 @@ import * as path from 'path';
import request = require('request-promise');
import * as utils from '../utils';
import {FileNames, ConfigKey, ScaffoldType, OSPlatform} from '../constants';
import {TelemetryContext} from '../telemetry';
import {DigitalTwinConstants} from './DigitalTwinConstants';
import {CodeGenProjectType, DeviceConnectionType, CodeGenLanguage, DeviceSdkReferenceType, CodeGenExecutionItem} from './DigitalTwinCodeGen/Interfaces/CodeGenerator';
import {AnsiCCodeGeneratorFactory} from './DigitalTwinCodeGen/AnsiCCodeGeneratorFactory';
import {ConfigHandler} from '../configHandler';
import {PnpDeviceConnection, CodeGenProjectTemplate, DeviceSdkReference} from '../Models/Interfaces/ProjectTemplate';
import {DialogResponses} from '../DialogResponses';
import {RemoteExtension} from '../Models/RemoteExtension';
import {DigitalTwinUtility} from './DigitalTwinUtility';
import {CodeGenUtility} from './DigitalTwinCodeGen/CodeGenUtility';
import {FileUtility} from '../FileUtility';
import {CancelOperationError} from '../CancelOperationError';
import {Utility} from './pnp/src/common/utility';
import { FileNames, ConfigKey, ScaffoldType, OSPlatform } from '../constants';
import { TelemetryContext } from '../telemetry';
import { DigitalTwinConstants } from './DigitalTwinConstants';
import { CodeGenProjectType, DeviceConnectionType, CodeGenLanguage, DeviceSdkReferenceType, CodeGenExecutionItem } from './DigitalTwinCodeGen/Interfaces/CodeGenerator';
import { AnsiCCodeGeneratorFactory } from './DigitalTwinCodeGen/AnsiCCodeGeneratorFactory';
import { ConfigHandler } from '../configHandler';
import { PnpDeviceConnection, CodeGenProjectTemplate, DeviceSdkReference } from '../Models/Interfaces/ProjectTemplate';
import { DialogResponses } from '../DialogResponses';
import { RemoteExtension } from '../Models/RemoteExtension';
import { DigitalTwinUtility } from './DigitalTwinUtility';
import { CodeGenUtility } from './DigitalTwinCodeGen/CodeGenUtility';
import { FileUtility } from '../FileUtility';
import { CancelOperationError } from '../CancelOperationError';
import { Utility } from './pnp/src/common/utility';
interface CodeGeneratorDownloadLocation {
win32Md5: string;
@ -60,10 +60,31 @@ enum ReGenResult {
Skipped
}
function compareVersion(verion1: string, verion2: string): 1 | -1 | 0 {
const ver1 = verion1.split('.');
const ver2 = verion2.split('.');
let i = 0;
let v1: number, v2: number;
/* default is 0, version format should be 1.1.0 */
while (i < 3) {
v1 = Number(ver1[i]);
v2 = Number(ver2[i]);
if (v1 > v2) return 1;
if (v1 < v2) return -1;
i++;
}
return 0;
}
function localCodeGenCliPath(): string {
return path.join(os.homedir(), DigitalTwinConstants.codeGenCliFolder);
}
export class CodeGeneratorCore {
async generateDeviceCodeStub(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> {
const isLocal = RemoteExtension.checkLocalBeforeRunCommand(context);
if (!isLocal) {
return;
@ -86,7 +107,7 @@ export class CodeGeneratorCore {
// Prompt if old project exists for the same Capability Model file
const regenResult = await this.regenCode(
rootPath, capabilityModelFilePath, context, channel, telemetryContext);
rootPath, capabilityModelFilePath, context, channel, telemetryContext);
if (regenResult === ReGenResult.Succeeded) {
return;
}
@ -107,15 +128,15 @@ export class CodeGeneratorCore {
// Select project template
const codeGenProjectType = await this.selectProjectTemplate(
channel, codeGenLanguage, codeGenOptions);
channel, codeGenLanguage, codeGenOptions);
// Select Device SDK reference type for CMake project
const sdkReferenceType = await this.selectDeviceSdkReferenceType(
channel, codeGenProjectType, codeGenOptions);
channel, codeGenProjectType, codeGenOptions);
// Download dependent interface of capability model
if (!await DigitalTwinUtility.downloadDependentInterface(
rootPath, capabilityModelFilePath)) {
rootPath, capabilityModelFilePath)) {
throw new Error(`Failed to download dependent interface.`);
}
@ -132,19 +153,19 @@ export class CodeGeneratorCore {
const scaffoldType = ScaffoldType.Local;
await this.saveCodeGenConfig(
scaffoldType, rootPath, capabilityModelFilePath, codeGenExecutionInfo);
scaffoldType, rootPath, capabilityModelFilePath, codeGenExecutionInfo);
await this.generateDeviceCodeCore(
codeGenExecutionInfo, context, channel, telemetryContext);
codeGenExecutionInfo, context, channel, telemetryContext);
}
private async regenCode(
rootPath: string, capabilityModelFilePath: string,
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<ReGenResult> {
rootPath: string, capabilityModelFilePath: string,
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<ReGenResult> {
const codeGenConfigPath = path.join(
rootPath, FileNames.vscodeSettingsFolderName,
DigitalTwinConstants.codeGenConfigFileName);
rootPath, FileNames.vscodeSettingsFolderName,
DigitalTwinConstants.codeGenConfigFileName);
let codeGenExecutionItem: CodeGenExecutionItem|undefined;
@ -158,7 +179,7 @@ export class CodeGeneratorCore {
JSON.parse(fs.readFileSync(codeGenConfigPath, 'utf8'));
if (codeGenExecutions) {
codeGenExecutionItem = codeGenExecutions.codeGenExecutionItems.find(
item => item.capabilityModelFilePath === capabilityModelFilePath);
item => item.capabilityModelFilePath === capabilityModelFilePath);
}
} catch {
// just skip this if read file failed.
@ -168,15 +189,15 @@ export class CodeGeneratorCore {
const regenOptions: vscode.QuickPickItem[] = [];
// select the target of the code stub
regenOptions.push(
{
label: `Re-generate code for ${codeGenExecutionItem.projectName}`,
description: ''
},
{label: 'Create new project', description: ''});
{
label: `Re-generate code for ${codeGenExecutionItem.projectName}`,
description: ''
},
{ label: 'Create new project', description: '' });
const regenSelection = await vscode.window.showQuickPick(
regenOptions,
{ignoreFocusOut: true, placeHolder: 'Please select an option:'});
regenOptions,
{ ignoreFocusOut: true, placeHolder: 'Please select an option:' });
if (!regenSelection) {
throw new CancelOperationError('Re-generate code selection cancelled.');
@ -185,19 +206,19 @@ export class CodeGeneratorCore {
// User select regenerate code
if (regenSelection.label !== 'Create new project') {
if (!await DigitalTwinUtility.downloadDependentInterface(
rootPath, capabilityModelFilePath)) {
rootPath, capabilityModelFilePath)) {
return ReGenResult.Skipped;
}
utils.channelShowAndAppendLine(
channel,
`${
DigitalTwinConstants
.dtPrefix} Regenerate device code using an existing CodeGen configure:`);
channel,
`${
DigitalTwinConstants
.dtPrefix} Regenerate device code using an existing CodeGen configure:`);
CodeGenUtility.printCodeGenConfig(codeGenExecutionItem, channel);
await this.generateDeviceCodeCore(
codeGenExecutionItem, context, channel, telemetryContext);
codeGenExecutionItem, context, channel, telemetryContext);
return ReGenResult.Succeeded;
} else {
return ReGenResult.Skipped;
@ -208,7 +229,7 @@ export class CodeGeneratorCore {
}
private async getCodeGenProjectName(
channel: vscode.OutputChannel, rootPath: string): Promise<string> {
channel: vscode.OutputChannel, rootPath: string): Promise<string> {
// select the project name for code gen
const codeGenProjectName = await vscode.window.showInputBox({
placeHolder: 'Please input the project name here.',
@ -219,7 +240,7 @@ export class CodeGeneratorCore {
}
if (!DigitalTwinConstants.codegenProjectNameRegex.test(projectName)) {
return `Project name can only contain ${
DigitalTwinConstants.codegenProjectNameRegexDescription}.`;
DigitalTwinConstants.codegenProjectNameRegexDescription}.`;
}
return;
}
@ -227,41 +248,41 @@ export class CodeGeneratorCore {
if (!codeGenProjectName) {
throw new CancelOperationError(
`Project name is not specified, cancelled.`);
`Project name is not specified, cancelled.`);
}
const projectPath = path.join(rootPath, codeGenProjectName);
if (fs.isDirectorySync(projectPath)) {
const messge = `The folder ${
projectPath} already exists. Do you want to overwrite the contents in this folder?`;
projectPath} already exists. Do you want to overwrite the contents in this folder?`;
const choice = await vscode.window.showWarningMessage(
messge, DialogResponses.yes, DialogResponses.no);
messge, DialogResponses.yes, DialogResponses.no);
if (choice !== DialogResponses.yes) {
throw new CancelOperationError(
`Valid project name is not specified, cancelled.`);
`Valid project name is not specified, cancelled.`);
}
}
utils.channelShowAndAppendLine(
channel, `Input project name: ${codeGenProjectName}`);
channel, `Input project name: ${codeGenProjectName}`);
return codeGenProjectName;
}
private readCodeGenOptionsConfiguration(
// tslint:disable-next-line: no-any
context: vscode.ExtensionContext): any {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context: vscode.ExtensionContext): any {
// Load CodeGen configuration file which defines the available CodeGen
// options in VS Code command palette
const codeGenConfigFilePath: string = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.codeGenOptionsFileName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.codeGenOptionsFileName));
return JSON.parse(fs.readFileSync(codeGenConfigFilePath, 'utf8'));
}
private async selectLanguage(channel: vscode.OutputChannel): Promise<string> {
const languageItems: vscode.QuickPickItem[] = [];
languageItems.push({label: CodeGenLanguage.ANSIC, description: ''});
languageItems.push({ label: CodeGenLanguage.ANSIC, description: '' });
const languageSelection = await vscode.window.showQuickPick(languageItems, {
ignoreFocusOut: true,
@ -273,21 +294,21 @@ export class CodeGeneratorCore {
}
utils.channelShowAndAppendLine(
channel, `Selected CodeGen language: ${languageSelection.label}`);
channel, `Selected CodeGen language: ${languageSelection.label}`);
return languageSelection.label;
}
private async selectConnectionType(
channel: vscode.OutputChannel,
// tslint:disable-next-line: no-any
codegenOptionsConfig: any): Promise<DeviceConnectionType> {
channel: vscode.OutputChannel,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
codegenOptionsConfig: any): Promise<DeviceConnectionType> {
// Load available Azure IoT connection types from JSON configuration
const connectionTypeItems: vscode.QuickPickItem[] = [];
codegenOptionsConfig.connectionTypes.forEach(
(element: PnpDeviceConnection) => {
connectionTypeItems.push(
{label: element.name, detail: element.detail});
});
(element: PnpDeviceConnection) => {
connectionTypeItems.push(
{ label: element.name, detail: element.detail });
});
const deviceConnectionSelection =
await vscode.window.showQuickPick(connectionTypeItems, {
@ -300,53 +321,52 @@ export class CodeGeneratorCore {
}
const deviceConnection = codegenOptionsConfig.connectionTypes.find(
(connectionType: PnpDeviceConnection) => {
return connectionType.name === deviceConnectionSelection.label;
});
(connectionType: PnpDeviceConnection) => {
return connectionType.name === deviceConnectionSelection.label;
});
const connectionType: DeviceConnectionType = DeviceConnectionType
[deviceConnection.type as keyof typeof DeviceConnectionType];
const connectionType: DeviceConnectionType = DeviceConnectionType[deviceConnection.type as keyof typeof DeviceConnectionType];
if (!connectionType) {
throw new Error(
`Failed to find an available device connection type with selection label '${
deviceConnectionSelection.label}' from CodeGen configuration.`);
`Failed to find an available device connection type with selection label '${
deviceConnectionSelection.label}' from CodeGen configuration.`);
}
utils.channelShowAndAppendLine(
channel, `Selected device connection type: ${connectionType}`);
channel, `Selected device connection type: ${connectionType}`);
return connectionType;
}
private async selectProjectTemplate(
channel: vscode.OutputChannel, language: string,
// tslint:disable-next-line: no-any
codegenOptionsConfig: any): Promise<CodeGenProjectType> {
channel: vscode.OutputChannel, language: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
codegenOptionsConfig: any): Promise<CodeGenProjectType> {
// Load available project templates from JSON configuration
const projectTemplates = codegenOptionsConfig.projectTemplates.filter(
(projectTemplate: CodeGenProjectTemplate) => {
return (
projectTemplate.enabled && projectTemplate.language === language);
});
(projectTemplate: CodeGenProjectTemplate) => {
return (
projectTemplate.enabled && projectTemplate.language === language);
});
const projectTemplateItems: vscode.QuickPickItem[] = [];
projectTemplates.forEach((element: CodeGenProjectTemplate) => {
projectTemplateItems.push({label: element.name, detail: element.detail});
projectTemplateItems.push({ label: element.name, detail: element.detail });
});
if (!projectTemplateItems) {
throw new Error(
`Internal error. Unable to find available project templates using ${
language} language.`);
`Internal error. Unable to find available project templates using ${
language} language.`);
}
const projectTemplateSelection = await vscode.window.showQuickPick(
projectTemplateItems,
{ignoreFocusOut: true, placeHolder: 'Select project template:'});
projectTemplateItems,
{ ignoreFocusOut: true, placeHolder: 'Select project template:' });
if (!projectTemplateSelection) {
throw new CancelOperationError(
'CodeGen project template selection cancelled.');
'CodeGen project template selection cancelled.');
}
const projectTemplate =
@ -354,119 +374,117 @@ export class CodeGeneratorCore {
return projectType.name === projectTemplateSelection.label;
});
const codeGenProjectType: CodeGenProjectType = CodeGenProjectType
[projectTemplate.type as keyof typeof CodeGenProjectType];
const codeGenProjectType: CodeGenProjectType = CodeGenProjectType[projectTemplate.type as keyof typeof CodeGenProjectType];
if (!codeGenProjectType) {
throw new Error(
`Failed to find an available project template with selection label '${
projectTemplateSelection.label}' from CodeGen configuration.`);
`Failed to find an available project template with selection label '${
projectTemplateSelection.label}' from CodeGen configuration.`);
}
utils.channelShowAndAppendLine(
channel, `Selected CodeGen project type: ${codeGenProjectType}`);
channel, `Selected CodeGen project type: ${codeGenProjectType}`);
return codeGenProjectType;
}
private async selectDeviceSdkReferenceType(
channel: vscode.OutputChannel, projectType: CodeGenProjectType,
// tslint:disable-next-line: no-any
codegenOptionsConfig: any): Promise<DeviceSdkReferenceType> {
channel: vscode.OutputChannel, projectType: CodeGenProjectType,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
codegenOptionsConfig: any): Promise<DeviceSdkReferenceType> {
let deviceSdkReferenceType = undefined;
switch (projectType) {
case CodeGenProjectType.IoTDevKit:
deviceSdkReferenceType = DeviceSdkReferenceType.DevKitSDK;
break;
case CodeGenProjectType.CMakeWindows:
case CodeGenProjectType.CMakeLinux: {
// Load available Azure IoT connection types from JSON configuration
const sdkReferenceTypeItems: vscode.QuickPickItem[] = [];
codegenOptionsConfig.deviceSdkReferenceTypes.forEach(
(element: DeviceSdkReference) => {
sdkReferenceTypeItems.push(
{label: element.name, detail: element.detail});
});
case CodeGenProjectType.IoTDevKit:
deviceSdkReferenceType = DeviceSdkReferenceType.DevKitSDK;
break;
case CodeGenProjectType.CMakeWindows:
case CodeGenProjectType.CMakeLinux: {
// Load available Azure IoT connection types from JSON configuration
const sdkReferenceTypeItems: vscode.QuickPickItem[] = [];
codegenOptionsConfig.deviceSdkReferenceTypes.forEach(
(element: DeviceSdkReference) => {
sdkReferenceTypeItems.push(
{ label: element.name, detail: element.detail });
});
const deviceConnectionSelection =
const deviceConnectionSelection =
await vscode.window.showQuickPick(sdkReferenceTypeItems, {
ignoreFocusOut: true,
placeHolder: 'How will CMake include the Azure IoT Device SDK?'
});
if (!deviceConnectionSelection) {
throw new CancelOperationError(
'IoT Device SDK reference type selection cancelled.');
}
// Map selection to a DeviceSdkReferenceType enum
const sdkReference = codegenOptionsConfig.deviceSdkReferenceTypes.find(
(sdkReference: DeviceSdkReference) => {
return sdkReference.name === deviceConnectionSelection.label;
});
const sdkReferenceType: DeviceSdkReferenceType = DeviceSdkReferenceType
[sdkReference.type as keyof typeof DeviceSdkReferenceType];
if (!sdkReference) {
throw new Error(
`Failed to find an available SDK reference type with selection label '${
deviceConnectionSelection
.label}' from CodeGen configuration.`);
}
deviceSdkReferenceType = sdkReferenceType;
break;
if (!deviceConnectionSelection) {
throw new CancelOperationError(
'IoT Device SDK reference type selection cancelled.');
}
default:
throw new Error(`projectType ${projectType} is not supported.`);
// Map selection to a DeviceSdkReferenceType enum
const sdkReference = codegenOptionsConfig.deviceSdkReferenceTypes.find(
(sdkReference: DeviceSdkReference) => {
return sdkReference.name === deviceConnectionSelection.label;
});
const sdkReferenceType: DeviceSdkReferenceType = DeviceSdkReferenceType[sdkReference.type as keyof typeof DeviceSdkReferenceType];
if (!sdkReference) {
throw new Error(
`Failed to find an available SDK reference type with selection label '${
deviceConnectionSelection
.label}' from CodeGen configuration.`);
}
deviceSdkReferenceType = sdkReferenceType;
break;
}
default:
throw new Error(`projectType ${projectType} is not supported.`);
}
utils.channelShowAndAppendLine(
channel,
`Selected device SDK reference type: ${deviceSdkReferenceType}`);
channel,
`Selected device SDK reference type: ${deviceSdkReferenceType}`);
return deviceSdkReferenceType;
}
private async generateDeviceCodeCore(
codeGenExecutionInfo: CodeGenExecutionItem,
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<boolean> {
codeGenExecutionInfo: CodeGenExecutionItem,
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<boolean> {
// We only support Ansi C
const codeGenFactory =
new AnsiCCodeGeneratorFactory(context, channel, telemetryContext);
const codeGenerator = codeGenFactory.createCodeGeneratorImpl(
codeGenExecutionInfo.languageLabel);
codeGenExecutionInfo.languageLabel);
if (!codeGenerator) {
return false;
}
// Parse capabilityModel name from id
const capabilityModel = await Utility.getJsonContent(
codeGenExecutionInfo.capabilityModelFilePath);
codeGenExecutionInfo.capabilityModelFilePath);
const capabilityModelId = capabilityModel['@id'];
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: `Generate PnP device code for ${capabilityModelId} ...`
},
async () => {
const result = await codeGenerator.generateCode(codeGenExecutionInfo);
if (result) {
vscode.window.showInformationMessage(
`Generate PnP device code for ${capabilityModelId} completed`);
}
});
{
location: vscode.ProgressLocation.Notification,
title: `Generate PnP device code for ${capabilityModelId} ...`
},
async () => {
const result = await codeGenerator.generateCode(codeGenExecutionInfo);
if (result) {
vscode.window.showInformationMessage(
`Generate PnP device code for ${capabilityModelId} completed`);
}
});
return true;
}
private async saveCodeGenConfig(
type: ScaffoldType, rootPath: string, capabilityModelFilePath: string,
codeGenExecutionInfo: CodeGenExecutionItem): Promise<void> {
type: ScaffoldType, rootPath: string, capabilityModelFilePath: string,
codeGenExecutionInfo: CodeGenExecutionItem): Promise<void> {
const codeGenConfigPath = path.join(
rootPath, FileNames.vscodeSettingsFolderName,
DigitalTwinConstants.codeGenConfigFileName);
rootPath, FileNames.vscodeSettingsFolderName,
DigitalTwinConstants.codeGenConfigFileName);
try {
let codeGenExecutions: CodeGenExecutions;
@ -478,16 +496,16 @@ export class CodeGeneratorCore {
if (codeGenExecutions) {
codeGenExecutions.codeGenExecutionItems =
codeGenExecutions.codeGenExecutionItems.filter(
item =>
item.capabilityModelFilePath !== capabilityModelFilePath);
item =>
item.capabilityModelFilePath !== capabilityModelFilePath);
codeGenExecutions.codeGenExecutionItems.push(codeGenExecutionInfo);
}
} else {
codeGenExecutions = {codeGenExecutionItems: [codeGenExecutionInfo]};
codeGenExecutions = { codeGenExecutionItems: [codeGenExecutionInfo] };
}
if (codeGenExecutions) {
await FileUtility.writeJsonFile(
type, codeGenConfigPath, codeGenExecutions);
type, codeGenConfigPath, codeGenExecutions);
}
} catch (error) {
// save config failure should not impact code gen.
@ -496,8 +514,8 @@ export class CodeGeneratorCore {
}
private async getCodeGenCliPackageInfo(
context: vscode.ExtensionContext,
channel: vscode.OutputChannel): Promise<CodeGeneratorConfigItem|null> {
context: vscode.ExtensionContext,
channel: vscode.OutputChannel): Promise<CodeGeneratorConfigItem|null> {
const extensionPackage = require(context.asAbsolutePath('./package.json'));
const extensionVersion = extensionPackage.version;
@ -514,11 +532,11 @@ export class CodeGeneratorCore {
const codeGenConfig: CodeGeneratorConfig = await request(options).promise();
if (codeGenConfig) {
codeGenConfig.codeGeneratorConfigItems.sort(
(configItem1, configItem2) => {
return compareVersion(
configItem2.codeGeneratorVersion,
configItem1.codeGeneratorVersion); // reverse order
});
(configItem1, configItem2) => {
return compareVersion(
configItem2.codeGeneratorVersion,
configItem1.codeGeneratorVersion); // reverse order
});
// if this is a RC build, always use the latest version of code generator.
if (!/^[0-9]+\.[0-9]+\.[0-9]+$/.test(extensionVersion)) {
@ -526,7 +544,7 @@ export class CodeGeneratorCore {
} else {
for (const item of codeGenConfig.codeGeneratorConfigItems) {
if (compareVersion(
extensionVersion, item.iotWorkbenchMinimalVersion) >= 0) {
extensionVersion, item.iotWorkbenchMinimalVersion) >= 0) {
targetConfigItem = item;
break;
}
@ -536,9 +554,9 @@ export class CodeGeneratorCore {
if (!targetConfigItem) {
const message = `${
DigitalTwinConstants
.dtPrefix} Failed to get download information for ${
DigitalTwinConstants.codeGenCli}.`;
DigitalTwinConstants
.dtPrefix} Failed to get download information for ${
DigitalTwinConstants.codeGenCli}.`;
utils.channelShowAndAppendLine(channel, message);
}
@ -565,8 +583,8 @@ export class CodeGeneratorCore {
}
private async downloadAndInstallCodeGenCli(
channel: vscode.OutputChannel, targetConfigItem: CodeGeneratorConfigItem,
installOrUpgrade: number, newVersion: string): Promise<boolean> {
channel: vscode.OutputChannel, targetConfigItem: CodeGeneratorConfigItem,
installOrUpgrade: number, newVersion: string): Promise<boolean> {
let packageUri: string;
let md5value: string;
const platform = os.platform();
@ -583,11 +601,11 @@ export class CodeGeneratorCore {
// Download
utils.channelShowAndAppend(
channel,
`Step 1: Downloading ${DigitalTwinConstants.codeGenCli} v${
newVersion} package ...`);
channel,
`Step 1: Downloading ${DigitalTwinConstants.codeGenCli} v${
newVersion} package ...`);
const downloadOption: request
.OptionsWithUri = {method: 'GET', uri: packageUri, encoding: null};
.OptionsWithUri = { method: 'GET', uri: packageUri, encoding: null };
const zipData = await request(downloadOption).promise();
const tempPath = path.join(os.tmpdir(), FileNames.iotworkbenchTempFolder);
const filePath = path.join(tempPath, `${md5value}.zip`);
@ -597,24 +615,24 @@ export class CodeGeneratorCore {
// Verify
// Validate hash code
utils.channelShowAndAppend(
channel, 'Step 2: Validating hash code for the package ...');
channel, 'Step 2: Validating hash code for the package ...');
const hashvalue = await FileUtility.getFileHash(filePath);
if (hashvalue !== md5value) {
utils.channelShowAndAppendLine(
channel,
`the downloaded ${DigitalTwinConstants.codeGenCli} v${
newVersion} package has been corrupted.`);
channel,
`the downloaded ${DigitalTwinConstants.codeGenCli} v${
newVersion} package has been corrupted.`);
if (installOrUpgrade === CodeGenCliOperation.Install) {
utils.channelShowAndAppendLine(
channel,
`${
DigitalTwinConstants
.dtPrefix} Abort generating device code stub.`);
channel,
`${
DigitalTwinConstants
.dtPrefix} Abort generating device code stub.`);
return false;
} else {
utils.channelShowAndAppendLine(
channel,
` Abort the installation and continue generating device code stub.`);
channel,
` Abort the installation and continue generating device code stub.`);
return true;
}
} else {
@ -629,23 +647,23 @@ export class CodeGeneratorCore {
// Update the config
await ConfigHandler.update(
ConfigKey.codeGeneratorVersion, newVersion,
vscode.ConfigurationTarget.Global);
ConfigKey.codeGeneratorVersion, newVersion,
vscode.ConfigurationTarget.Global);
utils.channelShowAndAppendLine(
channel,
`${DigitalTwinConstants.dtPrefix} The ${
DigitalTwinConstants.codeGenCli} v${newVersion} is ready to use.`);
channel,
`${DigitalTwinConstants.dtPrefix} The ${
DigitalTwinConstants.codeGenCli} v${newVersion} is ready to use.`);
return true;
}
private async installOrUpgradeCodeGenCli(
context: vscode.ExtensionContext,
channel: vscode.OutputChannel): Promise<boolean> {
context: vscode.ExtensionContext,
channel: vscode.OutputChannel): Promise<boolean> {
utils.channelShowAndAppend(
channel,
`${DigitalTwinConstants.dtPrefix} Check ${
DigitalTwinConstants.codeGenCli} ...`);
channel,
`${DigitalTwinConstants.dtPrefix} Check ${
DigitalTwinConstants.codeGenCli} ...`);
const targetConfigItem =
await this.getCodeGenCliPackageInfo(context, channel);
if (targetConfigItem === null) {
@ -660,7 +678,7 @@ export class CodeGeneratorCore {
} else {
// Compare version
if (compareVersion(
targetConfigItem.codeGeneratorVersion, currentVersion) > 0) {
targetConfigItem.codeGeneratorVersion, currentVersion) > 0) {
// Upgrade
installOrUpgrade = CodeGenCliOperation.Upgrade;
}
@ -668,68 +686,47 @@ export class CodeGeneratorCore {
if (installOrUpgrade === CodeGenCliOperation.None) {
// Already exists
utils.channelShowAndAppendLine(
channel,
`CodeGen CLI v${currentVersion} is installed and ready to use.`);
channel,
`CodeGen CLI v${currentVersion} is installed and ready to use.`);
return true;
}
const newVersion = targetConfigItem.codeGeneratorVersion;
const processTitle =
(installOrUpgrade === CodeGenCliOperation.Install ?
`Installing ${DigitalTwinConstants.codeGenCli}` :
`Upgrading ${DigitalTwinConstants.codeGenCli}`);
`Installing ${DigitalTwinConstants.codeGenCli}` :
`Upgrading ${DigitalTwinConstants.codeGenCli}`);
const message =
(installOrUpgrade === CodeGenCliOperation.Install ?
` not installed, start installing:` :
` new version detected, start upgrading from ${
currentVersion} to ${newVersion}:`);
` not installed, start installing:` :
` new version detected, start upgrading from ${
currentVersion} to ${newVersion}:`);
utils.channelShowAndAppendLine(channel, message);
// Start donwloading
let result = false;
await vscode.window.withProgress(
{location: vscode.ProgressLocation.Notification, title: processTitle},
async (progress) => {
progress.report({increment: 0});
{ location: vscode.ProgressLocation.Notification, title: processTitle },
async (progress) => {
progress.report({ increment: 0 });
setTimeout(() => {
progress.report({increment: 10, message: `still going...`});
}, 1000);
setTimeout(() => {
progress.report({ increment: 10, message: `still going...` });
}, 1000);
setTimeout(() => {
progress.report({increment: 40, message: `still going...`});
}, 5000);
setTimeout(() => {
progress.report({ increment: 40, message: `still going...` });
}, 5000);
setTimeout(() => {
progress.report({increment: 50, message: `almost done...`});
}, 10000);
setTimeout(() => {
progress.report({ increment: 50, message: `almost done...` });
}, 10000);
result = await this.downloadAndInstallCodeGenCli(
channel, targetConfigItem as CodeGeneratorConfigItem,
installOrUpgrade, newVersion);
});
result = await this.downloadAndInstallCodeGenCli(
channel, targetConfigItem as CodeGeneratorConfigItem,
installOrUpgrade, newVersion);
});
return result;
}
}
function localCodeGenCliPath(): string {
return path.join(os.homedir(), DigitalTwinConstants.codeGenCliFolder);
}
function compareVersion(verion1: string, verion2: string) {
const ver1 = verion1.split('.');
const ver2 = verion2.split('.');
let i = 0;
let v1: number, v2: number;
/* default is 0, version format should be 1.1.0 */
while (i < 3) {
v1 = Number(ver1[i]);
v2 = Number(ver2[i]);
if (v1 > v2) return 1;
if (v1 < v2) return -1;
i++;
}
return 0;
}

Просмотреть файл

@ -1,9 +1,9 @@
import * as vscode from 'vscode';
import {TelemetryContext} from '../../telemetry';
import {AnsiCCodeGenerator} from './Interfaces/AnsiCCodeGenerator';
import {CodeGenerator, CodeGenLanguage} from './Interfaces/CodeGenerator';
import {CodeGeneratorFactory} from './Interfaces/CodeGeneratorFactory';
import { TelemetryContext } from '../../telemetry';
import { AnsiCCodeGenerator } from './Interfaces/AnsiCCodeGenerator';
import { CodeGenerator, CodeGenLanguage } from './Interfaces/CodeGenerator';
import { CodeGeneratorFactory } from './Interfaces/CodeGeneratorFactory';
export class AnsiCCodeGeneratorFactory implements CodeGeneratorFactory {
constructor(
@ -13,7 +13,7 @@ export class AnsiCCodeGeneratorFactory implements CodeGeneratorFactory {
createCodeGeneratorImpl(language: string): CodeGenerator|null {
if (language === CodeGenLanguage.ANSIC.toString()) {
return new AnsiCCodeGenerator(
this.context, this.channel, this.telemetryContext);
this.context, this.channel, this.telemetryContext);
} else {
return null;
}

Просмотреть файл

@ -5,32 +5,29 @@
import * as utils from '../../utils';
import * as vscode from 'vscode';
import {CodeGenExecutionItem} from './Interfaces/CodeGenerator';
import { CodeGenExecutionItem } from './Interfaces/CodeGenerator';
export class CodeGenUtility {
static printCodeGenConfig(
codeGenExecutionItem: CodeGenExecutionItem,
channel: vscode.OutputChannel,
) {
static printCodeGenConfig(codeGenExecutionItem: CodeGenExecutionItem, channel: vscode.OutputChannel): void {
utils.channelShowAndAppendLine(
channel,
`Device capability model file: ${
codeGenExecutionItem.capabilityModelFilePath}`);
channel,
`Device capability model file: ${
codeGenExecutionItem.capabilityModelFilePath}`);
utils.channelShowAndAppendLine(
channel, `Project name: ${codeGenExecutionItem.projectName}`);
channel, `Project name: ${codeGenExecutionItem.projectName}`);
utils.channelShowAndAppendLine(
channel, `Language: ${codeGenExecutionItem.languageLabel}`);
channel, `Language: ${codeGenExecutionItem.languageLabel}`);
utils.channelShowAndAppendLine(
channel,
`Device connection type: ${codeGenExecutionItem.deviceConnectionType}`);
channel,
`Device connection type: ${codeGenExecutionItem.deviceConnectionType}`);
utils.channelShowAndAppendLine(
channel, `Project type: ${codeGenExecutionItem.codeGenProjectType}`);
channel, `Project type: ${codeGenExecutionItem.codeGenProjectType}`);
utils.channelShowAndAppendLine(
channel,
`Device SDK reference type: ${
codeGenExecutionItem.deviceSdkReferenceType}`);
channel,
`Device SDK reference type: ${
codeGenExecutionItem.deviceSdkReferenceType}`);
utils.channelShowAndAppendLine(
channel,
`Project output directory: ${codeGenExecutionItem.outputDirectory}`);
channel,
`Project output directory: ${codeGenExecutionItem.outputDirectory}`);
}
}

Просмотреть файл

@ -2,15 +2,15 @@ import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import {VscodeCommands} from '../../../common/Commands';
import {OSPlatform, ScaffoldType} from '../../../constants';
import {OpenScenario} from '../../../Models/IoTWorkbenchProjectBase';
import {IoTWorkspaceProject} from '../../../Models/IoTWorkspaceProject';
import {TelemetryContext} from '../../../telemetry';
import { VscodeCommands } from '../../../common/Commands';
import { OSPlatform, ScaffoldType } from '../../../constants';
import { OpenScenario } from '../../../Models/IoTWorkbenchProjectBase';
import { IoTWorkspaceProject } from '../../../Models/IoTWorkspaceProject';
import { TelemetryContext } from '../../../telemetry';
import * as utils from '../../../utils';
import {DigitalTwinConstants} from '../../DigitalTwinConstants';
import { DigitalTwinConstants } from '../../DigitalTwinConstants';
import {CodeGenerator, CodeGenExecutionItem, CodeGenProjectType} from './CodeGenerator';
import { CodeGenerator, CodeGenExecutionItem, CodeGenProjectType } from './CodeGenerator';
export class AnsiCCodeGenerator implements CodeGenerator {
constructor(
@ -25,20 +25,20 @@ export class AnsiCCodeGenerator implements CodeGenerator {
if (codegenSucceeded) {
if (codegenInfo.codeGenProjectType === CodeGenProjectType.IoTDevKit) {
const project: IoTWorkspaceProject = new IoTWorkspaceProject(
this.context, this.channel, this.telemetryContext,
codegenInfo.outputDirectory);
this.context, this.channel, this.telemetryContext,
codegenInfo.outputDirectory);
project.openProject(
ScaffoldType.Local, true, OpenScenario.createNewProject);
ScaffoldType.Local, true, OpenScenario.createNewProject);
} else {
await vscode.commands.executeCommand(
VscodeCommands.VscodeOpenFolder,
vscode.Uri.file(codegenInfo.outputDirectory), true);
VscodeCommands.VscodeOpenFolder,
vscode.Uri.file(codegenInfo.outputDirectory), true);
}
return true;
} else {
vscode.window.showErrorMessage(
'Unable to generate code, please check output window for detail.');
'Unable to generate code, please check output window for detail.');
return false;
}
}
@ -66,16 +66,16 @@ export class AnsiCCodeGenerator implements CodeGenerator {
}
const command = `${codeGenCommand} generate -d "${dcmFilePath}" -i "${
interfaceDir}" -p "${projectTypeValue}" -c "${
connectionTypeValue}" -r "${sdkReferenceTypeValue}" -l ansic -o "${
outputDir}" -n "${projectName}"`;
interfaceDir}" -p "${projectTypeValue}" -c "${
connectionTypeValue}" -r "${sdkReferenceTypeValue}" -l ansic -o "${
outputDir}" -n "${projectName}"`;
let message: string;
try {
await utils.runCommand(command, [], cmdPath, this.channel);
message = `${
DigitalTwinConstants.dtPrefix} generate PnP device code completed.`;
DigitalTwinConstants.dtPrefix} generate PnP device code completed.`;
utils.channelShowAndAppendLine(this.channel, message);
return true;
} catch {

Просмотреть файл

@ -1,4 +1,4 @@
import {CodeGenerator, CodeGenProjectType, DeviceConnectionType, DeviceSdkReferenceType} from './CodeGenerator';
import { CodeGenerator, CodeGenProjectType, DeviceConnectionType, DeviceSdkReferenceType } from './CodeGenerator';
export interface CodeGeneratorFactory {

Просмотреть файл

@ -5,10 +5,10 @@
import * as vscode from 'vscode';
import * as utils from '../utils';
import {DigitalTwinConstants} from './DigitalTwinConstants';
import {CancelOperationError} from '../CancelOperationError';
import {ModelRepositoryManager} from './pnp/src/modelRepository/modelRepositoryManager';
import {ApiProvider} from './pnp/src/api/apiProvider';
import { DigitalTwinConstants } from './DigitalTwinConstants';
import { CancelOperationError } from '../CancelOperationError';
import { ModelRepositoryManager } from './pnp/src/modelRepository/modelRepositoryManager';
import { ApiProvider } from './pnp/src/api/apiProvider';
/**
* Digital Twin extension utility
@ -16,7 +16,7 @@ import {ApiProvider} from './pnp/src/api/apiProvider';
export class DigitalTwinUtility {
private static readonly EXTENSION_NOT_INIT =
'Azure Digital Twin extension is not inititalized';
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static extensionInstance: any;
private static channel: vscode.OutputChannel;
@ -25,8 +25,8 @@ export class DigitalTwinUtility {
* @param channel output channel
*/
static init(
modelRepositoryManager: ModelRepositoryManager,
channel: vscode.OutputChannel): void {
modelRepositoryManager: ModelRepositoryManager,
channel: vscode.OutputChannel): void {
DigitalTwinUtility.extensionInstance =
new ApiProvider(modelRepositoryManager);
DigitalTwinUtility.channel = channel;
@ -48,14 +48,14 @@ export class DigitalTwinUtility {
}
if (!result) {
throw new CancelOperationError(
`Selected device capability model file cancelled.`);
`Selected device capability model file cancelled.`);
}
utils.channelShowAndAppendLine(
DigitalTwinUtility.channel,
`${
DigitalTwinConstants
.dtPrefix} Selected device capability model file: ${result}`);
DigitalTwinUtility.channel,
`${
DigitalTwinConstants
.dtPrefix} Selected device capability model file: ${result}`);
return result;
}
@ -66,17 +66,17 @@ export class DigitalTwinUtility {
* @param capabilityModelFile capability model file path
*/
static async downloadDependentInterface(
folder: string, capabilityModelFile: string): Promise<boolean> {
folder: string, capabilityModelFile: string): Promise<boolean> {
if (!DigitalTwinUtility.extensionInstance) {
throw new Error(DigitalTwinUtility.EXTENSION_NOT_INIT);
}
try {
await DigitalTwinUtility.extensionInstance.downloadDependentInterface(
folder, capabilityModelFile);
folder, capabilityModelFile);
} catch (error) {
utils.channelShowAndAppendLine(
DigitalTwinUtility.channel,
`${DigitalTwinConstants.dtPrefix} ${error.message}`);
DigitalTwinUtility.channel,
`${DigitalTwinConstants.dtPrefix} ${error.message}`);
return false;
}
return true;

Просмотреть файл

@ -21,7 +21,7 @@ export class Configuration {
* @param name property name
* @param value property value
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static async setGlobalProperty(name: string, value: any): Promise<void> {
await Configuration.instance.update(name, value, true);
}
@ -31,7 +31,7 @@ export class Configuration {
* @param name property name
* @param value property value
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static async setWorkspaceProperty(name: string, value: any): Promise<void> {
await Configuration.instance.update(name, value, false);
}

Просмотреть файл

@ -94,7 +94,7 @@ export class Utility {
* @param modelId model id
* @param content model content
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static async createModelFile(folder: string, modelId: string, content: any): Promise<void> {
const type: ModelType = DeviceModelManager.convertToModelType(content[DigitalTwinConstants.TYPE]);
if (!type) {
@ -105,6 +105,7 @@ export class Utility {
const modelName: string = Utility.replaceAll(modelId, replacement);
let candidate: string = DeviceModelManager.generateModelFileName(modelName, type);
let counter = 0;
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
if (!(await fs.pathExists(path.join(folder, candidate)))) {
break;
@ -141,7 +142,7 @@ export class Utility {
* get json content from file
* @param filePath file path
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static async getJsonContent(filePath: string): Promise<any> {
return fs.readJson(filePath, { encoding: Constants.UTF8 });
}

Просмотреть файл

@ -106,13 +106,13 @@ export class DigitalTwinCompletionItemProvider implements vscode.CompletionItemP
scanner.setPosition(offset);
const token: parser.SyntaxKind = scanner.scan();
switch (token) {
case parser.SyntaxKind.CommaToken:
case parser.SyntaxKind.CloseBraceToken:
case parser.SyntaxKind.CloseBracketToken:
case parser.SyntaxKind.EOF:
return Constants.EMPTY_STRING;
default:
return Constants.DEFAULT_SEPARATOR;
case parser.SyntaxKind.CommaToken:
case parser.SyntaxKind.CloseBraceToken:
case parser.SyntaxKind.CloseBracketToken:
case parser.SyntaxKind.EOF:
return Constants.EMPTY_STRING;
default:
return Constants.DEFAULT_SEPARATOR;
}
}
@ -345,16 +345,16 @@ export class DigitalTwinCompletionItemProvider implements vscode.CompletionItemP
value = "{$1}";
} else if (!classNode.label) {
switch (classNode.id) {
case ValueSchema.String:
value = '"$1"';
break;
case ValueSchema.Int:
value = "${1:0}";
break;
case ValueSchema.Boolean:
value = "${1:false}";
break;
default:
case ValueSchema.String:
value = '"$1"';
break;
case ValueSchema.Int:
value = "${1:0}";
break;
case ValueSchema.Boolean:
value = "${1:false}";
break;
default:
}
}
}
@ -453,11 +453,8 @@ export class DigitalTwinCompletionItemProvider implements vscode.CompletionItemP
* @param token cancellation token
* @param context completion context
*/
provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position,
token: vscode.CancellationToken,
context: vscode.CompletionContext,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, _token: vscode.CancellationToken, _context: vscode.CompletionContext,
): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
const text: string = DigitalTwinCompletionItemProvider.getTextForParse(document, position);
const jsonNode: parser.Node | undefined = IntelliSenseUtility.parseDigitalTwinModel(text);

Просмотреть файл

@ -102,22 +102,22 @@ export class DigitalTwinDiagnosticProvider {
private static validateNode(jsonNode: parser.Node, digitalTwinNode: PropertyNode, problems: Problem[]): void {
const nodeType: parser.NodeType = jsonNode.type;
switch (nodeType) {
case JsonNodeType.Object:
DigitalTwinDiagnosticProvider.validateObjectNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.Array:
DigitalTwinDiagnosticProvider.validateArrayNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.String:
DigitalTwinDiagnosticProvider.validateStringNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.Number:
DigitalTwinDiagnosticProvider.validateNumberNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.Boolean:
DigitalTwinDiagnosticProvider.validateBooleanNode(jsonNode, digitalTwinNode, problems);
break;
default:
case JsonNodeType.Object:
DigitalTwinDiagnosticProvider.validateObjectNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.Array:
DigitalTwinDiagnosticProvider.validateArrayNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.String:
DigitalTwinDiagnosticProvider.validateStringNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.Number:
DigitalTwinDiagnosticProvider.validateNumberNode(jsonNode, digitalTwinNode, problems);
break;
case JsonNodeType.Boolean:
DigitalTwinDiagnosticProvider.validateBooleanNode(jsonNode, digitalTwinNode, problems);
break;
default:
}
}
@ -259,38 +259,38 @@ export class DigitalTwinDiagnosticProvider {
// duplicate property name is handled by json validator
exist.add(propertyName);
switch (propertyName) {
case DigitalTwinConstants.ID:
// @id is available for each class
propertyNode = IntelliSenseUtility.getPropertyNode(propertyName);
if (propertyNode) {
DigitalTwinDiagnosticProvider.validateNode(propertyPair.value, propertyNode, problems);
}
break;
case DigitalTwinConstants.CONTEXT:
// @context is available when it is required
if (
classNode.constraint &&
case DigitalTwinConstants.ID:
// @id is available for each class
propertyNode = IntelliSenseUtility.getPropertyNode(propertyName);
if (propertyNode) {
DigitalTwinDiagnosticProvider.validateNode(propertyPair.value, propertyNode, problems);
}
break;
case DigitalTwinConstants.CONTEXT:
// @context is available when it is required
if (
classNode.constraint &&
classNode.constraint.required &&
classNode.constraint.required.includes(propertyName)
) {
if (!IntelliSenseUtility.isDigitalTwinContext(propertyPair.value)) {
DigitalTwinDiagnosticProvider.addProblem(propertyPair.value, problems, DiagnosticMessage.InvalidContext);
}
} else {
DigitalTwinDiagnosticProvider.addProblemOfUnexpectedProperty(propertyPair.name, problems);
}
break;
case DigitalTwinConstants.TYPE:
// skip since @type is already validated
break;
default:
// validate expected property
propertyNode = expectedProperties.get(propertyName);
if (!propertyNode) {
DigitalTwinDiagnosticProvider.addProblemOfUnexpectedProperty(propertyPair.name, problems);
} else {
DigitalTwinDiagnosticProvider.validateNode(propertyPair.value, propertyNode, problems);
) {
if (!IntelliSenseUtility.isDigitalTwinContext(propertyPair.value)) {
DigitalTwinDiagnosticProvider.addProblem(propertyPair.value, problems, DiagnosticMessage.InvalidContext);
}
} else {
DigitalTwinDiagnosticProvider.addProblemOfUnexpectedProperty(propertyPair.name, problems);
}
break;
case DigitalTwinConstants.TYPE:
// skip since @type is already validated
break;
default:
// validate expected property
propertyNode = expectedProperties.get(propertyName);
if (!propertyNode) {
DigitalTwinDiagnosticProvider.addProblemOfUnexpectedProperty(propertyPair.name, problems);
} else {
DigitalTwinDiagnosticProvider.validateNode(propertyPair.value, propertyNode, problems);
}
}
}
}

Просмотреть файл

@ -153,7 +153,7 @@ export class DigitalTwinGraph {
* check if json object is a valid constraint node
* @param object object data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static isConstraintNode(object: any): object is ConstraintNode {
return (
object.minItems || object.maxItems || object.minLength || object.maxLength || object.pattern || object.required
@ -164,7 +164,7 @@ export class DigitalTwinGraph {
* check if it is a valid edge
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static isValidEdge(edge: any): boolean {
return edge.SourceNode && edge.TargetNode && edge.Label;
}
@ -173,20 +173,20 @@ export class DigitalTwinGraph {
* resolve container type
* @param object object data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static resolveContainerType(object: any): ContainerType {
const container = object[DigitalTwinConstants.CONTAINER];
if (!container || typeof container !== "string") {
return ContainerType.None;
}
switch (container) {
case DigitalTwinConstants.LIST:
case DigitalTwinConstants.SET:
return ContainerType.Array;
case DigitalTwinConstants.LANGUAGE:
return ContainerType.Language;
default:
return ContainerType.None;
case DigitalTwinConstants.LIST:
case DigitalTwinConstants.SET:
return ContainerType.Array;
case DigitalTwinConstants.LANGUAGE:
return ContainerType.Language;
default:
return ContainerType.None;
}
}
@ -203,7 +203,7 @@ export class DigitalTwinGraph {
* @param context extension context
* @param fileName file name
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static async resolveDefinition(context: vscode.ExtensionContext, fileName: string): Promise<any> {
const filePath: string = context.asAbsolutePath(
path.join(Constants.RESOURCE_FOLDER, Constants.DEFINITION_FOLDER, fileName),
@ -285,7 +285,7 @@ export class DigitalTwinGraph {
* build context nodes by id and reversed index
* @param contextJson json object of context definition
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private buildContext(contextJson: any): void {
let id: string;
const context = contextJson[DigitalTwinConstants.CONTEXT];
@ -311,7 +311,7 @@ export class DigitalTwinGraph {
* build constraint nodes by name
* @param constraintJson json object of constraint definition
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private buildConstraint(constraintJson: any): void {
for (const key in constraintJson) {
if (DigitalTwinGraph.isConstraintNode(constraintJson[key])) {
@ -324,7 +324,7 @@ export class DigitalTwinGraph {
* build DigitalTwin graph on definitions of context, constraint and graph
* @param graphJson json object of graph definition
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private buildGraph(graphJson: any): void {
for (const edge of graphJson.Edges) {
if (DigitalTwinGraph.isValidEdge(edge)) {
@ -340,28 +340,28 @@ export class DigitalTwinGraph {
* handle data of edge
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleEdge(edge: any): void {
switch (edge.Label) {
case EdgeType.Type:
this.handleEdgeOfType(edge);
break;
case EdgeType.Label:
this.handleEdgeOfLabel(edge);
break;
case EdgeType.Domain:
this.handleEdgeOfDomain(edge);
break;
case EdgeType.Range:
this.handleEdgeOfRange(edge);
break;
case EdgeType.SubClassOf:
this.handleEdgeOfSubClassOf(edge);
break;
case EdgeType.Comment:
this.handleEdgeOfComment(edge);
break;
default:
case EdgeType.Type:
this.handleEdgeOfType(edge);
break;
case EdgeType.Label:
this.handleEdgeOfLabel(edge);
break;
case EdgeType.Domain:
this.handleEdgeOfDomain(edge);
break;
case EdgeType.Range:
this.handleEdgeOfRange(edge);
break;
case EdgeType.SubClassOf:
this.handleEdgeOfSubClassOf(edge);
break;
case EdgeType.Comment:
this.handleEdgeOfComment(edge);
break;
default:
}
}
@ -371,26 +371,27 @@ export class DigitalTwinGraph {
* 2. add enum value to enum node
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleEdgeOfType(edge: any): void {
const id: string = edge.SourceNode.Id as string;
const type: string = edge.TargetNode.Id as string;
switch (type) {
case NodeType.Class:
this.ensureClassNode(id);
break;
case NodeType.Property:
this.ensurePropertyNode(id);
break;
default:
// mark target class as enum node
const contextNode: ContextNode | undefined = this.contextNodes.get(id);
const enumValue: string = contextNode ? contextNode.name : id;
const enumNode: ClassNode = this.ensureClassNode(type);
if (!enumNode.enums) {
enumNode.enums = [];
}
enumNode.enums.push(enumValue);
case NodeType.Class:
this.ensureClassNode(id);
break;
case NodeType.Property:
this.ensurePropertyNode(id);
break;
default:{
// mark target class as enum node
const contextNode: ContextNode | undefined = this.contextNodes.get(id);
const enumValue: string = contextNode ? contextNode.name : id;
const enumNode: ClassNode = this.ensureClassNode(type);
if (!enumNode.enums) {
enumNode.enums = [];
}
enumNode.enums.push(enumValue);
}
}
}
@ -400,7 +401,7 @@ export class DigitalTwinGraph {
* 2. set label and constraint if not defined
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleEdgeOfLabel(edge: any): void {
const id: string = edge.SourceNode.Id as string;
const label: string = edge.TargetNode.Value as string;
@ -424,7 +425,7 @@ export class DigitalTwinGraph {
* 1. add property to class node
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleEdgeOfDomain(edge: any): void {
const id: string = edge.SourceNode.Id as string;
const classId: string = edge.TargetNode.Id as string;
@ -441,7 +442,7 @@ export class DigitalTwinGraph {
* 1. add range to property node
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleEdgeOfRange(edge: any): void {
const id: string = edge.SourceNode.Id as string;
const classId: string = edge.TargetNode.Id as string;
@ -458,7 +459,7 @@ export class DigitalTwinGraph {
* 1. add children to base class node
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleEdgeOfSubClassOf(edge: any): void {
const id: string = edge.SourceNode.Id as string;
const baseId: string = edge.TargetNode.Id as string;
@ -475,7 +476,7 @@ export class DigitalTwinGraph {
* 1. set comment of property node
* @param edge edge data
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private handleEdgeOfComment(edge: any): void {
const id: string = edge.SourceNode.Id as string;
const comment: string = edge.TargetNode.Value as string;

Просмотреть файл

@ -21,15 +21,16 @@ export class DigitalTwinHoverProvider implements vscode.HoverProvider {
return Constants.EMPTY_STRING;
}
switch (propertyName) {
case DigitalTwinConstants.ID:
return `An identifier for ${Constants.CHANNEL_NAME} Capability Model or interface`;
case DigitalTwinConstants.TYPE:
return `The type of ${Constants.CHANNEL_NAME} meta model object`;
case DigitalTwinConstants.CONTEXT:
return `The context for ${Constants.CHANNEL_NAME} Capability Model or interface`;
default:
const propertyNode: PropertyNode | undefined = IntelliSenseUtility.getPropertyNode(propertyName);
return propertyNode && propertyNode.comment ? propertyNode.comment : Constants.EMPTY_STRING;
case DigitalTwinConstants.ID:
return `An identifier for ${Constants.CHANNEL_NAME} Capability Model or interface`;
case DigitalTwinConstants.TYPE:
return `The type of ${Constants.CHANNEL_NAME} meta model object`;
case DigitalTwinConstants.CONTEXT:
return `The context for ${Constants.CHANNEL_NAME} Capability Model or interface`;
default: {
const propertyNode: PropertyNode | undefined = IntelliSenseUtility.getPropertyNode(propertyName);
return propertyNode && propertyNode.comment ? propertyNode.comment : Constants.EMPTY_STRING;
}
}
}
@ -42,7 +43,8 @@ export class DigitalTwinHoverProvider implements vscode.HoverProvider {
provideHover(
document: vscode.TextDocument,
position: vscode.Position,
token: vscode.CancellationToken,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_token: vscode.CancellationToken,
): vscode.ProviderResult<vscode.Hover> {
const jsonNode: parser.Node | undefined = IntelliSenseUtility.parseDigitalTwinModel(document.getText());
if (!jsonNode) {

Просмотреть файл

@ -90,7 +90,7 @@ export class ModelRepositoryClient {
* @param modelId model id
* @param content content to update
*/
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static async updateModel(repoInfo: RepositoryInfo, modelId: string, content: any): Promise<string> {
const options: request.OptionsWithUri = ModelRepositoryClient.createOptions(HttpMethod.Put, repoInfo, modelId);
options.body = content;
@ -132,12 +132,12 @@ export class ModelRepositoryClient {
*/
private static convertToMetaModelType(type: ModelType): MetaModelType {
switch (type) {
case ModelType.Interface:
return MetaModelType.Interface;
case ModelType.CapabilityModel:
return MetaModelType.CapabilityModel;
default:
return MetaModelType.None;
case ModelType.Interface:
return MetaModelType.Interface;
case ModelType.CapabilityModel:
return MetaModelType.CapabilityModel;
default:
return MetaModelType.None;
}
}
@ -151,7 +151,7 @@ export class ModelRepositoryClient {
const uri = modelId
? `${repoInfo.hostname}/models/${encodeURIComponent(modelId)}`
: `${repoInfo.hostname}/models/search`;
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const qs: any = { "api-version": repoInfo.apiVersion };
if (repoInfo.repositoryId) {
qs.repositoryId = repoInfo.repositoryId;

Просмотреть файл

@ -325,7 +325,7 @@ export class ModelRepositoryManager {
const repoInfos: RepositoryInfo[] = await ModelRepositoryManager.getAvailableRepositoryInfo();
const fileInfos: ModelFileInfo[] = await UI.findModelFiles(ModelType.Interface);
const exist = new Set<string>(fileInfos.map(f => f.id));
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let schema: any;
let found: boolean;
let message: string;
@ -512,13 +512,13 @@ export class ModelRepositoryManager {
succeedCount += value.length;
hashId = value.map(id => Utility.hash(id)).join(Constants.DEFAULT_SEPARATOR);
switch (key) {
case ModelType.Interface:
telemetryContext.properties.interfaceId = hashId;
break;
case ModelType.CapabilityModel:
telemetryContext.properties.capabilityModelId = hashId;
break;
default:
case ModelType.Interface:
telemetryContext.properties.interfaceId = hashId;
break;
case ModelType.CapabilityModel:
telemetryContext.properties.capabilityModelId = hashId;
break;
default:
}
}
telemetryContext.measurements.totalCount = totalCount;

Просмотреть файл

@ -57,16 +57,16 @@ export class UI {
*/
static showNotification(type: MessageType, message: string): void {
switch (type) {
case MessageType.Info:
vscode.window.showInformationMessage(message);
break;
case MessageType.Warn:
vscode.window.showWarningMessage(message);
break;
case MessageType.Error:
vscode.window.showErrorMessage(message);
break;
default:
case MessageType.Info:
vscode.window.showInformationMessage(message);
break;
case MessageType.Warn:
vscode.window.showWarningMessage(message);
break;
case MessageType.Error:
vscode.window.showErrorMessage(message);
break;
default:
}
}
@ -141,7 +141,7 @@ export class UI {
*/
static async inputModelName(label: string, type: ModelType, folder: string): Promise<string> {
const placeHolder = `${type} name`;
const validateInput = async (name: string) => {
const validateInput = async (name: string): Promise<string|undefined> => {
return await Utility.validateModelName(name, type, folder);
};
return await UI.showInputBox(label, placeHolder, validateInput);
@ -181,7 +181,7 @@ export class UI {
* @param label label
*/
static async inputConnectionString(label: string): Promise<string> {
const validateInput = (name: string) => {
const validateInput = (name: string): string|undefined => {
return Utility.validateNotEmpty(name, "Connection string");
};
return await UI.showInputBox(label, UIConstants.REPOSITORY_CONNECTION_STRING_TEMPLATE, validateInput);

Просмотреть файл

@ -4,7 +4,7 @@ import * as fs from 'fs-plus';
import * as path from 'path';
import * as sdk from 'vscode-iot-device-cube-sdk';
import * as crypto from 'crypto';
import {ScaffoldType} from './constants';
import { ScaffoldType } from './constants';
import extractzip = require('extract-zip');
export class FileUtility {
@ -57,7 +57,7 @@ export class FileUtility {
if (type === ScaffoldType.Local) {
return await sdk.FileSystem.mkDir(dirPath);
} else {
return new Promise(async (resolve: (value?: void) => void, reject) => {
return new Promise((resolve: (value?: void) => void, reject) => {
fs.mkdir(dirPath, (error) => {
if (error) {
reject(error);
@ -88,13 +88,13 @@ export class FileUtility {
// Make sure filepath's parent directory exists
static async writeFile(
type: ScaffoldType, filePath: string,
data: string|Buffer): Promise<void> {
type: ScaffoldType, filePath: string,
data: string|Buffer): Promise<void> {
if (type === ScaffoldType.Local) {
return await sdk.FileSystem.writeFile(filePath, data);
} else {
return new Promise(async (resolve: (value?: void) => void, reject) => {
await fs.writeFile(filePath, data, (err) => {
return new Promise((resolve: (value?: void) => void, reject) => {
fs.writeFile(filePath, data, (err) => {
if (err) {
reject(err);
return;
@ -113,8 +113,8 @@ export class FileUtility {
* @param data Json object
*/
static async writeJsonFile(
// tslint:disable-next-line: no-any
type: ScaffoldType, fileDestPath: string, data: any): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: ScaffoldType, fileDestPath: string, data: any): Promise<void> {
const indentationSpace = 4;
const jsonString = JSON.stringify(data, null, indentationSpace);
@ -126,29 +126,29 @@ export class FileUtility {
}
static async readFile(
type: ScaffoldType, filePath: string,
encoding?: string): Promise<string|Buffer> {
type: ScaffoldType, filePath: string,
encoding?: string): Promise<string|Buffer> {
if (type === ScaffoldType.Local) {
return await sdk.FileSystem.readFile(filePath, encoding);
} else {
return new Promise(
async (resolve: (data: string|Buffer) => void, reject) => {
await fs.readFile(filePath, encoding, (err, data) => {
if (err) {
reject(err);
return;
}
resolve(data);
(resolve: (data: string|Buffer) => void, reject) => {
fs.readFile(filePath, encoding, (err, data) => {
if (err) {
reject(err);
return;
});
}
resolve(data);
return;
});
});
}
}
static async extractZipFile(sourceZip: string, targetFoder: string):
Promise<boolean> {
return new Promise((resolve: (value: boolean) => void, reject) => {
extractzip(sourceZip, {dir: targetFoder}, err => {
extractzip(sourceZip, { dir: targetFoder }, err => {
if (err) {
return reject(err);
} else {

Просмотреть файл

@ -4,11 +4,11 @@
import * as path from 'path';
import * as vscode from 'vscode';
import {CancelOperationError} from './CancelOperationError';
import {ConfigHandler} from './configHandler';
import {ConfigKey, OSPlatform} from './constants';
import {PickWithData} from './Models/Interfaces/UI';
import {getHomeDir, getPlatform} from './utils';
import { CancelOperationError } from './CancelOperationError';
import { ConfigHandler } from './configHandler';
import { ConfigKey, OSPlatform } from './constants';
import { PickWithData } from './Models/Interfaces/UI';
import { getHomeDir, getPlatform } from './utils';
export class IoTWorkbenchSettings {
private workbenchPath = '';
@ -23,8 +23,8 @@ export class IoTWorkbenchSettings {
ConfigHandler.get<string>(ConfigKey.workbench) ||
(await this.getDefaultWorkbenchPath());
await ConfigHandler.update(
ConfigKey.workbench, IoTWorkbenchSettings.instance.workbenchPath,
vscode.ConfigurationTarget.Global);
ConfigKey.workbench, IoTWorkbenchSettings.instance.workbenchPath,
vscode.ConfigurationTarget.Global);
}
return IoTWorkbenchSettings.instance;
@ -64,18 +64,18 @@ export class IoTWorkbenchSettings {
if (userWorkbenchPath) {
await ConfigHandler.update(
ConfigKey.workbench, userWorkbenchPath,
vscode.ConfigurationTarget.Global);
ConfigKey.workbench, userWorkbenchPath,
vscode.ConfigurationTarget.Global);
await vscode.window.showInformationMessage(
'Change workbench successfully.');
'Change workbench successfully.');
}
}
private async selectWorkbenchPath(): Promise<PickWithData<string>> {
const userWorkbenchPath = this.getWorkbenchPath();
const workbenchPicks: Array<PickWithData<string>> = [
{label: userWorkbenchPath, description: '', data: userWorkbenchPath},
{label: '$(file-directory) Browse...', description: '', data: '$'}
{ label: userWorkbenchPath, description: '', data: userWorkbenchPath },
{ label: '$(file-directory) Browse...', description: '', data: '$' }
];
const selection = await vscode.window.showQuickPick(workbenchPicks, {

Просмотреть файл

@ -4,7 +4,7 @@
import * as crypto from 'crypto';
import * as fs from 'fs-plus';
import * as getmac from 'getmac';
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as _ from 'lodash';
import * as opn from 'opn';
import * as os from 'os';
@ -12,18 +12,20 @@ import * as path from 'path';
import * as vscode from 'vscode';
import * as WinReg from 'winreg';
import {BoardProvider} from '../boardProvider';
import {ArduinoCommands} from '../common/Commands';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, FileNames, OSPlatform, ScaffoldType} from '../constants';
import {DialogResponses} from '../DialogResponses';
import {FileUtility} from '../FileUtility';
import {TelemetryContext} from '../telemetry';
import {delay, getRegistryValues} from '../utils';
import { BoardProvider } from '../boardProvider';
import { ArduinoCommands } from '../common/Commands';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, FileNames, OSPlatform, ScaffoldType } from '../constants';
import { DialogResponses } from '../DialogResponses';
import { FileUtility } from '../FileUtility';
import { TelemetryContext } from '../telemetry';
import { delay, getRegistryValues } from '../utils';
import {ArduinoDeviceBase} from './ArduinoDeviceBase';
import {DeviceType} from './Interfaces/Device';
import {DeviceConfig, TemplateFileInfo} from './Interfaces/ProjectTemplate';
import { ArduinoDeviceBase } from './ArduinoDeviceBase';
import { DeviceType } from './Interfaces/Device';
import { DeviceConfig, TemplateFileInfo } from './Interfaces/ProjectTemplate';
import { Board } from './Interfaces/Board';
import { reject } from 'bluebird';
const impor = require('impor')(__dirname);
const forEach = impor('lodash.foreach') as typeof import('lodash.foreach');
@ -53,7 +55,7 @@ enum ConfigDeviceOptions {
}
export class AZ3166Device extends ArduinoDeviceBase {
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static get serialport(): any {
if (!AZ3166Device._serialport) {
AZ3166Device._serialport =
@ -62,28 +64,28 @@ export class AZ3166Device extends ArduinoDeviceBase {
return AZ3166Device._serialport;
}
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static _serialport: any;
private componentId: string;
get id() {
get id(): string {
return this.componentId;
}
private templateFiles: TemplateFileInfo[] = [];
private static _boardId = 'devkit';
static get boardId() {
static get boardId(): string {
return AZ3166Device._boardId;
}
constructor(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, devicePath: string,
templateFiles?: TemplateFileInfo[]) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, devicePath: string,
templateFiles?: TemplateFileInfo[]) {
super(
context, devicePath, channel, telemetryContext,
DeviceType.MXChip_AZ3166);
context, devicePath, channel, telemetryContext,
DeviceType.MXChipAZ3166);
this.channel = channel;
this.componentId = Guid.create().toString();
if (templateFiles) {
@ -93,13 +95,13 @@ export class AZ3166Device extends ArduinoDeviceBase {
name = 'AZ3166';
get board() {
get board(): Board|undefined {
const boardProvider = new BoardProvider(this.boardFolderPath);
const az3166 = boardProvider.find({id: AZ3166Device._boardId});
const az3166 = boardProvider.find({ id: AZ3166Device._boardId });
return az3166;
}
get version() {
get version(): string {
const packageRootPath = this.getArduinoPackagePath();
let version = '0.0.1';
@ -133,8 +135,8 @@ export class AZ3166Device extends ArduinoDeviceBase {
'The ST-LINK driver for DevKit is not installed. Install now?';
const result: vscode.MessageItem|undefined =
await vscode.window.showWarningMessage(
message, DialogResponses.yes, DialogResponses.skipForNow,
DialogResponses.cancel);
message, DialogResponses.yes, DialogResponses.skipForNow,
DialogResponses.cancel);
if (result === DialogResponses.yes) {
// Open the download page
const installUri =
@ -165,7 +167,7 @@ export class AZ3166Device extends ArduinoDeviceBase {
if (configSelection.detail === 'Config CRC') {
const retValue: boolean =
await this.generateCrc(this.extensionContext, this.channel);
await this.generateCrc(this.channel);
return retValue;
} else if (configSelection.detail === 'Config Connection String') {
// Get IoT Hub device connection string from config
@ -174,8 +176,8 @@ export class AZ3166Device extends ArduinoDeviceBase {
const deviceConnectionStringSelection =
this.getDeviceConnectionStringOptions(deviceConnectionString);
const selection = await vscode.window.showQuickPick(
deviceConnectionStringSelection,
{ignoreFocusOut: true, placeHolder: 'Choose an option:'});
deviceConnectionStringSelection,
{ ignoreFocusOut: true, placeHolder: 'Choose an option:' });
if (!selection) {
return false;
}
@ -188,7 +190,7 @@ export class AZ3166Device extends ArduinoDeviceBase {
'Need more information on how to get device connection string?';
const result: vscode.MessageItem|undefined =
await vscode.window.showWarningMessage(
message, DialogResponses.yes, DialogResponses.no);
message, DialogResponses.yes, DialogResponses.no);
if (result === DialogResponses.yes) {
opn(constants.informationPageUrl);
}
@ -201,12 +203,12 @@ export class AZ3166Device extends ArduinoDeviceBase {
console.log(deviceConnectionString);
const res = await this.setDeviceConfig(
deviceConnectionString, ConfigDeviceOptions.ConnectionString);
deviceConnectionString, ConfigDeviceOptions.ConnectionString);
if (!res) {
return false;
} else {
vscode.window.showInformationMessage(
'Configure Device connection string completely.');
'Configure Device connection string completely.');
return true;
}
} else if (configSelection.detail === 'Config DPS') {
@ -218,12 +220,12 @@ export class AZ3166Device extends ArduinoDeviceBase {
console.log(deviceConnectionString);
const res = await this.setDeviceConfig(
deviceConnectionString, ConfigDeviceOptions.DPS);
deviceConnectionString, ConfigDeviceOptions.DPS);
if (!res) {
return false;
} else {
vscode.window.showInformationMessage(
'Config DPS credentials completely.');
'Config DPS credentials completely.');
return true;
}
@ -240,7 +242,7 @@ export class AZ3166Device extends ArduinoDeviceBase {
return false;
} else {
vscode.window.showInformationMessage(
'Configure Unique Device String (UDS) completed successfully.');
'Configure Unique Device String (UDS) completed successfully.');
return true;
}
}
@ -251,23 +253,23 @@ export class AZ3166Device extends ArduinoDeviceBase {
// Read options configuration JSON
const devciceConfigFilePath: string =
this.extensionContext.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.configDeviceOptionsFileName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.configDeviceOptionsFileName));
const configSelectionItemsFilePath = await FileUtility.readFile(
ScaffoldType.Local, devciceConfigFilePath, 'utf8');
ScaffoldType.Local, devciceConfigFilePath, 'utf8');
const configSelectionItemsContent =
JSON.parse(configSelectionItemsFilePath as string);
const configSelectionItems: vscode.QuickPickItem[] = [];
configSelectionItemsContent.configSelectionItems.forEach(
(element: DeviceConfig) => {
configSelectionItems.push({
label: element.label,
description: element.description,
detail: element.detail
});
(element: DeviceConfig) => {
configSelectionItems.push({
label: element.label,
description: element.description,
detail: element.detail
});
});
return configSelectionItems;
}
@ -390,8 +392,9 @@ export class AZ3166Device extends ArduinoDeviceBase {
// Try to close serial monitor
try {
await vscode.commands.executeCommand(
ArduinoCommands.CloseSerialMonitor, null, false);
ArduinoCommands.CloseSerialMonitor, null, false);
} catch (ignore) {
// Ignore error if fail to close serial monitor
}
// Set selected connection string to device
@ -406,339 +409,346 @@ export class AZ3166Device extends ArduinoDeviceBase {
async flushDeviceConfigUnixAndMac(configValue: string, option: number):
Promise<boolean> {
return new Promise(
async (
resolve: (value: boolean) => void,
reject: (value: Error) => void) => {
let comPort = '';
let command = '';
try {
// Choose COM port that AZ3166 is connected
comPort = await this.chooseCOM();
console.log(`Opening ${comPort}.`);
} catch (error) {
reject(error);
}
if (option === ConfigDeviceOptions.ConnectionString) {
command = 'set_az_iothub';
} else if (option === ConfigDeviceOptions.DPS) {
command = 'set_az_iotdps';
} else {
command = 'set_dps_uds';
}
let errorRejected = false;
// eslint-disable-next-line no-async-promise-executor
async (
resolve: (value: boolean) => void,
reject: (value: Error) => void) => {
let comPort = '';
let command = '';
try {
// Choose COM port that AZ3166 is connected
comPort = await this.chooseCOM();
console.log(`Opening ${comPort}.`);
} catch (error) {
reject(error);
}
if (option === ConfigDeviceOptions.ConnectionString) {
command = 'set_az_iothub';
} else if (option === ConfigDeviceOptions.DPS) {
command = 'set_az_iotdps';
} else {
command = 'set_dps_uds';
}
let errorRejected = false;
const az3166 = this.board;
const az3166 = this.board;
if (!az3166) {
return reject(
new Error('IoT DevKit is not found in the board list.'));
}
if (!az3166) {
return reject(
new Error('IoT DevKit is not found in the board list.'));
}
const port = new AZ3166Device.serialport(comPort, {
baudRate: az3166.defaultBaudRate,
dataBits: 8,
stopBits: 1,
xon: false,
xoff: false,
parity: 'none'
});
const port = new AZ3166Device.serialport(comPort, {
baudRate: az3166.defaultBaudRate,
dataBits: 8,
stopBits: 1,
xon: false,
xoff: false,
parity: 'none'
});
const rejectIfError = (err: Error) => {
if (errorRejected) return true;
if (err) {
errorRejected = true;
reject(err);
try {
port.close();
} catch (ignore) {
}
}
return true;
};
const executeSetAzIoTHub = async () => {
const rejectIfError = (err: Error): boolean => {
if (errorRejected) return true;
if (err) {
errorRejected = true;
reject(err);
try {
const data = `${command} "${configValue}"\r\n`;
let restDataLength = data.length;
while (restDataLength > 0) {
const start = data.length - restDataLength;
const length = Math.min(100, restDataLength);
restDataLength -= length;
const dataChunk = data.substr(start, length);
await this.sendDataViaSerialPort(port, dataChunk);
await delay(1000);
}
port.close();
} catch (ignore) {
// ignore error if fail to close port.
}
}
return true;
};
const executeSetAzIoTHub = async (): Promise<void> => {
try {
const data = `${command} "${configValue}"\r\n`;
let restDataLength = data.length;
while (restDataLength > 0) {
const start = data.length - restDataLength;
const length = Math.min(100, restDataLength);
restDataLength -= length;
const dataChunk = data.substr(start, length);
await this.sendDataViaSerialPort(port, dataChunk);
await delay(1000);
}
if (errorRejected) {
return;
} else {
resolve(true);
}
};
port.close();
} catch (ignore) {
// Ignore error if fail to close port
}
// Configure serial port callbacks
port.on('open', async () => {
// tslint:disable-next-line: no-any
await vscode.window.showInformationMessage(
'Please hold down button A and then push and release the reset button to enter configuration mode. After enter configuration mode, click OK.',
'OK');
executeSetAzIoTHub()
.then(() => resolve(true))
.catch((error) => reject(error));
});
if (errorRejected) {
return;
} else {
resolve(true);
}
};
// tslint:disable-next-line: no-any
port.on('error', (error: any) => {
if (errorRejected) return;
console.log(error);
rejectIfError(error);
});
// Configure serial port callbacks
port.on('open', async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
await vscode.window.showInformationMessage(
'Please hold down button A and then push and release the reset button to enter configuration mode. After enter configuration mode, click OK.',
'OK');
executeSetAzIoTHub()
.then(() => resolve(true))
.catch((error) => reject(error));
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
port.on('error', (error: any) => {
if (errorRejected) return;
console.log(error);
rejectIfError(error);
});
});
}
async flushDeviceConfig(configValue: string, option: number):
Promise<boolean> {
return new Promise(
async (
resolve: (value: boolean) => void,
reject: (value: Error) => void) => {
let comPort = '';
let command = '';
try {
// Choose COM port that AZ3166 is connected
comPort = await this.chooseCOM();
console.log(`Opening ${comPort}.`);
} catch (error) {
reject(error);
}
if (option === ConfigDeviceOptions.ConnectionString) {
command = 'set_az_iothub';
} else if (option === ConfigDeviceOptions.DPS) {
command = 'set_az_iotdps';
} else {
command = 'set_dps_uds';
}
let configMode = false;
let errorRejected = false;
let commandExecuted = false;
let gotData = false;
// eslint-disable-next-line no-async-promise-executor
async (
resolve: (value: boolean) => void,
reject: (value: Error) => void) => {
let comPort = '';
let command = '';
try {
// Choose COM port that AZ3166 is connected
comPort = await this.chooseCOM();
console.log(`Opening ${comPort}.`);
} catch (error) {
reject(error);
}
if (option === ConfigDeviceOptions.ConnectionString) {
command = 'set_az_iothub';
} else if (option === ConfigDeviceOptions.DPS) {
command = 'set_az_iotdps';
} else {
command = 'set_dps_uds';
}
let configMode = false;
let errorRejected = false;
let commandExecuted = false;
let gotData = false;
const az3166 = this.board;
const az3166 = this.board;
if (!az3166) {
return reject(
new Error('IoT DevKit is not found in the board list.'));
}
if (!az3166) {
return reject(
new Error('IoT DevKit is not found in the board list.'));
}
const port = new AZ3166Device.serialport(comPort, {
baudRate: az3166.defaultBaudRate,
dataBits: 8,
stopBits: 1,
xon: false,
xoff: false,
parity: 'none'
});
const port = new AZ3166Device.serialport(comPort, {
baudRate: az3166.defaultBaudRate,
dataBits: 8,
stopBits: 1,
xon: false,
xoff: false,
parity: 'none'
});
const rejectIfError = (err: Error) => {
if (errorRejected) return true;
if (err) {
errorRejected = true;
reject(err);
try {
port.close();
} catch (ignore) {
}
}
return true;
};
const executeSetAzIoTHub = async () => {
const rejectIfError = (err: Error): boolean => {
if (errorRejected) return true;
if (err) {
errorRejected = true;
reject(err);
try {
const data = `${command} "${configValue}"\r\n`;
const maxDataLength = 256;
await this.sendDataViaSerialPort(
port, data.slice(0, maxDataLength));
if (data.length > maxDataLength) {
await delay(1000);
await this.sendDataViaSerialPort(
port, data.slice(maxDataLength));
}
await delay(1000);
port.close();
} catch (ignore) {
// Ignore error if fail to close port
}
}
return true;
};
const executeSetAzIoTHub = async (): Promise<void> => {
try {
const data = `${command} "${configValue}"\r\n`;
const maxDataLength = 256;
await this.sendDataViaSerialPort(
port, data.slice(0, maxDataLength));
if (data.length > maxDataLength) {
await delay(1000);
await this.sendDataViaSerialPort(
port, data.slice(maxDataLength));
}
if (errorRejected) {
return;
} else {
resolve(true);
}
};
await delay(1000);
port.close();
} catch (ignore) {
// Ignore error if fail to close port
}
// Configure serial port callbacks
port.on('open', () => {
port.write(
'\r\nhelp\r\n',
// tslint:disable-next-line: no-any
(error: any) => {
if (rejectIfError(error)) return;
});
});
if (errorRejected) {
return;
} else {
resolve(true);
}
};
// tslint:disable-next-line: no-any
port.on('data', (data: any) => {
gotData = true;
const output = data.toString().trim();
if (commandExecuted) return;
if (output.includes('set_')) {
commandExecuted = true;
configMode = true;
executeSetAzIoTHub()
.then(() => resolve(true))
.catch((error) => reject(error));
} else {
configMode = false;
}
if (configMode) {
forEach(output.split('\n'), line => {
if (line) {
line = trimStart(line.trim(), '#').trim();
if (line && line.length) {
console.log('SerialOutput', line);
}
}
});
}
});
// tslint:disable-next-line: no-any
port.on('error', (error: any) => {
if (errorRejected) return;
console.log(error);
rejectIfError(error);
});
setTimeout(() => {
if (errorRejected) return;
// Prompt user to enter configuration mode
if (!gotData || !configMode) {
vscode.window
.showInformationMessage(
'Please hold down button A and then push and release the reset button to enter configuration mode.')
.then(() => {
port.write(
'\r\nhelp\r\n',
// tslint:disable-next-line: no-any
(error: any) => {
rejectIfError(error);
});
});
}
}, 10000);
// Configure serial port callbacks
port.on('open', () => {
port.write(
'\r\nhelp\r\n',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(error: any) => {
if (rejectIfError(error)) return;
});
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
port.on('data', (data: any) => {
gotData = true;
const output = data.toString().trim();
if (commandExecuted) return;
if (output.includes('set_')) {
commandExecuted = true;
configMode = true;
executeSetAzIoTHub()
.then(() => resolve(true))
.catch((error) => reject(error));
} else {
configMode = false;
}
if (configMode) {
forEach(output.split('\n'), line => {
if (line) {
line = trimStart(line.trim(), '#').trim();
if (line && line.length) {
console.log('SerialOutput', line);
}
}
});
}
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
port.on('error', (error: any) => {
if (errorRejected) return;
console.log(error);
rejectIfError(error);
});
setTimeout(() => {
if (errorRejected) return;
// Prompt user to enter configuration mode
if (!gotData || !configMode) {
vscode.window
.showInformationMessage(
'Please hold down button A and then push and release the reset button to enter configuration mode.')
.then(() => {
port.write(
'\r\nhelp\r\n',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(error: any) => {
rejectIfError(error);
});
});
}
}, 10000);
});
}
private getComList(): Promise<SerialPortInfo[]> {
return new Promise(
(resolve: (value: SerialPortInfo[]) => void,
reject: (error: Error) => void) => {
// tslint:disable-next-line: no-any
AZ3166Device.serialport.list((e: any, ports: SerialPortInfo[]) => {
if (e) {
reject(e);
} else {
resolve(ports);
}
});
(resolve: (value: SerialPortInfo[]) => void,
reject: (error: Error) => void) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
AZ3166Device.serialport.list((e: any, ports: SerialPortInfo[]) => {
if (e) {
reject(e);
} else {
resolve(ports);
}
});
});
}
private async chooseCOM(): Promise<string> {
return new Promise(
async (
resolve: (value: string) => void,
reject: (reason: Error) => void) => {
const comList = await this.getComList();
// eslint-disable-next-line no-async-promise-executor
async (
resolve: (value: string) => void,
reject: (reason: Error) => void) => {
const comList = await this.getComList();
const az3166 = this.board;
const az3166 = this.board;
if (!az3166) {
return reject(new Error('AZ3166 is not found in the board list.'));
}
if (!az3166) {
return reject(new Error('AZ3166 is not found in the board list.'));
}
const list = _.filter(comList, com => {
if (com.vendorId && com.productId && az3166.vendorId &&
const list = _.filter(comList, com => {
if (com.vendorId && com.productId && az3166.vendorId &&
az3166.productId &&
com.vendorId.toLowerCase().endsWith(az3166.vendorId) &&
com.productId.toLowerCase().endsWith(az3166.productId)) {
return true;
} else {
return false;
}
});
if (list && list.length) {
let comPort = list[0].comName;
if (list.length > 1) {
// TODO: select com port from list when there are multiple AZ3166
// boards connected
comPort = list[0].comName;
}
if (!comPort) {
reject(new Error('No avalible COM port.'));
}
resolve(comPort);
return true;
} else {
reject(new Error('No AZ3166 board connected.'));
return false;
}
});
if (list && list.length) {
let comPort = list[0].comName;
if (list.length > 1) {
// TODO: select com port from list when there are multiple AZ3166
// boards connected
comPort = list[0].comName;
}
if (!comPort) {
reject(new Error('No avalible COM port.'));
}
resolve(comPort);
} else {
reject(new Error('No AZ3166 board connected.'));
}
});
}
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async sendDataViaSerialPort(port: any, data: string):
Promise<boolean> {
return new Promise(
(resolve: (value: boolean) => void, reject: (value: Error) => void) => {
try {
port.write(
data,
// tslint:disable-next-line: no-any
(err: any) => {
if (err) {
reject(err);
} else {
port.drain(() => resolve(true));
}
});
} catch (err) {
reject(err);
}
});
(resolve: (value: boolean) => void, reject: (value: Error) => void) => {
try {
port.write(
data,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(err: any) => {
if (err) {
reject(err);
} else {
port.drain(() => resolve(true));
}
});
} catch (err) {
reject(err);
}
});
}
private async stlinkDriverInstalled() {
private async stlinkDriverInstalled(): Promise<boolean> {
const platform = os.platform();
if (platform === OSPlatform.WIN32) {
try {
// The STlink driver would write to the following registry.
const pathString = await getRegistryValues(
WinReg.HKLM,
'\\SYSTEM\\ControlSet001\\Control\\Class\\{88bae032-5a81-49f0-bc3d-a4ff138216d6}',
'Class');
WinReg.HKLM,
'\\SYSTEM\\ControlSet001\\Control\\Class\\{88bae032-5a81-49f0-bc3d-a4ff138216d6}',
'Class');
if (pathString) {
return true;
} else {
@ -752,18 +762,18 @@ export class AZ3166Device extends ArduinoDeviceBase {
return true;
}
private async generatePlatformLocal() {
private async generatePlatformLocal(): Promise<void> {
const arduinoPackagePath = this.getArduinoPackagePath();
function getHashMacAsync() {
function getHashMacAsync(): Promise<unknown> {
return new Promise((resolve) => {
getmac.getMac((err, macAddress) => {
if (err) {
throw (err);
reject(err);
}
const hashMacAddress = crypto.createHash('sha256')
.update(macAddress, 'utf8')
.digest('hex');
.update(macAddress, 'utf8')
.digest('hex');
resolve(hashMacAddress);
});
});
@ -771,7 +781,7 @@ export class AZ3166Device extends ArduinoDeviceBase {
if (!fs.existsSync(arduinoPackagePath)) {
throw new Error(
'Unable to locate Arduino IDE. Please install it from https://www.arduino.cc/en/main/software and use "Arduino: Board Manager" to install your device packages. Restart VS Code to apply to changes.');
'Unable to locate Arduino IDE. Please install it from https://www.arduino.cc/en/main/software and use "Arduino: Board Manager" to install your device packages. Restart VS Code to apply to changes.');
}
const files = fs.readdirSync(arduinoPackagePath);
@ -783,38 +793,34 @@ export class AZ3166Device extends ArduinoDeviceBase {
if (files.length === 0 || files.length > 1) {
throw new Error(
'There are unexpected files or folders under Arduino package installation path. Please clear the folder and reinstall the package for Devkit.');
'There are unexpected files or folders under Arduino package installation path. Please clear the folder and reinstall the package for Devkit.');
}
const directoryName = path.join(arduinoPackagePath, files[0]);
if (!fs.isDirectorySync(directoryName)) {
throw new Error(
'The Arduino package for MXChip IoT Devkit is not installed. Please follow the guide to install it');
'The Arduino package for MXChip IoT Devkit is not installed. Please follow the guide to install it');
}
const fileName = path.join(directoryName, constants.platformLocalFileName);
if (!fs.existsSync(fileName)) {
const enableTrace = 1;
let hashMacAddress;
hashMacAddress = await getHashMacAsync();
const hashMacAddress = await getHashMacAsync();
// Create the file of platform.local.txt
const targetFileName =
path.join(directoryName, constants.platformLocalFileName);
const content = `${constants.cExtraFlag}${hashMacAddress}" ${
constants.traceExtraFlag}${enableTrace}\r\n` +
constants.traceExtraFlag}${enableTrace}\r\n` +
`${constants.cppExtraFlag}${hashMacAddress}" ${
constants.traceExtraFlag}${enableTrace}\r\n`;
try {
fs.writeFileSync(targetFileName, content);
} catch (e) {
throw e;
}
constants.traceExtraFlag}${enableTrace}\r\n`;
fs.writeFileSync(targetFileName, content);
}
}
private getArduinoPackagePath() {
private getArduinoPackagePath(): string {
const platform = os.platform();
// TODO: Currently, we do not support portable Arduino installation.

Просмотреть файл

@ -3,27 +3,31 @@
import * as vscode from 'vscode';
import {AzureAccount} from '../azure-account.api';
import {AzureAccountCommands} from '../common/Commands';
import { AzureAccount } from '../azure-account.api';
import { AzureAccountCommands } from '../common/Commands';
import {ExtensionName} from './Interfaces/Api';
import { ExtensionName } from './Interfaces/Api';
export function getExtension(name: ExtensionName) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getExtension(name: ExtensionName): any {
switch (name) {
case ExtensionName.Toolkit:
const toolkit =
case ExtensionName.Toolkit:{
const toolkit =
vscode.extensions.getExtension('vsciot-vscode.azure-iot-toolkit');
return toolkit ? toolkit.exports : undefined;
case ExtensionName.AzureAccount:
const azureAccount = vscode.extensions.getExtension<AzureAccount>(
'ms-vscode.azure-account');
return azureAccount ? azureAccount.exports : undefined;
case ExtensionName.DigitalTwins:
const digitalTwins =
return toolkit ? toolkit.exports : undefined;
}
case ExtensionName.AzureAccount:{
const azureAccount = vscode.extensions.getExtension<AzureAccount>(
'ms-vscode.azure-account');
return azureAccount ? azureAccount.exports : undefined;
}
case ExtensionName.DigitalTwins:{
const digitalTwins =
vscode.extensions.getExtension('vsciot-vscode.azure-digital-twins');
return digitalTwins ? digitalTwins.exports : undefined;
default:
return undefined;
return digitalTwins ? digitalTwins.exports : undefined;
}
default:
return undefined;
}
}
@ -31,7 +35,7 @@ export async function checkAzureLogin(): Promise<boolean> {
const azureAccount = getExtension(ExtensionName.AzureAccount);
if (!azureAccount) {
throw new Error(
'Azure account extension is not found. Please install it from Marketplace.');
'Azure account extension is not found. Please install it from Marketplace.');
}
// Sign in Azure

Просмотреть файл

@ -5,18 +5,18 @@ import * as fs from 'fs-plus';
import * as path from 'path';
import * as vscode from 'vscode';
import {VscodeCommands} from '../common/Commands';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, DependentExtensions, FileNames, OperationType, OSPlatform, PlatformType, ScaffoldType} from '../constants';
import {FileUtility} from '../FileUtility';
import {TelemetryContext} from '../telemetry';
import { VscodeCommands } from '../common/Commands';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, DependentExtensions, FileNames, OperationType, OSPlatform, PlatformType, ScaffoldType } from '../constants';
import { FileUtility } from '../FileUtility';
import { TelemetryContext } from '../telemetry';
import * as utils from '../utils';
import {Board} from './Interfaces/Board';
import {ComponentType} from './Interfaces/Component';
import {Device, DeviceType} from './Interfaces/Device';
import {TemplateFileInfo} from './Interfaces/ProjectTemplate';
import {OTA} from './OTA';
import { Board } from './Interfaces/Board';
import { ComponentType } from './Interfaces/Component';
import { Device, DeviceType } from './Interfaces/Device';
import { TemplateFileInfo } from './Interfaces/ProjectTemplate';
import { OTA } from './OTA';
const constants = {
defaultSketchFileName: 'device.ino',
@ -47,9 +47,9 @@ export abstract class ArduinoDeviceBase implements Device {
abstract board: Board|undefined;
constructor(
context: vscode.ExtensionContext, devicePath: string,
channel: vscode.OutputChannel, telemetryContext: TelemetryContext,
deviceType: DeviceType) {
context: vscode.ExtensionContext, devicePath: string,
channel: vscode.OutputChannel, telemetryContext: TelemetryContext,
deviceType: DeviceType) {
this.deviceType = deviceType;
this.componentType = ComponentType.Device;
this.deviceFolder = devicePath;
@ -57,7 +57,7 @@ export abstract class ArduinoDeviceBase implements Device {
this.vscodeFolderPath =
path.join(this.deviceFolder, FileNames.vscodeSettingsFolderName);
this.boardFolderPath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName));
FileNames.resourcesFolderName, FileNames.templatesFolderName));
this.telemetryContext = telemetryContext;
this.channel = channel;
}
@ -73,13 +73,13 @@ export abstract class ArduinoDeviceBase implements Device {
static async isAvailable(): Promise<boolean> {
if (!vscode.extensions.getExtension(DependentExtensions.arduino)) {
const choice = await vscode.window.showInformationMessage(
'Arduino extension is required for the current project. Do you want to install it from marketplace?',
'Yes', 'No');
'Arduino extension is required for the current project. Do you want to install it from marketplace?',
'Yes', 'No');
if (choice === 'Yes') {
vscode.commands.executeCommand(
VscodeCommands.VscodeOpen,
vscode.Uri.parse(
'vscode:extension/' + DependentExtensions.arduino));
VscodeCommands.VscodeOpen,
vscode.Uri.parse(
'vscode:extension/' + DependentExtensions.arduino));
}
return false;
}
@ -102,9 +102,9 @@ export abstract class ArduinoDeviceBase implements Device {
}
await utils.fetchAndExecuteTask(
this.extensionContext, this.channel, this.telemetryContext,
this.deviceFolder, OperationType.Compile, PlatformType.Arduino,
constants.compileTaskName);
this.extensionContext, this.channel, this.telemetryContext,
this.deviceFolder, OperationType.Compile, PlatformType.Arduino,
constants.compileTaskName);
return true;
}
@ -114,9 +114,9 @@ export abstract class ArduinoDeviceBase implements Device {
return false;
}
await utils.fetchAndExecuteTask(
this.extensionContext, this.channel, this.telemetryContext,
this.deviceFolder, OperationType.Upload, PlatformType.Arduino,
constants.uploadTaskName);
this.extensionContext, this.channel, this.telemetryContext,
this.deviceFolder, OperationType.Upload, PlatformType.Arduino,
constants.uploadTaskName);
return true;
}
@ -128,7 +128,7 @@ export abstract class ArduinoDeviceBase implements Device {
const loadTimeScaffoldType = ScaffoldType.Workspace;
if (!await FileUtility.directoryExists(
loadTimeScaffoldType, deviceFolderPath)) {
loadTimeScaffoldType, deviceFolderPath)) {
throw new Error('Unable to find the device folder inside the project.');
}
@ -147,7 +147,7 @@ export abstract class ArduinoDeviceBase implements Device {
// Generate template files
const createTimeScaffoldType = ScaffoldType.Local;
if (!await FileUtility.directoryExists(
createTimeScaffoldType, this.deviceFolder)) {
createTimeScaffoldType, this.deviceFolder)) {
throw new Error(`Internal error: Couldn't find the template folder.`);
}
if (!board) {
@ -156,14 +156,14 @@ export abstract class ArduinoDeviceBase implements Device {
for (const fileInfo of templateFiles) {
await utils.generateTemplateFile(
this.deviceFolder, createTimeScaffoldType, fileInfo);
this.deviceFolder, createTimeScaffoldType, fileInfo);
}
await this.generateCppPropertiesFile(createTimeScaffoldType, board);
// Configurate device environment
await this.configDeviceEnvironment(
this.deviceFolder, createTimeScaffoldType);
this.deviceFolder, createTimeScaffoldType);
}
// Backward compatibility: Check configuration
@ -174,7 +174,7 @@ export abstract class ArduinoDeviceBase implements Device {
abstract get version(): string;
private async writeCppPropertiesFile(
boardId: string, type: ScaffoldType, platform: string): Promise<void> {
boardId: string, type: ScaffoldType, platform: string): Promise<void> {
const cppPropertiesFilePath =
path.join(this.vscodeFolderPath, constants.cppPropertiesFileName);
@ -200,8 +200,8 @@ export abstract class ArduinoDeviceBase implements Device {
const cppPropertiesTemplateFilePath =
this.extensionContext.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
boardId, cppPropertiesTemplateFileName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
boardId, cppPropertiesTemplateFileName));
const propertiesContent =
await FileUtility.readFile(type, cppPropertiesTemplateFilePath);
const propertiesContentString = propertiesContent.toString();
@ -232,8 +232,7 @@ export abstract class ArduinoDeviceBase implements Device {
}
}
async generateCrc(
context: vscode.ExtensionContext, channel: vscode.OutputChannel) {
async generateCrc(channel: vscode.OutputChannel): Promise<boolean> {
if (!(vscode.workspace.workspaceFolders &&
vscode.workspace.workspaceFolders.length > 0)) {
const message = 'No workspace opened.';
@ -250,8 +249,8 @@ export abstract class ArduinoDeviceBase implements Device {
return false;
}
const deviceBuildLocation = path.join(
vscode.workspace.workspaceFolders[0].uri.fsPath, '..', devicePath,
'.build');
vscode.workspace.workspaceFolders[0].uri.fsPath, '..', devicePath,
'.build');
if (!deviceBuildLocation) {
const message = 'No device compile output folder found.';
@ -277,7 +276,7 @@ export abstract class ArduinoDeviceBase implements Device {
const binFilePickItems: vscode.QuickPickItem[] = [];
for (const file of binFiles) {
const fileName = path.basename(file);
binFilePickItems.push({label: fileName, description: file});
binFilePickItems.push({ label: fileName, description: file });
}
const choice = await vscode.window.showQuickPick(binFilePickItems, {
@ -315,15 +314,15 @@ export abstract class ArduinoDeviceBase implements Device {
}
async configDeviceEnvironment(
deviceRootPath: string, scaffoldType: ScaffoldType): Promise<void> {
deviceRootPath: string, scaffoldType: ScaffoldType): Promise<void> {
if (!deviceRootPath) {
throw new Error(
'Unable to find the project device path, please open the folder and initialize project again.');
'Unable to find the project device path, please open the folder and initialize project again.');
}
const templateFilesInfo = await utils.getEnvTemplateFilesAndAskOverwrite(
this.extensionContext, this.deviceFolder, scaffoldType,
constants.environmentTemplateFolderName);
this.extensionContext, this.deviceFolder, scaffoldType,
constants.environmentTemplateFolderName);
// Configure project environment with template files
for (const fileInfo of templateFilesInfo) {

Просмотреть файл

@ -1,13 +1,13 @@
import * as path from 'path';
import {AzureComponentsStorage, ScaffoldType} from '../constants';
import {FileUtility} from '../FileUtility';
import { AzureComponentsStorage, ScaffoldType } from '../constants';
import { FileUtility } from '../FileUtility';
import {Component} from './Interfaces/Component';
import {ComponentType} from './Interfaces/Component';
import { Component } from './Interfaces/Component';
import { ComponentType } from './Interfaces/Component';
// TODO: need to check what value should be included here
export interface ComponentInfo { values: {[key: string]: string}; }
export interface ComponentInfo { values: {[key: string]: string} }
export enum DependencyType {
Other,
@ -29,7 +29,7 @@ export interface AzureComponentConfig {
componentInfo?: ComponentInfo;
}
export interface AzureConfigs { componentConfigs: AzureComponentConfig[]; }
export interface AzureConfigs { componentConfigs: AzureComponentConfig[] }
export interface Dependency {
component: Component;
@ -43,12 +43,12 @@ export class AzureConfigFileHandler {
constructor(projectRoot: string) {
this.projectRootPath = projectRoot;
this.configFilePath = path.join(
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
}
async createIfNotExists(type: ScaffoldType) {
const azureConfigs: AzureConfigs = {componentConfigs: []};
async createIfNotExists(type: ScaffoldType): Promise<void> {
const azureConfigs: AzureConfigs = { componentConfigs: [] };
const azureConfigFolderPath =
path.join(this.projectRootPath, AzureComponentsStorage.folderName);
if (!await FileUtility.directoryExists(type, azureConfigFolderPath)) {
@ -56,7 +56,7 @@ export class AzureConfigFileHandler {
await FileUtility.mkdirRecursively(type, azureConfigFolderPath);
} catch (error) {
throw new Error(`Failed to create azure config folder. Error message: ${
error.message}`);
error.message}`);
}
}
const azureConfigFilePath =
@ -67,7 +67,7 @@ export class AzureConfigFileHandler {
}
}
async getSortedComponents(type: ScaffoldType) {
async getSortedComponents(type: ScaffoldType): Promise<AzureComponentConfig[]> {
try {
const azureConfigContent =
await FileUtility.readFile(type, this.configFilePath, 'utf8');
@ -108,7 +108,7 @@ export class AzureConfigFileHandler {
}
}
async getComponentIndexById(type: ScaffoldType, id: string) {
async getComponentIndexById(type: ScaffoldType, id: string): Promise<number> {
try {
const azureConfigContent =
await FileUtility.readFile(type, this.configFilePath, 'utf8');
@ -122,7 +122,7 @@ export class AzureConfigFileHandler {
}
}
async getComponentById(type: ScaffoldType, id: string) {
async getComponentById(type: ScaffoldType, id: string): Promise<AzureComponentConfig | undefined> {
try {
const azureConfigContent =
await FileUtility.readFile(type, this.configFilePath, 'utf8');
@ -136,7 +136,7 @@ export class AzureConfigFileHandler {
}
}
async appendComponent(type: ScaffoldType, component: AzureComponentConfig) {
async appendComponent(type: ScaffoldType, component: AzureComponentConfig): Promise<AzureConfigs> {
try {
const azureConfigContent =
await FileUtility.readFile(type, this.configFilePath, 'utf8');
@ -150,8 +150,7 @@ export class AzureConfigFileHandler {
}
}
async updateComponent(
type: ScaffoldType, index: number, componentInfo: ComponentInfo) {
async updateComponent(type: ScaffoldType, index: number, componentInfo: ComponentInfo): Promise<AzureConfigs> {
try {
const azureConfigContent =
await FileUtility.readFile(type, this.configFilePath, 'utf8');

Просмотреть файл

@ -9,23 +9,23 @@ import * as vscode from 'vscode';
import * as utils from '../utils';
import WebSiteManagementClient = require('azure-arm-website');
import {Component, ComponentType} from './Interfaces/Component';
import {Provisionable} from './Interfaces/Provisionable';
import {Deployable} from './Interfaces/Deployable';
import { Component, ComponentType } from './Interfaces/Component';
import { Provisionable } from './Interfaces/Provisionable';
import { Deployable } from './Interfaces/Deployable';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, AzureFunctionsLanguage, AzureComponentsStorage, DependentExtensions, ScaffoldType} from '../constants';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, AzureFunctionsLanguage, AzureComponentsStorage, DependentExtensions, ScaffoldType } from '../constants';
import {ServiceClientCredentials} from 'ms-rest';
import {AzureAccount, AzureResourceFilter} from '../azure-account.api';
import {StringDictionary} from 'azure-arm-website/lib/models';
import {getExtension} from './Apis';
import {ExtensionName} from './Interfaces/Api';
import {Guid} from 'guid-typescript';
import {AzureComponentConfig, AzureConfigs, ComponentInfo, DependencyConfig, Dependency} from './AzureComponentConfig';
import {FileUtility} from '../FileUtility';
import {VscodeCommands, AzureFunctionsCommands} from '../common/Commands';
import {CancelOperationError} from '../CancelOperationError';
import { ServiceClientCredentials } from 'ms-rest';
import { AzureAccount, AzureResourceFilter } from '../azure-account.api';
import { StringDictionary } from 'azure-arm-website/lib/models';
import { getExtension } from './Apis';
import { ExtensionName } from './Interfaces/Api';
import { Guid } from 'guid-typescript';
import { AzureComponentConfig, AzureConfigs, ComponentInfo, DependencyConfig, Dependency } from './AzureComponentConfig';
import { FileUtility } from '../FileUtility';
import { VscodeCommands, AzureFunctionsCommands } from '../common/Commands';
import { CancelOperationError } from '../CancelOperationError';
const impor = require('impor')(__dirname);
const azureUtilityModule =
@ -42,7 +42,7 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
private functionFolder: string;
private componentId: string;
get id() {
get id(): string {
return this.componentId;
}
@ -69,9 +69,9 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
}
constructor(
azureFunctionsPath: string, functionFolder: string,
channel: vscode.OutputChannel, language: string|null = null,
dependencyComponents: Dependency[]|null = null) {
azureFunctionsPath: string, functionFolder: string,
channel: vscode.OutputChannel, language: string|null = null,
dependencyComponents: Dependency[]|null = null) {
this.componentType = ComponentType.AzureFunctions;
this.channel = channel;
this.azureFunctionsPath = azureFunctionsPath;
@ -80,8 +80,8 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
this.componentId = Guid.create().toString();
if (dependencyComponents && dependencyComponents.length > 0) {
dependencyComponents.forEach(
dependency => this.dependencies.push(
{id: dependency.component.id.toString(), type: dependency.type}));
dependency => this.dependencies.push(
{ id: dependency.component.id.toString(), type: dependency.type }));
}
}
@ -94,13 +94,13 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
static async isAvailable(): Promise<boolean> {
if (!vscode.extensions.getExtension(DependentExtensions.azureFunctions)) {
const choice = await vscode.window.showInformationMessage(
'Azure Functions extension is required for the current project. Do you want to install it from marketplace?',
'Yes', 'No');
'Azure Functions extension is required for the current project. Do you want to install it from marketplace?',
'Yes', 'No');
if (choice === 'Yes') {
vscode.commands.executeCommand(
VscodeCommands.VscodeOpen,
vscode.Uri.parse(
'vscode:extension/' + DependentExtensions.azureFunctions));
VscodeCommands.VscodeOpen,
vscode.Uri.parse(
'vscode:extension/' + DependentExtensions.azureFunctions));
}
return false;
}
@ -118,8 +118,8 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
async load(): Promise<boolean> {
const azureConfigFilePath = path.join(
this.azureFunctionsPath, '..', AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
this.azureFunctionsPath, '..', AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
if (!fs.existsSync(azureConfigFilePath)) {
return false;
@ -134,7 +134,7 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
}
const azureFunctionsConfig = azureConfigs.componentConfigs.find(
config => config.folder === this.functionFolder);
config => config.folder === this.functionFolder);
if (azureFunctionsConfig) {
this.componentId = azureFunctionsConfig.id;
this.dependencies = azureFunctionsConfig.dependencies;
@ -155,14 +155,14 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
if (!await FileUtility.directoryExists(scaffoldType, azureFunctionsPath)) {
throw new Error(
'Unable to find the Azure Functions folder inside the project.');
'Unable to find the Azure Functions folder inside the project.');
}
if (!this.functionLanguage) {
const picks: vscode.QuickPickItem[] = [
{label: AzureFunctionsLanguage.CSharpScript, description: ''},
{label: AzureFunctionsLanguage.JavaScript, description: ''},
{label: AzureFunctionsLanguage.CSharpLibrary, description: ''}
{ label: AzureFunctionsLanguage.CSharpScript, description: '' },
{ label: AzureFunctionsLanguage.JavaScript, description: '' },
{ label: AzureFunctionsLanguage.CSharpLibrary, description: '' }
];
const languageSelection = await vscode.window.showQuickPick(picks, {
@ -174,7 +174,7 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
if (!languageSelection) {
throw new CancelOperationError(
'Unable to get the language for Azure Functions. Creating project for Azure Functions cancelled.');
'Unable to get the language for Azure Functions. Creating project for Azure Functions cancelled.');
}
this.functionLanguage = languageSelection.label;
}
@ -183,32 +183,32 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
utils.getScriptTemplateNameFromLanguage(this.functionLanguage);
if (!templateName) {
throw new CancelOperationError(
'Unable to get the template for Azure Functions.Creating project for Azure Functions cancelled.');
'Unable to get the template for Azure Functions.Creating project for Azure Functions cancelled.');
}
if (this.functionLanguage === AzureFunctionsLanguage.CSharpLibrary) {
await vscode.commands.executeCommand(
AzureFunctionsCommands.CreateNewProject, azureFunctionsPath,
this.functionLanguage, '~2', false /* openFolder */, templateName,
'IoTHubTrigger1', {
connection: 'eventHubConnectionString',
path: '%eventHubConnectionPath%',
consumerGroup: '$Default',
namespace: 'IoTWorkbench'
});
AzureFunctionsCommands.CreateNewProject, azureFunctionsPath,
this.functionLanguage, '~2', false /* openFolder */, templateName,
'IoTHubTrigger1', {
connection: 'eventHubConnectionString',
path: '%eventHubConnectionPath%',
consumerGroup: '$Default',
namespace: 'IoTWorkbench'
});
} else {
await vscode.commands.executeCommand(
AzureFunctionsCommands.CreateNewProject, azureFunctionsPath,
this.functionLanguage, '~1', false /* openFolder */, templateName,
'IoTHubTrigger1', {
connection: 'eventHubConnectionString',
path: '%eventHubConnectionPath%',
consumerGroup: '$Default'
});
AzureFunctionsCommands.CreateNewProject, azureFunctionsPath,
this.functionLanguage, '~1', false /* openFolder */, templateName,
'IoTHubTrigger1', {
connection: 'eventHubConnectionString',
path: '%eventHubConnectionPath%',
consumerGroup: '$Default'
});
}
await this.updateConfigSettings(
scaffoldType, {values: {functionLanguage: this.functionLanguage}});
scaffoldType, { values: { functionLanguage: this.functionLanguage } });
}
async provision(): Promise<boolean> {
@ -224,8 +224,8 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
const functionAppId: string|undefined =
await vscode.commands.executeCommand<string>(
AzureFunctionsCommands.CreateFunctionApp, subscriptionId,
resourceGroup);
AzureFunctionsCommands.CreateFunctionApp, subscriptionId,
resourceGroup);
if (functionAppId) {
await ConfigHandler.update(ConfigKey.functionAppId, functionAppId);
const eventHubConnectionString =
@ -245,13 +245,13 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
}
const resourceGroupMatches =
functionAppId.match(/\/resourceGroups\/([^\/]*)/);
functionAppId.match(/\/resourceGroups\/([^/]*)/);
if (!resourceGroupMatches || resourceGroupMatches.length < 2) {
throw new Error('Cannot parse resource group from function app ID.');
}
const resourceGroup = resourceGroupMatches[1];
const siteNameMatches = functionAppId.match(/\/sites\/([^\/]*)/);
const siteNameMatches = functionAppId.match(/\/sites\/([^/]*)/);
if (!siteNameMatches || siteNameMatches.length < 2) {
throw new Error('Cannot parse function app name from function app ID.');
}
@ -282,12 +282,12 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
appSettings.properties['WEBSITE_RUN_FROM_PACKAGE'] = '0';
await client.webApps.updateApplicationSettings(
resourceGroup, siteName, appSettings);
resourceGroup, siteName, appSettings);
return true;
} else {
throw new Error(
'Creating Azure Functions application failed. Please check the error log in output window.');
'Creating Azure Functions application failed. Please check the error log in output window.');
}
}
@ -295,7 +295,7 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
let deployPending: NodeJS.Timer|null = null;
if (this.channel) {
utils.channelShowAndAppendLine(
this.channel, 'Deploying Azure Functions App...');
this.channel, 'Deploying Azure Functions App...');
deployPending = setInterval(() => {
this.channel.append('.');
}, 1000);
@ -307,18 +307,16 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
if (this.functionLanguage !==
AzureFunctionsLanguage.CSharpLibrary as string) {
await vscode.commands.executeCommand(
AzureFunctionsCommands.Deploy, azureFunctionsPath, functionAppId);
AzureFunctionsCommands.Deploy, azureFunctionsPath, functionAppId);
} else {
const subPath =
path.join(azureFunctionsPath, 'bin/Release/netcoreapp2.1/publish');
await vscode.commands.executeCommand(
AzureFunctionsCommands.Deploy, subPath, functionAppId);
AzureFunctionsCommands.Deploy, subPath, functionAppId);
}
console.log(azureFunctionsPath, functionAppId);
return true;
} catch (error) {
throw error;
} finally {
if (this.channel && deployPending) {
clearInterval(deployPending);
@ -330,10 +328,10 @@ export class AzureFunctions implements Component, Provisionable, Deployable {
async updateConfigSettings(type: ScaffoldType, componentInfo?: ComponentInfo):
Promise<void> {
const azureConfigFilePath = path.join(
this.azureFunctionsPath, '..', AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
this.azureFunctionsPath, '..', AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
let azureConfigs: AzureConfigs = {componentConfigs: []};
let azureConfigs: AzureConfigs = { componentConfigs: [] };
try {
const azureConfigContent =

Просмотреть файл

@ -1,21 +1,21 @@
import {ResourceManagementClient, ResourceModels, SubscriptionClient} from 'azure-arm-resource';
import { ResourceManagementClient, ResourceModels, SubscriptionClient, SubscriptionModels } from 'azure-arm-resource';
import * as fs from 'fs-plus';
import {HttpMethods, WebResource} from 'ms-rest';
import { HttpMethods, WebResource } from 'ms-rest';
import * as path from 'path';
import * as vscode from 'vscode';
import {channelPrintJsonObject, channelShowAndAppendLine} from '../utils';
import { channelPrintJsonObject, channelShowAndAppendLine } from '../utils';
import request = require('request-promise');
import rq = require('request');
import {AzureAccount, AzureResourceFilter, AzureSession} from '../azure-account.api';
import {ConfigHandler} from '../configHandler';
import { AzureAccount, AzureResourceFilter, AzureSession } from '../azure-account.api';
import { ConfigHandler } from '../configHandler';
import {getExtension} from './Apis';
import {ExtensionName} from './Interfaces/Api';
import {TelemetryWorker} from '../telemetry';
import {EventNames} from '../constants';
import { getExtension } from './Apis';
import { ExtensionName } from './Interfaces/Api';
import { TelemetryWorker } from '../telemetry';
import { EventNames } from '../constants';
export interface ARMParameters {
[key: string]: {value: string|number|boolean|null};
@ -35,7 +35,9 @@ export interface ARMParameterTemplate {
[key: string]: ARMParameterTemplateValue;
}
export interface ARMTemplate { parameters: ARMParameterTemplate; }
export interface ARMTemplate {
parameters: ARMParameterTemplate;
}
export class AzureUtility {
private static _context: vscode.ExtensionContext;
@ -46,8 +48,8 @@ export class AzureUtility {
getExtension(ExtensionName.AzureAccount);
static init(
context: vscode.ExtensionContext, channel?: vscode.OutputChannel,
subscriptionId?: string) {
context: vscode.ExtensionContext, channel?: vscode.OutputChannel,
subscriptionId?: string): void {
AzureUtility._context = context;
AzureUtility._channel = channel;
AzureUtility._subscriptionId = subscriptionId;
@ -88,7 +90,7 @@ export class AzureUtility {
const subscriptions: AzureResourceFilter[] =
AzureUtility._azureAccountExtension.filters;
const subscription = subscriptions.find(
sub => sub.subscription.subscriptionId === subscriptionId);
sub => sub.subscription.subscriptionId === subscriptionId);
if (subscription) {
return subscription.session;
}
@ -104,10 +106,10 @@ export class AzureUtility {
}
return AzureUtility._getSessionBySubscriptionId(
AzureUtility._subscriptionId);
AzureUtility._subscriptionId);
}
private static async _getResourceClient() {
private static async _getResourceClient(): Promise<ResourceManagementClient | undefined> {
AzureUtility._subscriptionId = await AzureUtility._getSubscription();
if (!AzureUtility._subscriptionId) {
@ -118,38 +120,37 @@ export class AzureUtility {
if (session) {
const credential = session.credentials;
const client = new ResourceManagementClient(
credential, AzureUtility._subscriptionId,
session.environment.resourceManagerEndpointUrl);
credential, AzureUtility._subscriptionId,
session.environment.resourceManagerEndpointUrl);
return client;
}
return undefined;
}
private static _getSubscriptionClientBySubscriptionId(substriptionId:
string) {
private static _getSubscriptionClientBySubscriptionId(substriptionId: string): ResourceManagementClient | undefined {
const session = AzureUtility._getSessionBySubscriptionId(substriptionId);
if (session) {
const credential = session.credentials;
const client = new ResourceManagementClient(
credential, substriptionId,
session.environment.resourceManagerEndpointUrl);
credential, substriptionId,
session.environment.resourceManagerEndpointUrl);
return client;
}
return undefined;
}
private static async _getSubscriptionClient() {
private static async _getSubscriptionClient(): Promise<SubscriptionClient | undefined> {
const session = await AzureUtility._getSession();
if (session) {
const credential = session.credentials;
const client = new SubscriptionClient(
credential, session.environment.resourceManagerEndpointUrl);
credential, session.environment.resourceManagerEndpointUrl);
return client;
}
return undefined;
}
private static async _getLocations() {
private static async _getLocations(): Promise<SubscriptionModels.LocationListResult | undefined> {
AzureUtility._subscriptionId = await AzureUtility._getSubscription();
if (!AzureUtility._subscriptionId) {
@ -166,7 +167,7 @@ export class AzureUtility {
return locations;
}
private static async _createResouceGroup() {
private static async _createResouceGroup(): Promise<string | undefined> {
const client = await AzureUtility._getResourceClient();
if (!client) {
return undefined;
@ -176,7 +177,7 @@ export class AzureUtility {
prompt: 'Input resouce group name',
ignoreFocusOut: true,
validateInput: async (name: string) => {
if (!/^[a-z0-9_\-\.]*[a-z0-9_\-]+$/.test(name)) {
if (!/^[a-z0-9_\-.]*[a-z0-9_-]+$/.test(name)) {
return 'Resource group names only allow alphanumeric characters, periods, underscores, hyphens and parenthesis and cannot end in a period.';
}
@ -206,33 +207,32 @@ export class AzureUtility {
}
const resourceGroupLocation = await vscode.window.showQuickPick(
locationList,
{placeHolder: 'Select Resource Group Location', ignoreFocusOut: true});
locationList,
{ placeHolder: 'Select Resource Group Location', ignoreFocusOut: true });
if (!resourceGroupLocation || !resourceGroupLocation.description) {
return undefined;
}
const resourceGroup = await client.resourceGroups.createOrUpdate(
resourceGroupName, {location: resourceGroupLocation.description});
resourceGroupName, { location: resourceGroupLocation.description });
return resourceGroup.name;
}
private static _commonParameterCheck(
_value: string, parameter: ARMParameterTemplateValue) {
private static _commonParameterCheck(_value: string, parameter: ARMParameterTemplateValue): string {
let value: string|number|boolean|null = null;
switch (parameter.type.toLocaleLowerCase()) {
case 'string':
value = _value;
break;
case 'int':
value = Number(_value);
break;
case 'bool':
value = _value.toLocaleLowerCase() === 'true';
break;
default:
break;
case 'string':
value = _value;
break;
case 'int':
value = Number(_value);
break;
case 'bool':
value = _value.toLocaleLowerCase() === 'true';
break;
default:
break;
}
if (value === null) {
@ -241,26 +241,26 @@ export class AzureUtility {
if (typeof value === 'string' && parameter.minLength !== undefined &&
parameter.minLength > value.length) {
return `The value does\'t meet requirement: minLength ${
parameter.minLength}.`;
return `The value does't meet requirement: minLength ${
parameter.minLength}.`;
}
if (typeof value === 'string' && parameter.maxLength !== undefined &&
parameter.maxLength < value.length) {
return `The value does\'t meet requirement: maxLength ${
parameter.maxLength}.`;
return `The value does't meet requirement: maxLength ${
parameter.maxLength}.`;
}
if (typeof value === 'number' && parameter.minValue !== undefined &&
parameter.minValue > value) {
return `The value does\'t meet requirement: minValue ${
parameter.minValue}.`;
return `The value does't meet requirement: minValue ${
parameter.minValue}.`;
}
if (typeof value === 'number' && parameter.maxValue !== undefined &&
parameter.maxValue < value) {
return `The value does\'t meet requirement: maxValue ${
parameter.maxValue}.`;
return `The value does't meet requirement: maxValue ${
parameter.maxValue}.`;
}
if (typeof value === 'number' && isNaN(value)) {
@ -270,18 +270,17 @@ export class AzureUtility {
return '';
}
private static _getKeyDisplayName(key: string) {
private static _getKeyDisplayName(key: string): string {
key = key.replace(/^\$*/, '');
const keyDisplayName = key.replace(/([A-Z][^A-Z])/g, ' $1')
.replace(/([a-z])([A-Z])/g, '$1 $2');
.replace(/([a-z])([A-Z])/g, '$1 $2');
return keyDisplayName.substr(0, 1).toUpperCase() + keyDisplayName.substr(1);
}
private static async _getARMParameters(
parameterTemplate: ARMParameterTemplate, parameters?: ARMParameters) {
private static async _getARMParameters(parameterTemplate: ARMParameterTemplate, parameters?: ARMParameters): Promise<ARMParameters|undefined> {
parameters = parameters || {} as ARMParameters;
for (const key of Object.keys(parameterTemplate)) {
if (parameters.hasOwnProperty(key)) {
if (Object.prototype.hasOwnProperty.call(parameters, key)) {
continue;
}
@ -294,7 +293,7 @@ export class AzureUtility {
const values: vscode.QuickPickItem[] = [];
for (const value of parameter.allowedValues) {
if (value !== null) {
values.push({label: value.toString(), description: ''});
values.push({ label: value.toString(), description: '' });
}
}
@ -315,7 +314,7 @@ export class AzureUtility {
} else {
const _key = key.substr(2);
const filePath = path.join(
vscode.workspace.workspaceFolders[0].uri.fsPath, '..', _key);
vscode.workspace.workspaceFolders[0].uri.fsPath, '..', _key);
AzureUtility._context.asAbsolutePath(_key);
if (fs.existsSync(filePath)) {
inputValue = fs.readFileSync(filePath, 'utf8');
@ -331,62 +330,63 @@ export class AzureUtility {
ConfigHandler.get<string>('iothubConnectionString');
switch (_key) {
case 'iotHubName':
if (!iothubConnectionString) {
inputValue = '';
} else {
const iotHubNameMatches =
case 'iotHubName':
if (!iothubConnectionString) {
inputValue = '';
} else {
const iotHubNameMatches =
iothubConnectionString.match(/HostName=(.*?)\./);
if (!iotHubNameMatches) {
inputValue = '';
} else {
inputValue = iotHubNameMatches[1];
}
}
break;
case 'iotHubKeyName':
if (!iothubConnectionString) {
if (!iotHubNameMatches) {
inputValue = '';
} else {
const iotHubKeyNameMatches = iothubConnectionString.match(
/SharedAccessKeyName=(.*?)(;|$)/);
if (!iotHubKeyNameMatches) {
inputValue = '';
} else {
inputValue = iotHubKeyNameMatches[1];
}
inputValue = iotHubNameMatches[1];
}
break;
case 'iotHubKey':
if (!iothubConnectionString) {
}
break;
case 'iotHubKeyName':
if (!iothubConnectionString) {
inputValue = '';
} else {
const iotHubKeyNameMatches = iothubConnectionString.match(
/SharedAccessKeyName=(.*?)(;|$)/);
if (!iotHubKeyNameMatches) {
inputValue = '';
} else {
const iotHubKeyMatches =
inputValue = iotHubKeyNameMatches[1];
}
}
break;
case 'iotHubKey':
if (!iothubConnectionString) {
inputValue = '';
} else {
const iotHubKeyMatches =
iothubConnectionString.match(/SharedAccessKey=(.*?)(;|$)/);
if (!iotHubKeyMatches) {
inputValue = '';
} else {
inputValue = iotHubKeyMatches[1];
}
}
break;
case 'subscription':
inputValue = AzureUtility._subscriptionId || '';
break;
default:
const _value = ConfigHandler.get<string>(_key);
if (!_value) {
if (!iotHubKeyMatches) {
inputValue = '';
} else {
inputValue = _value;
inputValue = iotHubKeyMatches[1];
}
}
break;
case 'subscription':
inputValue = AzureUtility._subscriptionId || '';
break;
default:{
const _value = ConfigHandler.get<string>(_key);
if (!_value) {
inputValue = '';
} else {
inputValue = _value;
}
}
}
} else {
const _value = await vscode.window.showInputBox({
prompt: `Input value for ${keyDisplayName}`,
ignoreFocusOut: true,
value: parameter.defaultValue ? parameter.defaultValue.toString() :
'',
'',
validateInput: async (value: string) => {
return AzureUtility._commonParameterCheck(value, parameter);
}
@ -400,33 +400,33 @@ export class AzureUtility {
}
switch (parameter.type.toLocaleLowerCase()) {
case 'string':
value = inputValue;
break;
case 'int':
value = Number(inputValue);
break;
case 'bool':
value = inputValue.toLocaleLowerCase() === 'true';
break;
default:
break;
case 'string':
value = inputValue;
break;
case 'int':
value = Number(inputValue);
break;
case 'bool':
value = inputValue.toLocaleLowerCase() === 'true';
break;
default:
break;
}
parameters[key] = {value};
parameters[key] = { value };
}
return parameters;
}
private static async _getSubscription() {
private static async _getSubscription(): Promise<string | undefined> {
if (AzureUtility._subscriptionId) {
return AzureUtility._subscriptionId;
}
const subscription = await vscode.window.showQuickPick(
AzureUtility._getSubscriptionList(),
{placeHolder: 'Select Subscription', ignoreFocusOut: true});
AzureUtility._getSubscriptionList(),
{ placeHolder: 'Select Subscription', ignoreFocusOut: true });
if (!subscription || !subscription.description) {
return undefined;
}
@ -437,14 +437,14 @@ export class AzureUtility {
try {
telemetryWorker.sendEvent(
EventNames.selectSubscription, telemetryContext);
EventNames.selectSubscription, telemetryContext);
} catch {
// If sending telemetry failed, skip the error to avoid blocking user.
}
return subscription.description;
}
private static async _getResourceGroupItems() {
private static async _getResourceGroupItems(): Promise<vscode.QuickPickItem[]> {
const client = await AzureUtility._getResourceClient();
if (!client) {
@ -452,7 +452,7 @@ export class AzureUtility {
}
const resourceGrouplist: vscode.QuickPickItem[] =
[{label: '$(plus) Create Resource Group', description: '', detail: ''}];
[{ label: '$(plus) Create Resource Group', description: '', detail: '' }];
const resourceGroups = await client.resourceGroups.list();
@ -467,7 +467,7 @@ export class AzureUtility {
return resourceGrouplist;
}
static async getResourceGroup() {
static async getResourceGroup(): Promise<string | undefined> {
const client = await AzureUtility._getResourceClient();
if (!client) {
@ -476,8 +476,8 @@ export class AzureUtility {
}
const choice = await vscode.window.showQuickPick(
AzureUtility._getResourceGroupItems(),
{placeHolder: 'Select Resource Group', ignoreFocusOut: true});
AzureUtility._getResourceGroupItems(),
{ placeHolder: 'Select Resource Group', ignoreFocusOut: true });
if (!choice) {
AzureUtility._resourceGroup = undefined;
@ -494,8 +494,7 @@ export class AzureUtility {
}
}
static async deployARMTemplate(
template: ARMTemplate, parameters?: ARMParameters) {
static async deployARMTemplate(template: ARMTemplate, parameters?: ARMParameters): Promise<ResourceModels.DeploymentExtended | undefined> {
const client = await AzureUtility._getResourceClient();
if (!client) {
return undefined;
@ -522,12 +521,12 @@ export class AzureUtility {
const mode = 'Incremental';
const deploymentParameters:
ResourceModels.Deployment = {properties: {parameters, template, mode}};
ResourceModels.Deployment = { properties: { parameters, template, mode } };
try {
const deployment = await client.deployments.createOrUpdate(
AzureUtility._resourceGroup,
`IoTWorkbecnhDeploy${new Date().getTime()}`, deploymentParameters);
AzureUtility._resourceGroup,
`IoTWorkbecnhDeploy${new Date().getTime()}`, deploymentParameters);
if (AzureUtility._channel && deployPending) {
clearInterval(deployPending);
@ -545,21 +544,21 @@ export class AzureUtility {
}
}
static get subscriptionId() {
static get subscriptionId(): string|undefined {
return AzureUtility._subscriptionId;
}
static get resourceGroup() {
static get resourceGroup(): string|undefined {
return AzureUtility._resourceGroup;
}
static getClient() {
static getClient(): ResourceManagementClient |undefined {
if (!AzureUtility._subscriptionId) {
return undefined;
}
const client = AzureUtility._getSubscriptionClientBySubscriptionId(
AzureUtility._subscriptionId);
AzureUtility._subscriptionId);
if (!client) {
return undefined;
}
@ -567,9 +566,8 @@ export class AzureUtility {
return client;
}
static async request(
// tslint:disable-next-line: no-any
method: HttpMethods, resource: string, body: any = null) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static async request(method: HttpMethods, resource: string, body: any = null): Promise<unknown> {
const session = await AzureUtility._getSession();
if (!session) {
return undefined;
@ -589,7 +587,7 @@ export class AzureUtility {
httpRequestOption.simple = false;
httpRequestOption.json = true;
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
credential.signRequest(httpRequest, async err => {
if (!err) {
const res = await request(httpRequestOption);
@ -601,12 +599,12 @@ export class AzureUtility {
});
}
// tslint:disable-next-line: no-any
static async postRequest(resource: string, body: any = null) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static async postRequest(resource: string, body: any = null): Promise<unknown> {
return AzureUtility.request('POST', resource, body);
}
static async getRequest(resource: string) {
static async getRequest(resource: string): Promise<unknown> {
return AzureUtility.request('GET', resource);
}
}

Просмотреть файл

@ -1,21 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as path from 'path';
import * as vscode from 'vscode';
import {CancelOperationError} from '../CancelOperationError';
import {FileNames, OperationType, PlatformType, ScaffoldType, TemplateTag} from '../constants';
import {DigitalTwinConstants} from '../DigitalTwin/DigitalTwinConstants';
import {FileUtility} from '../FileUtility';
import {TelemetryContext} from '../telemetry';
import { CancelOperationError } from '../CancelOperationError';
import { FileNames, OperationType, PlatformType, ScaffoldType, TemplateTag } from '../constants';
import { DigitalTwinConstants } from '../DigitalTwin/DigitalTwinConstants';
import { FileUtility } from '../FileUtility';
import { TelemetryContext } from '../telemetry';
import * as utils from '../utils';
import {ComponentType} from './Interfaces/Component';
import {Device, DeviceType} from './Interfaces/Device';
import {ProjectTemplate, TemplateFileInfo, TemplatesType} from './Interfaces/ProjectTemplate';
import {RemoteExtension} from './RemoteExtension';
import { ComponentType } from './Interfaces/Component';
import { Device, DeviceType } from './Interfaces/Device';
import { ProjectTemplate, TemplateFileInfo, TemplatesType } from './Interfaces/ProjectTemplate';
import { RemoteExtension } from './RemoteExtension';
const constants = {
configFile: 'config.json',
@ -24,7 +24,7 @@ const constants = {
export abstract class ContainerDeviceBase implements Device {
protected componentId: string;
get id() {
get id(): string {
return this.componentId;
}
protected deviceType: DeviceType;
@ -39,9 +39,9 @@ export abstract class ContainerDeviceBase implements Device {
name = 'container base';
constructor(
context: vscode.ExtensionContext, projectPath: string,
channel: vscode.OutputChannel, telemetryContext: TelemetryContext,
deviceType: DeviceType,
context: vscode.ExtensionContext, projectPath: string,
channel: vscode.OutputChannel, telemetryContext: TelemetryContext,
deviceType: DeviceType,
protected templateFilesInfo: TemplateFileInfo[] = []) {
this.deviceType = deviceType;
this.componentType = ComponentType.Device;
@ -79,20 +79,20 @@ export abstract class ContainerDeviceBase implements Device {
// ScaffoldType is local when creating a project
const createTimeScaffoldType = ScaffoldType.Local;
if (!await FileUtility.directoryExists(
createTimeScaffoldType, this.projectFolder)) {
createTimeScaffoldType, this.projectFolder)) {
throw new Error('Unable to find the project folder.');
}
await this.generateTemplateFiles(
createTimeScaffoldType, this.projectFolder, this.templateFilesInfo);
createTimeScaffoldType, this.projectFolder, this.templateFilesInfo);
await this.configDeviceEnvironment(
this.projectFolder, createTimeScaffoldType);
this.projectFolder, createTimeScaffoldType);
}
async generateTemplateFiles(
type: ScaffoldType, projectPath: string,
templateFilesInfo: TemplateFileInfo[]): Promise<boolean> {
type: ScaffoldType, projectPath: string,
templateFilesInfo: TemplateFileInfo[]): Promise<boolean> {
if (!templateFilesInfo) {
throw new Error('No template file provided.');
}
@ -122,14 +122,14 @@ export abstract class ContainerDeviceBase implements Device {
const isRemote = RemoteExtension.isRemote(this.extensionContext);
if (!isRemote) {
await utils.askAndOpenInRemote(
OperationType.Compile, this.telemetryContext);
OperationType.Compile, this.telemetryContext);
return false;
}
await utils.fetchAndExecuteTask(
this.extensionContext, this.channel, this.telemetryContext,
this.projectFolder, OperationType.Compile, PlatformType.EmbeddedLinux,
constants.compileTaskName);
this.extensionContext, this.channel, this.telemetryContext,
this.projectFolder, OperationType.Compile, PlatformType.EmbeddedLinux,
constants.compileTaskName);
return true;
}
@ -138,19 +138,19 @@ export abstract class ContainerDeviceBase implements Device {
abstract async configDeviceSettings(): Promise<boolean>;
async configDeviceEnvironment(
projectPath: string, scaffoldType: ScaffoldType): Promise<void> {
projectPath: string, scaffoldType: ScaffoldType): Promise<void> {
if (!projectPath) {
throw new Error(
'Unable to find the project path, please open the folder and initialize project again.');
'Unable to find the project path, please open the folder and initialize project again.');
}
// Get template list json object
const templateJsonFilePath = this.extensionContext.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.templateFileName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.templateFileName));
const templateJsonFileString =
await FileUtility.readFile(
scaffoldType, templateJsonFilePath, 'utf8') as string;
scaffoldType, templateJsonFilePath, 'utf8') as string;
const templateJson = JSON.parse(templateJsonFileString);
if (!templateJson) {
throw new Error('Fail to load template list.');
@ -164,11 +164,11 @@ export abstract class ContainerDeviceBase implements Device {
const templateName = containerSelection.label;
if (!templateName) {
throw new Error(
`Internal Error: Cannot get template name from template property.`);
`Internal Error: Cannot get template name from template property.`);
}
const templateFilesInfo = await utils.getEnvTemplateFilesAndAskOverwrite(
this.extensionContext, this.projectFolder, scaffoldType, templateName);
this.extensionContext, this.projectFolder, scaffoldType, templateName);
if (templateFilesInfo.length === 0) {
throw new Error(`Internal Error: template files info is empty.`);
}
@ -197,13 +197,13 @@ export abstract class ContainerDeviceBase implements Device {
const containerTemplates =
templateListJson.templates.filter((template: ProjectTemplate) => {
return (
template.tag === TemplateTag.DevelopmentEnvironment &&
template.tag === TemplateTag.DevelopmentEnvironment &&
template.platform === PlatformType.EmbeddedLinux);
});
const containerList: vscode.QuickPickItem[] = [];
containerTemplates.forEach((container: ProjectTemplate) => {
containerList.push({label: container.name, detail: container.detail});
containerList.push({ label: container.name, detail: container.detail });
});
const containerSelection =

Просмотреть файл

@ -1,19 +1,19 @@
import * as crypto from 'crypto';
import * as fs from 'fs-plus';
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as path from 'path';
import * as vscode from 'vscode';
import request = require('request-promise');
import rq = require('request');
import {AzureComponentsStorage, FileNames, ScaffoldType} from '../constants';
import { AzureComponentsStorage, FileNames, ScaffoldType } from '../constants';
import {AzureComponentConfig, AzureConfigFileHandler, AzureConfigs, ComponentInfo, Dependency, DependencyConfig, DependencyType} from './AzureComponentConfig';
import {ARMTemplate, AzureUtility} from './AzureUtility';
import {Component, ComponentType} from './Interfaces/Component';
import {Provisionable} from './Interfaces/Provisionable';
import {channelShowAndAppendLine, channelPrintJsonObject} from '../utils';
import { AzureComponentConfig, AzureConfigFileHandler, AzureConfigs, ComponentInfo, Dependency, DependencyConfig, DependencyType } from './AzureComponentConfig';
import { ARMTemplate, AzureUtility } from './AzureUtility';
import { Component, ComponentType } from './Interfaces/Component';
import { Provisionable } from './Interfaces/Provisionable';
import { channelShowAndAppendLine, channelPrintJsonObject } from '../utils';
export class CosmosDB implements Component, Provisionable {
dependencies: DependencyConfig[] = [];
@ -24,14 +24,14 @@ export class CosmosDB implements Component, Provisionable {
private azureConfigHandler: AzureConfigFileHandler;
private extensionContext: vscode.ExtensionContext;
private catchedCosmosDbList: Array<{name: string}> = [];
get id() {
get id(): string {
return this.componentId;
}
constructor(
context: vscode.ExtensionContext, projectRoot: string,
channel: vscode.OutputChannel,
dependencyComponents: Dependency[]|null = null) {
context: vscode.ExtensionContext, projectRoot: string,
channel: vscode.OutputChannel,
dependencyComponents: Dependency[]|null = null) {
this.componentType = ComponentType.CosmosDB;
this.channel = channel;
this.componentId = Guid.create().toString();
@ -40,8 +40,8 @@ export class CosmosDB implements Component, Provisionable {
this.extensionContext = context;
if (dependencyComponents && dependencyComponents.length > 0) {
dependencyComponents.forEach(
dependency => this.dependencies.push(
{id: dependency.component.id, type: dependency.type}));
dependency => this.dependencies.push(
{ id: dependency.component.id, type: dependency.type }));
}
}
@ -57,8 +57,8 @@ export class CosmosDB implements Component, Provisionable {
async load(): Promise<boolean> {
const azureConfigFilePath = path.join(
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
if (!fs.existsSync(azureConfigFilePath)) {
return false;
@ -69,7 +69,7 @@ export class CosmosDB implements Component, Provisionable {
try {
azureConfigs = JSON.parse(fs.readFileSync(azureConfigFilePath, 'utf8'));
const cosmosDBConfig = azureConfigs.componentConfigs.find(
config => config.type === this.componentType);
config => config.type === this.componentType);
if (cosmosDBConfig) {
this.componentId = cosmosDBConfig.id;
this.dependencies = cosmosDBConfig.dependencies;
@ -94,7 +94,7 @@ export class CosmosDB implements Component, Provisionable {
return;
}
await this.azureConfigHandler.updateComponent(
type, cosmosDBComponentIndex, componentInfo);
type, cosmosDBComponentIndex, componentInfo);
} else {
const newCosmosDBConfig: AzureComponentConfig = {
id: this.id,
@ -110,7 +110,7 @@ export class CosmosDB implements Component, Provisionable {
async provision(): Promise<boolean> {
const cosmosDbList = this.getCosmosDbInResourceGroup();
const cosmosDbNameChoose = await vscode.window.showQuickPick(
cosmosDbList, {placeHolder: 'Select Cosmos DB', ignoreFocusOut: true});
cosmosDbList, { placeHolder: 'Select Cosmos DB', ignoreFocusOut: true });
if (!cosmosDbNameChoose) {
return false;
}
@ -124,7 +124,7 @@ export class CosmosDB implements Component, Provisionable {
channelShowAndAppendLine(this.channel, 'Creating Cosmos DB...');
}
const cosmosDBArmTemplatePath = this.extensionContext.asAbsolutePath(
path.join(FileNames.resourcesFolderName, 'arm', 'cosmosdb.json'));
path.join(FileNames.resourcesFolderName, 'arm', 'cosmosdb.json'));
const cosmosDBArmTemplate =
JSON.parse(fs.readFileSync(cosmosDBArmTemplatePath, 'utf8')) as
ARMTemplate;
@ -141,7 +141,7 @@ export class CosmosDB implements Component, Provisionable {
for (const dependency of this.dependencies) {
const componentConfig = await this.azureConfigHandler.getComponentById(
scaffoldType, dependency.id);
scaffoldType, dependency.id);
if (!componentConfig) {
throw new Error(`Cannot find component with id ${dependency.id}.`);
}
@ -170,7 +170,7 @@ export class CosmosDB implements Component, Provisionable {
const databaseList = this.getDatabases(cosmosDbName, cosmosDbKey);
const databaseChoose = await vscode.window.showQuickPick(
databaseList, {placeHolder: 'Select Database', ignoreFocusOut: true});
databaseList, { placeHolder: 'Select Database', ignoreFocusOut: true });
if (!databaseChoose) {
return false;
}
@ -186,7 +186,7 @@ export class CosmosDB implements Component, Provisionable {
if (!value) {
return 'Please fill this field.';
}
if (!/^[^\\\/#\?]+/.test(value)) {
if (!/^[^\\/#?]+/.test(value)) {
return 'May not end with space nor contain "\\", "/", "#", "?".';
}
return;
@ -209,8 +209,8 @@ export class CosmosDB implements Component, Provisionable {
const collectionList =
this.getCollections(cosmosDbName, cosmosDbKey, database);
const collectionChoose = await vscode.window.showQuickPick(
collectionList,
{placeHolder: 'Select Collection', ignoreFocusOut: true});
collectionList,
{ placeHolder: 'Select Collection', ignoreFocusOut: true });
if (!collectionChoose) {
return false;
}
@ -226,7 +226,7 @@ export class CosmosDB implements Component, Provisionable {
if (!value) {
return 'Please fill this field.';
}
if (!/^[^\\\/#\?]+/.test(value)) {
if (!/^[^\\/#?]+/.test(value)) {
return 'May not end with space nor contain "\\", "/", "#", "?".';
}
return;
@ -238,7 +238,7 @@ export class CosmosDB implements Component, Provisionable {
}
collection = collection.trim();
const cosmosDBApiRes = await this.ensureCollection(
cosmosDbName, cosmosDbKey, database, collection);
cosmosDbName, cosmosDbKey, database, collection);
if (!cosmosDBApiRes) {
throw new Error('Error occurred when create collection.');
}
@ -263,9 +263,7 @@ export class CosmosDB implements Component, Provisionable {
return true;
}
private _getCosmosDBAuthorizationToken(
key: string, verb: string, date: string, resourceType: string,
resourceId: string) {
private _getCosmosDBAuthorizationToken(key: string, verb: string, date: string, resourceType: string, resourceId: string): string {
const _key = Buffer.from(key, 'base64');
const stringToSign =
(`${verb}\n${resourceType}\n${resourceId}\n${date}\n\n`).toLowerCase();
@ -278,14 +276,14 @@ export class CosmosDB implements Component, Provisionable {
const tokenVersion = '1.0';
return encodeURIComponent(
`type=${masterToken}&ver=${tokenVersion}&sig=${signature}`);
`type=${masterToken}&ver=${tokenVersion}&sig=${signature}`);
}
private _getRestHeaders(
key: string, verb: string, resourceType: string, resourceId: string) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private _getRestHeaders(key: string, verb: string, resourceType: string, resourceId: string): any {
const date = new Date().toUTCString();
const authorization = this._getCosmosDBAuthorizationToken(
key, verb, date, resourceType, resourceId);
key, verb, date, resourceType, resourceId);
const headers = {
'Authorization': authorization,
'Content-Type': 'application/json',
@ -296,10 +294,7 @@ export class CosmosDB implements Component, Provisionable {
return headers;
}
private async _apiRequest(
account: string, key: string, verb: string, path: string,
resourceType: string, resourceId: string,
body: {id: string}|null = null) {
private async _apiRequest(account: string, key: string, verb: string, path: string, resourceType: string, resourceId: string, body: {id: string}|null = null): Promise<rq.Response> {
const apiUrl = `https://${account}.documents.azure.com/${path}`;
const headers = this._getRestHeaders(key, verb, resourceType, resourceId);
const apiRes: rq.Response = await request({
@ -319,28 +314,28 @@ export class CosmosDB implements Component, Provisionable {
return apiRes;
}
async getDatabases(account: string, key: string) {
async getDatabases(account: string, key: string): Promise<vscode.QuickPickItem[]> {
const getDatabasesRes =
await this._apiRequest(account, key, 'GET', 'dbs', 'dbs', '');
const listRes = getDatabasesRes.body as {Databases: Array<{id: string}>};
const databaseList: vscode.QuickPickItem[] =
[{label: '$(plus) Create New Database', description: ''}];
[{ label: '$(plus) Create New Database', description: '' }];
for (const item of listRes.Databases) {
databaseList.push({label: item.id, description: account});
databaseList.push({ label: item.id, description: account });
}
return databaseList;
}
async ensureDatabase(account: string, key: string, database: string) {
async ensureDatabase(account: string, key: string, database: string): Promise<boolean> {
const getDatabaseRes = await this._apiRequest(
account, key, 'GET', `dbs/${database}`, 'dbs', `dbs/${database}`);
account, key, 'GET', `dbs/${database}`, 'dbs', `dbs/${database}`);
if (getDatabaseRes.statusCode === 200) {
return true;
}
const createDatabaseRes = await this._apiRequest(
account, key, 'POST', 'dbs', 'dbs', '', {id: database});
account, key, 'POST', 'dbs', 'dbs', '', { id: database });
if (createDatabaseRes.statusCode === 201) {
return true;
}
@ -348,34 +343,33 @@ export class CosmosDB implements Component, Provisionable {
return false;
}
async getCollections(account: string, key: string, database: string) {
async getCollections(account: string, key: string, database: string): Promise<vscode.QuickPickItem[]> {
const getDCollectionsRes = await this._apiRequest(
account, key, 'GET', `dbs/${database}/colls`, 'colls',
`dbs/${database}`);
account, key, 'GET', `dbs/${database}/colls`, 'colls',
`dbs/${database}`);
const listRes =
getDCollectionsRes.body as {DocumentCollections: Array<{id: string}>};
const collectionList: vscode.QuickPickItem[] =
[{label: '$(plus) Create New Collection', description: ''}];
[{ label: '$(plus) Create New Collection', description: '' }];
for (const item of listRes.DocumentCollections) {
collectionList.push(
{label: item.id, description: `${account}/${database}`});
{ label: item.id, description: `${account}/${database}` });
}
return collectionList;
}
async ensureCollection(
account: string, key: string, database: string, collection: string) {
async ensureCollection(account: string, key: string, database: string, collection: string): Promise<boolean> {
const getCollectionRes = await this._apiRequest(
account, key, 'GET', `dbs/${database}/colls/${collection}`, 'colls',
`dbs/${database}/colls/${collection}`);
account, key, 'GET', `dbs/${database}/colls/${collection}`, 'colls',
`dbs/${database}/colls/${collection}`);
if (getCollectionRes.statusCode === 200) {
return true;
}
const creatCollectionRes = await this._apiRequest(
account, key, 'POST', `dbs/${database}/colls`, 'colls',
`dbs/${database}`, {id: collection});
account, key, 'POST', `dbs/${database}/colls`, 'colls',
`dbs/${database}`, { id: collection });
if (creatCollectionRes.statusCode === 201) {
return true;
}
@ -383,32 +377,32 @@ export class CosmosDB implements Component, Provisionable {
return false;
}
private getCosmosDbByNameFromCache(name: string) {
private getCosmosDbByNameFromCache(name: string): {name: string}|undefined {
return this.catchedCosmosDbList.find(item => item.name === name);
}
private async getCosmosDbInResourceGroup() {
private async getCosmosDbInResourceGroup(): Promise<vscode.QuickPickItem[]> {
const resource = `/subscriptions/${
AzureUtility.subscriptionId}/resourceGroups/${
AzureUtility
.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts?api-version=2015-04-08`;
AzureUtility.subscriptionId}/resourceGroups/${
AzureUtility
.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts?api-version=2015-04-08`;
const cosmosDbListRes = await AzureUtility.getRequest(resource) as
{value: Array<{name: string, location: string}>};
{value: Array<{name: string; location: string}>};
const cosmosDbList: vscode.QuickPickItem[] =
[{label: '$(plus) Create New Cosmos DB', description: ''}];
[{ label: '$(plus) Create New Cosmos DB', description: '' }];
for (const item of cosmosDbListRes.value) {
cosmosDbList.push({label: item.name, description: item.location});
cosmosDbList.push({ label: item.name, description: item.location });
}
this.catchedCosmosDbList = cosmosDbListRes.value;
return cosmosDbList;
}
private async getCosmosDbKey(name: string) {
private async getCosmosDbKey(name: string): Promise<string> {
const resource = `/subscriptions/${
AzureUtility.subscriptionId}/resourceGroups/${
AzureUtility
.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${
name}/listKeys?api-version=2015-04-08`;
AzureUtility.subscriptionId}/resourceGroups/${
AzureUtility
.resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${
name}/listKeys?api-version=2015-04-08`;
const cosmosDbKeyListRes =
await AzureUtility.postRequest(resource) as {primaryMasterKey: string};
return cosmosDbKeyListRes.primaryMasterKey;

Просмотреть файл

@ -3,40 +3,41 @@
import * as clipboardy from 'clipboardy';
import * as fs from 'fs-plus';
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import {BoardProvider} from '../boardProvider';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, OSPlatform} from '../constants';
import {TelemetryContext} from '../telemetry';
import { BoardProvider } from '../boardProvider';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, OSPlatform } from '../constants';
import { TelemetryContext } from '../telemetry';
import {ArduinoDeviceBase} from './ArduinoDeviceBase';
import {DeviceType} from './Interfaces/Device';
import {TemplateFileInfo} from './Interfaces/ProjectTemplate';
import { ArduinoDeviceBase } from './ArduinoDeviceBase';
import { DeviceType } from './Interfaces/Device';
import { TemplateFileInfo } from './Interfaces/ProjectTemplate';
import { Board } from './Interfaces/Board';
export class Esp32Device extends ArduinoDeviceBase {
private templateFiles: TemplateFileInfo[] = [];
private static _boardId = 'esp32';
private componentId: string;
get id() {
get id(): string {
return this.componentId;
}
static get boardId() {
static get boardId(): string {
return Esp32Device._boardId;
}
get board() {
get board(): Board | undefined {
const boardProvider = new BoardProvider(this.boardFolderPath);
const esp32 = boardProvider.find({id: Esp32Device._boardId});
const esp32 = boardProvider.find({ id: Esp32Device._boardId });
return esp32;
}
get version() {
get version(): string {
const platform = os.platform();
let packageRootPath = '';
let version = '0.0.1';
@ -45,7 +46,7 @@ export class Esp32Device extends ArduinoDeviceBase {
const homeDir = os.homedir();
const localAppData: string = path.join(homeDir, 'AppData', 'Local');
packageRootPath = path.join(
localAppData, 'Arduino15', 'packages', 'esp32', 'hardware', 'esp32');
localAppData, 'Arduino15', 'packages', 'esp32', 'hardware', 'esp32');
} else {
packageRootPath = '~/Library/Arduino15/packages/esp32/hardware/esp32';
}
@ -63,11 +64,11 @@ export class Esp32Device extends ArduinoDeviceBase {
name = 'Esp32Arduino';
constructor(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, devicePath: string,
templateFiles?: TemplateFileInfo[]) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, devicePath: string,
templateFiles?: TemplateFileInfo[]) {
super(
context, devicePath, channel, telemetryContext, DeviceType.IoT_Button);
context, devicePath, channel, telemetryContext, DeviceType.IoTButton);
this.channel = channel;
this.componentId = Guid.create().toString();
if (templateFiles) {
@ -112,7 +113,7 @@ export class Esp32Device extends ArduinoDeviceBase {
if (configSelection.detail === 'Config CRC') {
const retValue: boolean =
await this.generateCrc(this.extensionContext, this.channel);
await this.generateCrc(this.channel);
return retValue;
} else if (configSelection.detail === 'Copy') {
const deviceConnectionString =
@ -120,7 +121,7 @@ export class Esp32Device extends ArduinoDeviceBase {
if (!deviceConnectionString) {
throw new Error(
'Unable to get the device connection string, please invoke the command of Azure Provision first.');
'Unable to get the device connection string, please invoke the command of Azure Provision first.');
}
clipboardy.writeSync(deviceConnectionString);
return true;

Просмотреть файл

@ -7,7 +7,7 @@ export interface CommandItem extends vscode.QuickPickItem {
/**
* Click action of the menu item
*/
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
click?: (...args: any[]) => any;
/**
* Submenu of the menu item

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
export interface Compilable { compile(): Promise<boolean>; }
export interface Compilable { compile(): Promise<boolean> }

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
export interface Deployable { deploy(): Promise<boolean>; }
export interface Deployable { deploy(): Promise<boolean> }

Просмотреть файл

@ -1,17 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {ScaffoldType} from '../../constants';
import { ScaffoldType } from '../../constants';
import {Compilable} from './Compilable';
import {Component} from './Component';
import {Uploadable} from './Uploadable';
import { Compilable } from './Compilable';
import { Component } from './Component';
import { Uploadable } from './Uploadable';
export enum DeviceType {
MXChip_AZ3166 = 1,
IoT_Button = 2,
MXChipAZ3166 = 1,
IoTButton = 2,
Esp32 = 3,
Raspberry_Pi = 4
RaspberryPi = 4
}
export interface Device extends Component, Compilable, Uploadable {

Просмотреть файл

@ -16,7 +16,7 @@ export interface TemplateFileInfo {
overwrite?: boolean;
}
export interface TemplatesType { templates: ProjectTemplate[]; }
export interface TemplatesType { templates: ProjectTemplate[] }
export interface ProjectTemplate {
platform: string;
name: string;

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {ScaffoldType} from '../../constants';
import {ComponentInfo, DependencyConfig} from '../AzureComponentConfig';
import { ScaffoldType } from '../../constants';
import { ComponentInfo, DependencyConfig } from '../AzureComponentConfig';
export interface Provisionable {
dependencies: DependencyConfig[];

Просмотреть файл

@ -1,6 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {QuickPickItem} from 'vscode';
import { QuickPickItem } from 'vscode';
export interface PickWithData<T> extends QuickPickItem { data: T; }
export interface PickWithData<T> extends QuickPickItem { data: T }

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
export interface Uploadable { upload(): Promise<boolean>; }
export interface Uploadable { upload(): Promise<boolean> }

Просмотреть файл

@ -2,19 +2,19 @@
// Licensed under the MIT License.
import * as fs from 'fs-plus';
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as path from 'path';
import * as request from 'request-promise';
import * as vscode from 'vscode';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, ScaffoldType} from '../constants';
import {FileUtility} from '../FileUtility';
import {generateTemplateFile} from '../utils';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, ScaffoldType } from '../constants';
import { FileUtility } from '../FileUtility';
import { generateTemplateFile } from '../utils';
import {ComponentType} from './Interfaces/Component';
import {Device, DeviceType} from './Interfaces/Device';
import {TemplateFileInfo} from './Interfaces/ProjectTemplate';
import { ComponentType } from './Interfaces/Component';
import { Device, DeviceType } from './Interfaces/Device';
import { TemplateFileInfo } from './Interfaces/ProjectTemplate';
const constants = {
timeout: 10000,
@ -27,26 +27,22 @@ export class IoTButtonDevice implements Device {
private deviceType: DeviceType;
private componentType: ComponentType;
private deviceFolder: string;
private extensionContext: vscode.ExtensionContext;
private componentId: string;
get id() {
get id(): string {
return this.componentId;
}
private static _boardId = 'iotbutton';
static get boardId() {
static get boardId(): string {
return IoTButtonDevice._boardId;
}
constructor(
context: vscode.ExtensionContext, devicePath: string,
private templateFilesInfo: TemplateFileInfo[] = []) {
this.deviceType = DeviceType.IoT_Button;
constructor(devicePath: string, private templateFilesInfo: TemplateFileInfo[] = []) {
this.deviceType = DeviceType.IoTButton;
this.componentType = ComponentType.Device;
this.deviceFolder = devicePath;
this.extensionContext = context;
this.componentId = Guid.create().toString();
}
@ -77,25 +73,25 @@ export class IoTButtonDevice implements Device {
async create(): Promise<void> {
const createTimeScaffoldType = ScaffoldType.Local;
if (!await FileUtility.directoryExists(
createTimeScaffoldType, this.deviceFolder)) {
createTimeScaffoldType, this.deviceFolder)) {
throw new Error(`Internal error: Couldn't find the template folder.`);
}
for (const fileInfo of this.templateFilesInfo) {
await generateTemplateFile(
this.deviceFolder, createTimeScaffoldType, fileInfo);
this.deviceFolder, createTimeScaffoldType, fileInfo);
}
}
async compile(): Promise<boolean> {
vscode.window.showInformationMessage(
'Congratulations! There is no device code to compile in this project.');
'Congratulations! There is no device code to compile in this project.');
return true;
}
async upload(): Promise<boolean> {
vscode.window.showInformationMessage(
'Congratulations! There is no device code to upload in this project.');
'Congratulations! There is no device code to upload in this project.');
return true;
}
@ -156,7 +152,7 @@ export class IoTButtonDevice implements Device {
const res = await this.configHub();
if (res) {
vscode.window.showInformationMessage(
'Config Azure IoT Hub successfully.');
'Config Azure IoT Hub successfully.');
}
} catch (error) {
vscode.window.showWarningMessage('Config IoT Hub failed.');
@ -166,7 +162,7 @@ export class IoTButtonDevice implements Device {
const res = await this.configNtp();
if (res) {
vscode.window.showInformationMessage(
'Config time server successfully.');
'Config time server successfully.');
}
} catch (error) {
vscode.window.showWarningMessage('Config IoT Hub failed.');
@ -176,14 +172,14 @@ export class IoTButtonDevice implements Device {
const res = await this.configUserData();
if (res) {
vscode.window.showInformationMessage(
'Config user data successfully.');
'Config user data successfully.');
}
} catch (error) {
vscode.window.showWarningMessage('Config user data failed.');
}
} else {
try {
const res = await this.configSaveAndShutdown();
await this.configSaveAndShutdown();
} catch (error) {
// Ignore.
// Because the button has been shutdown, we won't get any response for
@ -197,9 +193,10 @@ export class IoTButtonDevice implements Device {
return await this.configDeviceSettings();
}
async setConfig(uri: string, data: {}) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async setConfig(uri: string, data: {}): Promise<any> {
const option =
{uri, method: 'POST', timeout: constants.timeout, form: data};
{ uri, method: 'POST', timeout: constants.timeout, form: data };
const res = await request(option);
@ -210,7 +207,8 @@ export class IoTButtonDevice implements Device {
return res;
}
async configWifi() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async configWifi(): Promise<any> {
const ssid = await vscode.window.showInputBox({
prompt: `WiFi SSID`,
ignoreFocusOut: true,
@ -228,13 +226,13 @@ export class IoTButtonDevice implements Device {
}
const password = await vscode.window.showInputBox(
{prompt: `WiFi Password`, password: true, ignoreFocusOut: true});
{ prompt: `WiFi Password`, password: true, ignoreFocusOut: true });
if (!password) {
return false;
}
const data = {ssid, password};
const data = { ssid, password };
const uri = constants.accessEndpoint;
const res = await this.setConfig(uri, data);
@ -242,7 +240,7 @@ export class IoTButtonDevice implements Device {
return res;
}
async configHub() {
async configHub(): Promise<boolean> {
let deviceConnectionString =
ConfigHandler.get<string>(ConfigKey.iotHubDeviceConnectionString);
@ -318,7 +316,7 @@ export class IoTButtonDevice implements Device {
(deviceConnectionString.indexOf('DeviceId') === -1) ||
(deviceConnectionString.indexOf('SharedAccessKey') === -1)) {
throw new Error(
'The format of the IoT Hub Device connection string is invalid. Please provide a valid Device connection string.');
'The format of the IoT Hub Device connection string is invalid. Please provide a valid Device connection string.');
}
}
@ -343,7 +341,7 @@ export class IoTButtonDevice implements Device {
const iotdevicename = iotdevicenameMatches[1];
const iotdevicesecret = iotdevicesecretMatches[1];
const data = {iothub, iotdevicename, iotdevicesecret};
const data = { iothub, iotdevicename, iotdevicesecret };
const uri = constants.accessEndpoint;
const res = await this.setConfig(uri, data);
@ -351,7 +349,8 @@ export class IoTButtonDevice implements Device {
return res;
}
async configUserData() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async configUserData(): Promise<any> {
const deviceFolderPath = this.deviceFolder;
if (!fs.existsSync(deviceFolderPath)) {
@ -373,7 +372,7 @@ export class IoTButtonDevice implements Device {
userjson = {};
}
const data = {userjson: JSON.stringify(userjson)};
const data = { userjson: JSON.stringify(userjson) };
const uri = constants.accessEndpoint;
const res = await this.setConfig(uri, data);
@ -381,7 +380,8 @@ export class IoTButtonDevice implements Device {
return res;
}
async configNtp() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async configNtp(): Promise<any> {
const timeserver = await vscode.window.showInputBox({
value: 'pool.ntp.org',
prompt: `Time Server`,
@ -399,7 +399,7 @@ export class IoTButtonDevice implements Device {
return false;
}
const data = {timeserver};
const data = { timeserver };
const uri = constants.accessEndpoint;
const res = await this.setConfig(uri, data);
@ -407,8 +407,9 @@ export class IoTButtonDevice implements Device {
return res;
}
async configSaveAndShutdown() {
const data = {action: 'shutdown'};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async configSaveAndShutdown(): Promise<any> {
const data = { action: 'shutdown' };
const uri = constants.accessEndpoint;
const res = await this.setConfig(uri, data);
@ -416,6 +417,8 @@ export class IoTButtonDevice implements Device {
return res;
}
async configDeviceEnvironment(
deviceRootPath: string, scaffoldType: ScaffoldType): Promise<void> {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async configDeviceEnvironment(_deviceRootPath: string, _scaffoldType: ScaffoldType): Promise<void> {
// Do nothing.
}
}

Просмотреть файл

@ -5,18 +5,18 @@ import * as fs from 'fs-plus';
import * as path from 'path';
import * as vscode from 'vscode';
import {CancelOperationError} from '../CancelOperationError';
import {RemoteContainersCommands, VscodeCommands} from '../common/Commands';
import {ConfigKey, EventNames, FileNames, ScaffoldType} from '../constants';
import {FileUtility} from '../FileUtility';
import {TelemetryContext, TelemetryWorker} from '../telemetry';
import {getProjectConfig, updateProjectHostTypeConfig} from '../utils';
import { CancelOperationError } from '../CancelOperationError';
import { RemoteContainersCommands, VscodeCommands } from '../common/Commands';
import { ConfigKey, EventNames, FileNames, ScaffoldType } from '../constants';
import { FileUtility } from '../FileUtility';
import { TelemetryContext, TelemetryWorker } from '../telemetry';
import { getProjectConfig, updateProjectHostTypeConfig } from '../utils';
import {Component} from './Interfaces/Component';
import {ProjectHostType} from './Interfaces/ProjectHostType';
import {ProjectTemplateType, TemplateFileInfo} from './Interfaces/ProjectTemplate';
import {IoTWorkbenchProjectBase, OpenScenario} from './IoTWorkbenchProjectBase';
import {RemoteExtension} from './RemoteExtension';
import { Component } from './Interfaces/Component';
import { ProjectHostType } from './Interfaces/ProjectHostType';
import { ProjectTemplateType, TemplateFileInfo } from './Interfaces/ProjectTemplate';
import { IoTWorkbenchProjectBase, OpenScenario } from './IoTWorkbenchProjectBase';
import { RemoteExtension } from './RemoteExtension';
const impor = require('impor')(__dirname);
const raspberryPiDeviceModule =
@ -24,13 +24,13 @@ const raspberryPiDeviceModule =
export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
constructor(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, rootFolderPath: string) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, rootFolderPath: string) {
super(context, channel, telemetryContext);
this.projectHostType = ProjectHostType.Container;
if (!rootFolderPath) {
throw new Error(
`Fail to construct iot workspace project: root folder path is empty.`);
`Fail to construct iot workspace project: root folder path is empty.`);
}
this.projectRootPath = rootFolderPath;
this.iotWorkbenchProjectFilePath =
@ -43,7 +43,7 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
// 1. Update iot workbench project file.
await updateProjectHostTypeConfig(
scaffoldType, this.iotWorkbenchProjectFilePath, this.projectHostType);
scaffoldType, this.iotWorkbenchProjectFilePath, this.projectHostType);
// 2. Send load project event telemetry only if the IoT project is loaded
// when VS Code opens.
@ -57,14 +57,12 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
const boardId = projectConfigJson[`${ConfigKey.boardId}`];
if (!boardId) {
throw new Error(
`Internal Error: Fail to get board id from configuration.`);
`Internal Error: Fail to get board id from configuration.`);
}
await this.initDevice(boardId, scaffoldType);
}
async create(
templateFilesInfo: TemplateFileInfo[], projectType: ProjectTemplateType,
boardId: string, openInNewWindow: boolean): Promise<void> {
async create(templateFilesInfo: TemplateFileInfo[], _projectType: ProjectTemplateType, boardId: string, openInNewWindow: boolean): Promise<void> {
// Can only create project locally
await RemoteExtension.checkRemoteExtension();
@ -72,18 +70,18 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
// Create project root path
if (!await FileUtility.directoryExists(
createTimeScaffoldType, this.projectRootPath)) {
createTimeScaffoldType, this.projectRootPath)) {
await FileUtility.mkdirRecursively(
createTimeScaffoldType, this.projectRootPath);
createTimeScaffoldType, this.projectRootPath);
}
// Update iot workbench project file
await updateProjectHostTypeConfig(
createTimeScaffoldType, this.iotWorkbenchProjectFilePath,
this.projectHostType);
createTimeScaffoldType, this.iotWorkbenchProjectFilePath,
this.projectHostType);
const projectConfig = await getProjectConfig(
createTimeScaffoldType, this.iotWorkbenchProjectFilePath);
createTimeScaffoldType, this.iotWorkbenchProjectFilePath);
// Step 1: Create device
await this.initDevice(boardId, createTimeScaffoldType, templateFilesInfo);
@ -92,18 +90,18 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
// Update workspace config to workspace config file
if (!this.iotWorkbenchProjectFilePath) {
throw new Error(
`Workspace config file path is empty. Please initialize the project first.`);
`Workspace config file path is empty. Please initialize the project first.`);
}
await FileUtility.writeJsonFile(
createTimeScaffoldType, this.iotWorkbenchProjectFilePath,
projectConfig);
createTimeScaffoldType, this.iotWorkbenchProjectFilePath,
projectConfig);
// Check components prerequisites
this.componentList.forEach(async item => {
const res = await item.checkPrerequisites();
if (!res) {
throw new Error(
`Failed to create component because prerequisite is not met.`);
`Failed to create component because prerequisite is not met.`);
}
});
@ -119,7 +117,7 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
// Open project
await this.openProject(
createTimeScaffoldType, openInNewWindow, OpenScenario.createNewProject);
createTimeScaffoldType, openInNewWindow, OpenScenario.createNewProject);
}
/**
@ -127,8 +125,8 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
* If yes, open project in container. If not, stay local.
*/
async openProject(
scaffoldType: ScaffoldType, openInNewWindow: boolean,
openScenario: OpenScenario): Promise<void> {
scaffoldType: ScaffoldType, openInNewWindow: boolean,
openScenario: OpenScenario): Promise<void> {
this.validateProjectRootPath(scaffoldType);
// 1. Ask to customize
@ -144,8 +142,8 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
const telemetryWorker =
TelemetryWorker.getInstance(this.extensionContext);
const eventNames = openScenario === OpenScenario.createNewProject ?
EventNames.createNewProjectEvent :
EventNames.configProjectEnvironmentEvent;
EventNames.createNewProjectEvent :
EventNames.configProjectEnvironmentEvent;
telemetryWorker.sendEvent(eventNames, this.telemetryContext);
} catch {
// If sending telemetry failed, skip the error to avoid blocking user.
@ -157,22 +155,22 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
await this.openFolderInContainer(this.projectRootPath);
} else {
await vscode.commands.executeCommand(
VscodeCommands.VscodeOpenFolder,
vscode.Uri.file(this.projectRootPath), openInNewWindow);
VscodeCommands.VscodeOpenFolder,
vscode.Uri.file(this.projectRootPath), openInNewWindow);
// TODO: open install_packages.sh bash script.
}
}
private async openFolderInContainer(folderPath: string) {
private async openFolderInContainer(folderPath: string): Promise<void> {
if (!await FileUtility.directoryExists(ScaffoldType.Local, folderPath)) {
throw new Error(
`Fail to open folder in container: ${folderPath} does not exist.`);
`Fail to open folder in container: ${folderPath} does not exist.`);
}
await RemoteExtension.checkRemoteExtension();
await vscode.commands.executeCommand(
RemoteContainersCommands.OpenFolder, vscode.Uri.file(folderPath));
RemoteContainersCommands.OpenFolder, vscode.Uri.file(folderPath));
}
/**
@ -183,15 +181,15 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
* @param templateFilesInfo template files info to scaffold files for device
*/
private async initDevice(
boardId: string, scaffoldType: ScaffoldType,
templateFilesInfo?: TemplateFileInfo[]): Promise<void> {
boardId: string, scaffoldType: ScaffoldType,
templateFilesInfo?: TemplateFileInfo[]): Promise<void> {
this.validateProjectRootPath(scaffoldType);
let device: Component;
if (boardId === raspberryPiDeviceModule.RaspberryPiDevice.boardId) {
device = new raspberryPiDeviceModule.RaspberryPiDevice(
this.extensionContext, this.projectRootPath, this.channel,
this.telemetryContext, templateFilesInfo);
this.extensionContext, this.projectRootPath, this.channel,
this.telemetryContext, templateFilesInfo);
} else {
throw new Error(`The board ${boardId} is not supported.`);
}
@ -209,14 +207,14 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
private async askToOpenInContainer(): Promise<boolean> {
const openInContainerOption: vscode.QuickPickItem[] = [];
openInContainerOption.push(
{
label: `Yes`,
detail: 'I want to work on this project in container now.'
},
{
label: `No`,
detail: 'I need to customize my container first locally.'
});
{
label: `Yes`,
detail: 'I want to work on this project in container now.'
},
{
label: `No`,
detail: 'I need to customize my container first locally.'
});
const openInContainerSelection =
await vscode.window.showQuickPick(openInContainerOption, {
@ -226,7 +224,7 @@ export class IoTContainerizedProject extends IoTWorkbenchProjectBase {
if (!openInContainerSelection) {
throw new CancelOperationError(
`Ask to customize development environment selection cancelled.`);
`Ask to customize development environment selection cancelled.`);
}
return openInContainerSelection.label === 'Yes';

Просмотреть файл

@ -2,20 +2,20 @@
// Licensed under the MIT License.
import * as fs from 'fs-plus';
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as path from 'path';
import * as vscode from 'vscode';
import {ConfigHandler} from '../configHandler';
import {AzureComponentsStorage, ConfigKey, ScaffoldType} from '../constants';
import {channelPrintJsonObject, channelShowAndAppendLine} from '../utils';
import { ConfigHandler } from '../configHandler';
import { AzureComponentsStorage, ConfigKey, ScaffoldType } from '../constants';
import { channelPrintJsonObject, channelShowAndAppendLine } from '../utils';
import {getExtension} from './Apis';
import {AzureComponentConfig, AzureConfigFileHandler, AzureConfigs, ComponentInfo, DependencyConfig} from './AzureComponentConfig';
import {AzureUtility} from './AzureUtility';
import {ExtensionName} from './Interfaces/Api';
import {Component, ComponentType} from './Interfaces/Component';
import {Provisionable} from './Interfaces/Provisionable';
import { getExtension } from './Apis';
import { AzureComponentConfig, AzureConfigFileHandler, AzureConfigs, ComponentInfo, DependencyConfig } from './AzureComponentConfig';
import { AzureUtility } from './AzureUtility';
import { ExtensionName } from './Interfaces/Api';
import { Component, ComponentType } from './Interfaces/Component';
import { Provisionable } from './Interfaces/Provisionable';
export class IoTHub implements Component, Provisionable {
dependencies: DependencyConfig[] = [];
@ -24,7 +24,7 @@ export class IoTHub implements Component, Provisionable {
private projectRootPath: string;
private componentId: string;
private azureConfigFileHandler: AzureConfigFileHandler;
get id() {
get id(): string {
return this.componentId;
}
@ -48,8 +48,8 @@ export class IoTHub implements Component, Provisionable {
async load(): Promise<boolean> {
const azureConfigFilePath = path.join(
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
if (!fs.existsSync(azureConfigFilePath)) {
return false;
@ -60,7 +60,7 @@ export class IoTHub implements Component, Provisionable {
try {
azureConfigs = JSON.parse(fs.readFileSync(azureConfigFilePath, 'utf8'));
const iotHubConfig = azureConfigs.componentConfigs.find(
config => config.type === this.componentType);
config => config.type === this.componentType);
if (iotHubConfig) {
this.componentId = iotHubConfig.id;
this.dependencies = iotHubConfig.dependencies;
@ -91,8 +91,8 @@ export class IoTHub implements Component, Provisionable {
}
];
const selection = await vscode.window.showQuickPick(
provisionIothubSelection,
{ignoreFocusOut: true, placeHolder: 'Provision IoT Hub'});
provisionIothubSelection,
{ ignoreFocusOut: true, placeHolder: 'Provision IoT Hub' });
if (!selection) {
return false;
@ -101,7 +101,7 @@ export class IoTHub implements Component, Provisionable {
const toolkit = getExtension(ExtensionName.Toolkit);
if (!toolkit) {
throw new Error(
'Azure IoT Hub Toolkit is not installed. Please install it from Marketplace.');
'Azure IoT Hub Toolkit is not installed. Please install it from Marketplace.');
}
let iothub = null;
@ -109,20 +109,20 @@ export class IoTHub implements Component, Provisionable {
const resourceGroup = AzureUtility.resourceGroup;
switch (selection.detail) {
case 'select':
iothub = await toolkit.azureIoTExplorer.selectIoTHub(
this.channel, subscriptionId);
break;
case 'create':
if (this.channel) {
channelShowAndAppendLine(this.channel, 'Creating new IoT Hub...');
}
case 'select':
iothub = await toolkit.azureIoTExplorer.selectIoTHub(
this.channel, subscriptionId);
break;
case 'create':
if (this.channel) {
channelShowAndAppendLine(this.channel, 'Creating new IoT Hub...');
}
iothub = await toolkit.azureIoTExplorer.createIoTHub(
this.channel, subscriptionId, resourceGroup);
break;
default:
break;
iothub = await toolkit.azureIoTExplorer.createIoTHub(
this.channel, subscriptionId, resourceGroup);
break;
default:
break;
}
if (iothub && iothub.iotHubConnectionString) {
@ -134,24 +134,24 @@ export class IoTHub implements Component, Provisionable {
iothub.iotHubConnectionString.match(/SharedAccessKey=([^;]*)/);
if (!sharedAccessKeyMatches || sharedAccessKeyMatches.length < 2) {
throw new Error(
'Cannot parse shared access key from IoT Hub connection string. Please retry Azure Provision.');
'Cannot parse shared access key from IoT Hub connection string. Please retry Azure Provision.');
}
const sharedAccessKey = sharedAccessKeyMatches[1];
const eventHubConnectionString = `Endpoint=${
iothub.properties.eventHubEndpoints.events
.endpoint};SharedAccessKeyName=iothubowner;SharedAccessKey=${
sharedAccessKey}`;
iothub.properties.eventHubEndpoints.events
.endpoint};SharedAccessKeyName=iothubowner;SharedAccessKey=${
sharedAccessKey}`;
const eventHubConnectionPath =
iothub.properties.eventHubEndpoints.events.path;
await ConfigHandler.update(
ConfigKey.iotHubConnectionString, iothub.iotHubConnectionString);
ConfigKey.iotHubConnectionString, iothub.iotHubConnectionString);
await ConfigHandler.update(
ConfigKey.eventHubConnectionString, eventHubConnectionString);
ConfigKey.eventHubConnectionString, eventHubConnectionString);
await ConfigHandler.update(
ConfigKey.eventHubConnectionPath, eventHubConnectionPath);
ConfigKey.eventHubConnectionPath, eventHubConnectionPath);
const scaffoldType = ScaffoldType.Workspace;
await this.updateConfigSettings(scaffoldType, {
@ -170,7 +170,7 @@ export class IoTHub implements Component, Provisionable {
return false;
} else {
throw new Error(
'IoT Hub provision failed. Please check output window for detail.');
'IoT Hub provision failed. Please check output window for detail.');
}
}
@ -184,7 +184,7 @@ export class IoTHub implements Component, Provisionable {
return;
}
await this.azureConfigFileHandler.updateComponent(
type, iotHubComponentIndex, componentInfo);
type, iotHubComponentIndex, componentInfo);
} else {
const newIoTHubConfig: AzureComponentConfig = {
id: this.id,

Просмотреть файл

@ -2,107 +2,37 @@
// Licensed under the MIT License.
import * as iothub from 'azure-iothub';
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as vscode from 'vscode';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, ScaffoldType} from '../constants';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, ScaffoldType } from '../constants';
import {getExtension} from './Apis';
import {ComponentInfo, DependencyConfig} from './AzureComponentConfig';
import {ExtensionName} from './Interfaces/Api';
import {Component, ComponentType} from './Interfaces/Component';
import {Provisionable} from './Interfaces/Provisionable';
import { getExtension } from './Apis';
import { ComponentInfo, DependencyConfig } from './AzureComponentConfig';
import { ExtensionName } from './Interfaces/Api';
import { Component, ComponentType } from './Interfaces/Component';
import { Provisionable } from './Interfaces/Provisionable';
export class IoTHubDevice implements Component, Provisionable {
private componentType: ComponentType;
private channel: vscode.OutputChannel;
private componentId: string;
get id() {
return this.componentId;
}
dependencies: DependencyConfig[] = [];
constructor(channel: vscode.OutputChannel) {
this.componentType = ComponentType.IoTHubDevice;
this.channel = channel;
this.componentId = Guid.create().toString();
}
name = 'IoT Hub Device';
getComponentType(): ComponentType {
return this.componentType;
}
async checkPrerequisites(): Promise<boolean> {
return true;
}
async load(): Promise<boolean> {
return true;
}
async create(): Promise<void> {}
async provision(): Promise<boolean> {
const iotHubConnectionString =
ConfigHandler.get<string>(ConfigKey.iotHubConnectionString);
if (!iotHubConnectionString) {
throw new Error(
'Unable to find IoT Hub connection in the project. Please retry Azure Provision.');
}
const selection = await vscode.window.showQuickPick(
getProvisionIothubDeviceSelection(iotHubConnectionString),
{ignoreFocusOut: true, placeHolder: 'Provision IoTHub Device'});
if (!selection) {
return false;
}
const toolkit = getExtension(ExtensionName.Toolkit);
if (!toolkit) {
throw new Error(
'Azure IoT Hub Toolkit is not installed. Please install it from Marketplace.');
}
let device = null;
switch (selection.detail) {
case 'select':
device = await toolkit.azureIoTExplorer.getDevice(
null, iotHubConnectionString, this.channel);
if (!device) {
return false;
} else {
await ConfigHandler.update(
ConfigKey.iotHubDeviceConnectionString, device.connectionString);
async function getDeviceNumber(iotHubConnectionString: string): Promise<number> {
return new Promise(
(resolve: (value: number) => void, reject: (error: Error) => void) => {
const registry: iothub.Registry =
iothub.Registry.fromConnectionString(iotHubConnectionString);
registry.list((err, list) => {
if (err) {
return reject(err);
}
break;
case 'create':
device = await toolkit.azureIoTExplorer.createDevice(
false, iotHubConnectionString, this.channel);
if (!device) {
return false;
if (!list) {
return resolve(0);
} else {
await ConfigHandler.update(
ConfigKey.iotHubDeviceConnectionString, device.connectionString);
return resolve(list.length);
}
break;
default:
break;
}
return true;
}
updateConfigSettings(type: ScaffoldType, componentInfo?: ComponentInfo):
void {}
});
});
}
async function getProvisionIothubDeviceSelection(
iotHubConnectionString: string) {
async function getProvisionIothubDeviceSelection(iotHubConnectionString: string): Promise<vscode.QuickPickItem[]> {
let provisionIothubDeviceSelection: vscode.QuickPickItem[];
const deviceNumber = await getDeviceNumber(iotHubConnectionString);
@ -129,20 +59,93 @@ async function getProvisionIothubDeviceSelection(
return provisionIothubDeviceSelection;
}
async function getDeviceNumber(iotHubConnectionString: string) {
return new Promise(
(resolve: (value: number) => void, reject: (error: Error) => void) => {
const registry: iothub.Registry =
iothub.Registry.fromConnectionString(iotHubConnectionString);
registry.list((err, list) => {
if (err) {
return reject(err);
}
if (!list) {
return resolve(0);
} else {
return resolve(list.length);
}
});
});
}
export class IoTHubDevice implements Component, Provisionable {
private componentType: ComponentType;
private channel: vscode.OutputChannel;
private componentId: string;
get id(): string {
return this.componentId;
}
dependencies: DependencyConfig[] = [];
constructor(channel: vscode.OutputChannel) {
this.componentType = ComponentType.IoTHubDevice;
this.channel = channel;
this.componentId = Guid.create().toString();
}
name = 'IoT Hub Device';
getComponentType(): ComponentType {
return this.componentType;
}
async checkPrerequisites(): Promise<boolean> {
return true;
}
async load(): Promise<boolean> {
return true;
}
async create(): Promise<void> {
// Do nothing.
}
async provision(): Promise<boolean> {
const iotHubConnectionString =
ConfigHandler.get<string>(ConfigKey.iotHubConnectionString);
if (!iotHubConnectionString) {
throw new Error(
'Unable to find IoT Hub connection in the project. Please retry Azure Provision.');
}
const selection = await vscode.window.showQuickPick(
getProvisionIothubDeviceSelection(iotHubConnectionString),
{ ignoreFocusOut: true, placeHolder: 'Provision IoTHub Device' });
if (!selection) {
return false;
}
const toolkit = getExtension(ExtensionName.Toolkit);
if (!toolkit) {
throw new Error(
'Azure IoT Hub Toolkit is not installed. Please install it from Marketplace.');
}
let device = null;
switch (selection.detail) {
case 'select':
device = await toolkit.azureIoTExplorer.getDevice(
null, iotHubConnectionString, this.channel);
if (!device) {
return false;
} else {
await ConfigHandler.update(
ConfigKey.iotHubDeviceConnectionString, device.connectionString);
}
break;
case 'create':
device = await toolkit.azureIoTExplorer.createDevice(
false, iotHubConnectionString, this.channel);
if (!device) {
return false;
} else {
await ConfigHandler.update(
ConfigKey.iotHubDeviceConnectionString, device.connectionString);
}
break;
default:
break;
}
return true;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
updateConfigSettings(_type: ScaffoldType, _componentInfo?: ComponentInfo): void {
// Do nothing.
}
}

Просмотреть файл

@ -4,21 +4,21 @@
import * as path from 'path';
import * as vscode from 'vscode';
import {CancelOperationError} from '../CancelOperationError';
import {ConfigKey, EventNames, FileNames, ScaffoldType} from '../constants';
import {FileUtility} from '../FileUtility';
import {TelemetryContext, TelemetryWorker} from '../telemetry';
import { CancelOperationError } from '../CancelOperationError';
import { ConfigKey, EventNames, FileNames, ScaffoldType } from '../constants';
import { FileUtility } from '../FileUtility';
import { TelemetryContext, TelemetryWorker } from '../telemetry';
import * as utils from '../utils';
import {checkAzureLogin} from './Apis';
import {Compilable} from './Interfaces/Compilable';
import {Component, ComponentType} from './Interfaces/Component';
import {Deployable} from './Interfaces/Deployable';
import {Device} from './Interfaces/Device';
import {ProjectHostType} from './Interfaces/ProjectHostType';
import {ProjectTemplateType, TemplateFileInfo} from './Interfaces/ProjectTemplate';
import {Provisionable} from './Interfaces/Provisionable';
import {Uploadable} from './Interfaces/Uploadable';
import { checkAzureLogin } from './Apis';
import { Compilable } from './Interfaces/Compilable';
import { Component, ComponentType } from './Interfaces/Component';
import { Deployable } from './Interfaces/Deployable';
import { Device } from './Interfaces/Device';
import { ProjectHostType } from './Interfaces/ProjectHostType';
import { ProjectTemplateType, TemplateFileInfo } from './Interfaces/ProjectTemplate';
import { Provisionable } from './Interfaces/Provisionable';
import { Uploadable } from './Interfaces/Uploadable';
const impor = require('impor')(__dirname);
const azureUtilityModule =
@ -45,8 +45,8 @@ export abstract class IoTWorkbenchProjectBase {
* @param projectFileRootPath
*/
static async getProjectType(
scaffoldType: ScaffoldType,
projectFileRootPath: string|undefined): Promise<ProjectHostType> {
scaffoldType: ScaffoldType,
projectFileRootPath: string|undefined): Promise<ProjectHostType> {
if (!projectFileRootPath) {
return ProjectHostType.Unknown;
}
@ -57,14 +57,14 @@ export abstract class IoTWorkbenchProjectBase {
}
const iotWorkbenchProjectFileString =
(await FileUtility.readFile(
scaffoldType, iotWorkbenchProjectFile, 'utf8') as string)
.trim();
scaffoldType, iotWorkbenchProjectFile, 'utf8') as string)
.trim();
if (iotWorkbenchProjectFileString) {
const projectConfig = JSON.parse(iotWorkbenchProjectFileString);
if (projectConfig &&
projectConfig[`${ConfigKey.projectHostType}`] !== undefined) {
const projectHostType: ProjectHostType = utils.getEnumKeyByEnumValue(
ProjectHostType, projectConfig[`${ConfigKey.projectHostType}`]);
ProjectHostType, projectConfig[`${ConfigKey.projectHostType}`]);
return projectHostType;
}
}
@ -73,7 +73,7 @@ export abstract class IoTWorkbenchProjectBase {
const devcontainerFolderPath =
path.join(projectFileRootPath, FileNames.devcontainerFolderName);
if (await FileUtility.directoryExists(
scaffoldType, devcontainerFolderPath)) {
scaffoldType, devcontainerFolderPath)) {
return ProjectHostType.Container;
} else {
return ProjectHostType.Workspace;
@ -97,8 +97,8 @@ export abstract class IoTWorkbenchProjectBase {
}
constructor(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
this.componentList = [];
this.extensionContext = context;
this.channel = channel;
@ -123,7 +123,7 @@ export abstract class IoTWorkbenchProjectBase {
const res = await item.compile();
if (!res) {
vscode.window.showErrorMessage(
'Unable to compile the device code, please check output window for detail.');
'Unable to compile the device code, please check output window for detail.');
}
}
}
@ -141,7 +141,7 @@ export abstract class IoTWorkbenchProjectBase {
const res = await item.upload();
if (!res) {
vscode.window.showErrorMessage(
'Unable to upload the sketch, please check output window for detail.');
'Unable to upload the sketch, please check output window for detail.');
}
}
}
@ -164,7 +164,7 @@ export abstract class IoTWorkbenchProjectBase {
if (provisionItemList.length === 0) {
// nothing to provision:
vscode.window.showInformationMessage(
'Congratulations! There is no Azure service to provision in this project.');
'Congratulations! There is no Azure service to provision in this project.');
return false;
}
@ -194,12 +194,12 @@ export abstract class IoTWorkbenchProjectBase {
}
}
const selection = await vscode.window.showQuickPick(
[{
label: _provisionItemList.join(' - '),
description: '',
detail: 'Click to continue'
}],
{ignoreFocusOut: true, placeHolder: 'Provision process'});
[{
label: _provisionItemList.join(' - '),
description: '',
detail: 'Click to continue'
}],
{ ignoreFocusOut: true, placeHolder: 'Provision process' });
if (!selection) {
return false;
@ -214,7 +214,7 @@ export abstract class IoTWorkbenchProjectBase {
return true;
}
async deploy() {
async deploy(): Promise<void> {
let azureLoggedIn = false;
const deployItemList: string[] = [];
@ -231,7 +231,7 @@ export abstract class IoTWorkbenchProjectBase {
if (deployItemList && deployItemList.length <= 0) {
await vscode.window.showInformationMessage(
'Congratulations! The project does not contain any Azure components to be deployed.');
'Congratulations! The project does not contain any Azure components to be deployed.');
return;
}
@ -250,12 +250,12 @@ export abstract class IoTWorkbenchProjectBase {
}
}
const selection = await vscode.window.showQuickPick(
[{
label: _deployItemList.join(' - '),
description: '',
detail: 'Click to continue'
}],
{ignoreFocusOut: true, placeHolder: 'Deploy process'});
[{
label: _deployItemList.join(' - '),
description: '',
detail: 'Click to continue'
}],
{ ignoreFocusOut: true, placeHolder: 'Deploy process' });
if (!selection) {
throw new CancelOperationError(`Component deployment cancelled.`);
@ -276,7 +276,7 @@ export abstract class IoTWorkbenchProjectBase {
* template files.
*/
async configureProjectEnvironmentCore(
deviceRootPath: string, scaffoldType: ScaffoldType): Promise<void> {
deviceRootPath: string, scaffoldType: ScaffoldType): Promise<void> {
for (const component of this.componentList) {
if (component.getComponentType() === ComponentType.Device) {
const device = component as Device;
@ -302,11 +302,11 @@ export abstract class IoTWorkbenchProjectBase {
/**
* Send telemetry when the IoT project is load when VS Code opens
*/
sendLoadEventTelemetry(context: vscode.ExtensionContext) {
sendLoadEventTelemetry(context: vscode.ExtensionContext): void {
const telemetryWorker = TelemetryWorker.getInstance(context);
try {
telemetryWorker.sendEvent(
EventNames.projectLoadEvent, this.telemetryContext);
EventNames.projectLoadEvent, this.telemetryContext);
} catch {
// If sending telemetry failed, skip the error to avoid blocking user.
}
@ -318,9 +318,9 @@ export abstract class IoTWorkbenchProjectBase {
*/
async validateProjectRootPath(scaffoldType: ScaffoldType): Promise<void> {
if (!await FileUtility.directoryExists(
scaffoldType, this.projectRootPath)) {
scaffoldType, this.projectRootPath)) {
throw new Error(`Project root path ${
this.projectRootPath} does not exist. Please initialize the project first.`);
this.projectRootPath} does not exist. Please initialize the project first.`);
}
}
}

Просмотреть файл

@ -5,19 +5,19 @@ import * as fs from 'fs-plus';
import * as path from 'path';
import * as vscode from 'vscode';
import {IoTCubeCommands} from '../common/Commands';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, EventNames, FileNames, ScaffoldType} from '../constants';
import {FileUtility} from '../FileUtility';
import {TelemetryContext, TelemetryWorker} from '../telemetry';
import {getWorkspaceFile, updateProjectHostTypeConfig} from '../utils';
import { IoTCubeCommands } from '../common/Commands';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, EventNames, FileNames, ScaffoldType } from '../constants';
import { FileUtility } from '../FileUtility';
import { TelemetryContext, TelemetryWorker } from '../telemetry';
import { getWorkspaceFile, updateProjectHostTypeConfig } from '../utils';
import {AzureComponentConfig, Dependency} from './AzureComponentConfig';
import {Component, ComponentType} from './Interfaces/Component';
import {ProjectHostType} from './Interfaces/ProjectHostType';
import {ProjectTemplateType, TemplateFileInfo} from './Interfaces/ProjectTemplate';
import {Workspace} from './Interfaces/Workspace';
import {IoTWorkbenchProjectBase, OpenScenario} from './IoTWorkbenchProjectBase';
import { AzureComponentConfig, Dependency } from './AzureComponentConfig';
import { Component, ComponentType } from './Interfaces/Component';
import { ProjectHostType } from './Interfaces/ProjectHostType';
import { ProjectTemplateType, TemplateFileInfo } from './Interfaces/ProjectTemplate';
import { Workspace } from './Interfaces/Workspace';
import { IoTWorkbenchProjectBase, OpenScenario } from './IoTWorkbenchProjectBase';
const impor = require('impor')(__dirname);
const az3166DeviceModule =
@ -48,13 +48,13 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
private workspaceConfigFilePath = '';
constructor(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, rootFolderPath: string) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, rootFolderPath: string) {
super(context, channel, telemetryContext);
this.projectHostType = ProjectHostType.Workspace;
if (!rootFolderPath) {
throw new Error(
`Fail to construct iot workspace project: root folder path is empty.`);
`Fail to construct iot workspace project: root folder path is empty.`);
}
this.projectRootPath = rootFolderPath;
this.telemetryContext.properties.projectHostType = this.projectHostType;
@ -67,19 +67,19 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
const devicePath = ConfigHandler.get<string>(ConfigKey.devicePath);
if (!devicePath) {
throw new Error(
`Internal Error: Fail to get device path from configuration.`);
`Internal Error: Fail to get device path from configuration.`);
}
this.deviceRootPath = path.join(this.projectRootPath, devicePath);
if (!await FileUtility.directoryExists(scaffoldType, this.deviceRootPath)) {
throw new Error(
`Device root path ${this.deviceRootPath} does not exist.`);
`Device root path ${this.deviceRootPath} does not exist.`);
}
// Init and update iot workbench project file
this.iotWorkbenchProjectFilePath =
path.join(this.deviceRootPath, FileNames.iotWorkbenchProjectFileName);
await updateProjectHostTypeConfig(
scaffoldType, this.iotWorkbenchProjectFilePath, this.projectHostType);
scaffoldType, this.iotWorkbenchProjectFilePath, this.projectHostType);
// Init workspace config file
this.loadAndInitWorkspaceConfigFilePath(scaffoldType);
@ -93,7 +93,7 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
const boardId = ConfigHandler.get<string>(ConfigKey.boardId);
if (!boardId) {
throw new Error(
`Internal Error: Fail to get board id from configuration.`);
`Internal Error: Fail to get board id from configuration.`);
}
await this.initDevice(boardId, scaffoldType);
@ -106,52 +106,52 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
}
async create(
templateFilesInfo: TemplateFileInfo[], projectType: ProjectTemplateType,
boardId: string, openInNewWindow: boolean): Promise<void> {
templateFilesInfo: TemplateFileInfo[], projectType: ProjectTemplateType,
boardId: string, openInNewWindow: boolean): Promise<void> {
const createTimeScaffoldType = ScaffoldType.Local;
// Init device root path
this.deviceRootPath =
path.join(this.projectRootPath, folderName.deviceDefaultFolderName);
if (!await FileUtility.directoryExists(
createTimeScaffoldType, this.deviceRootPath)) {
createTimeScaffoldType, this.deviceRootPath)) {
await FileUtility.mkdirRecursively(
createTimeScaffoldType, this.deviceRootPath);
createTimeScaffoldType, this.deviceRootPath);
}
// Init iot workbench project file path
this.iotWorkbenchProjectFilePath =
path.join(this.deviceRootPath, FileNames.iotWorkbenchProjectFileName);
// Init workspace config file
this.workspaceConfigFilePath = path.join(
this.projectRootPath,
`${path.basename(this.projectRootPath)}${
FileNames.workspaceExtensionName}`);
this.projectRootPath,
`${path.basename(this.projectRootPath)}${
FileNames.workspaceExtensionName}`);
// Update iot workbench project file.
await updateProjectHostTypeConfig(
createTimeScaffoldType, this.iotWorkbenchProjectFilePath,
this.projectHostType);
createTimeScaffoldType, this.iotWorkbenchProjectFilePath,
this.projectHostType);
const workspace: Workspace = {folders: [], settings: {}};
const workspace: Workspace = { folders: [], settings: {} };
// Init device
await this.initDevice(boardId, createTimeScaffoldType, templateFilesInfo);
workspace.folders.push({path: folderName.deviceDefaultFolderName});
workspace.folders.push({ path: folderName.deviceDefaultFolderName });
workspace.settings[`IoTWorkbench.${ConfigKey.boardId}`] = boardId;
workspace.settings[`IoTWorkbench.${ConfigKey.devicePath}`] =
folderName.deviceDefaultFolderName;
// Create azure components
await this.createAzureComponentsWithProjectType(
projectType, createTimeScaffoldType, workspace);
projectType, createTimeScaffoldType, workspace);
// Update workspace config to workspace config file
if (!this.workspaceConfigFilePath) {
throw new Error(
`Workspace config file path is empty. Please initialize the project first.`);
`Workspace config file path is empty. Please initialize the project first.`);
}
await FileUtility.writeJsonFile(
createTimeScaffoldType, this.workspaceConfigFilePath, workspace);
createTimeScaffoldType, this.workspaceConfigFilePath, workspace);
// Check components prerequisites
this.componentList.forEach(async item => {
@ -173,18 +173,18 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
// Open project
await this.openProject(
createTimeScaffoldType, openInNewWindow, OpenScenario.createNewProject);
createTimeScaffoldType, openInNewWindow, OpenScenario.createNewProject);
}
async openProject(
scaffoldType: ScaffoldType, openInNewWindow: boolean,
openScenario: OpenScenario): Promise<void> {
scaffoldType: ScaffoldType, openInNewWindow: boolean,
openScenario: OpenScenario): Promise<void> {
this.loadAndInitWorkspaceConfigFilePath(scaffoldType);
if (!await FileUtility.fileExists(
scaffoldType, this.workspaceConfigFilePath)) {
scaffoldType, this.workspaceConfigFilePath)) {
throw new Error(`Workspace config file ${
this.workspaceConfigFilePath} does not exist. Please initialize the project first.`);
this.workspaceConfigFilePath} does not exist. Please initialize the project first.`);
}
if (!openInNewWindow) {
@ -194,8 +194,8 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
const telemetryWorker =
TelemetryWorker.getInstance(this.extensionContext);
const eventNames = openScenario === OpenScenario.createNewProject ?
EventNames.createNewProjectEvent :
EventNames.configProjectEnvironmentEvent;
EventNames.createNewProjectEvent :
EventNames.configProjectEnvironmentEvent;
telemetryWorker.sendEvent(eventNames, this.telemetryContext);
} catch {
// If sending telemetry failed, skip the error to avoid blocking user.
@ -203,8 +203,8 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
}
vscode.commands.executeCommand(
IoTCubeCommands.OpenLocally, this.workspaceConfigFilePath,
openInNewWindow);
IoTCubeCommands.OpenLocally, this.workspaceConfigFilePath,
openInNewWindow);
}
/**
@ -214,26 +214,23 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
* @param scaffoldType scaffold type
* @param templateFilesInfo template files info to scaffold files for device
*/
private async initDevice(
boardId: string, scaffoldType: ScaffoldType,
templateFilesInfo?: TemplateFileInfo[]) {
private async initDevice(boardId: string, scaffoldType: ScaffoldType, templateFilesInfo?: TemplateFileInfo[]): Promise<void> {
if (!await FileUtility.directoryExists(scaffoldType, this.deviceRootPath)) {
throw new Error(`Device root path ${
this.deviceRootPath} does not exist. Please initialize the project first.`);
this.deviceRootPath} does not exist. Please initialize the project first.`);
}
let device: Component;
if (boardId === az3166DeviceModule.AZ3166Device.boardId) {
device = new az3166DeviceModule.AZ3166Device(
this.extensionContext, this.channel, this.telemetryContext,
this.deviceRootPath, templateFilesInfo);
this.extensionContext, this.channel, this.telemetryContext,
this.deviceRootPath, templateFilesInfo);
} else if (boardId === ioTButtonDeviceModule.IoTButtonDevice.boardId) {
device = new ioTButtonDeviceModule.IoTButtonDevice(
this.extensionContext, this.deviceRootPath, templateFilesInfo);
device = new ioTButtonDeviceModule.IoTButtonDevice(this.deviceRootPath, templateFilesInfo);
} else if (boardId === esp32DeviceModule.Esp32Device.boardId) {
device = new esp32DeviceModule.Esp32Device(
this.extensionContext, this.channel, this.telemetryContext,
this.deviceRootPath, templateFilesInfo);
this.extensionContext, this.channel, this.telemetryContext,
this.deviceRootPath, templateFilesInfo);
} else {
throw new Error(`The board ${boardId} is not supported.`);
}
@ -266,10 +263,10 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
if (functionPath) {
const functionLocation = path.join(this.projectRootPath, functionPath);
const functionApp = new azureFunctionsModule.AzureFunctions(
functionLocation, functionPath, this.channel, null, [{
component: iotHub,
type: azureComponentConfigModule.DependencyType.Input
}]);
functionLocation, functionPath, this.channel, null, [{
component: iotHub,
type: azureComponentConfigModule.DependencyType.Input
}]);
await functionApp.updateConfigSettings(scaffoldType);
await functionApp.load();
this.componentList.push(functionApp);
@ -283,85 +280,85 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
* @param componentConfigs azure component configs
*/
private async initAzureComponentsWithConfig(
scaffoldType: ScaffoldType,
componentConfigs: AzureComponentConfig[]): Promise<void> {
scaffoldType: ScaffoldType,
componentConfigs: AzureComponentConfig[]): Promise<void> {
this.validateProjectRootPath(scaffoldType);
const components: {[key: string]: Component} = {};
for (const componentConfig of componentConfigs) {
switch (componentConfig.type) {
case ComponentType.IoTHub: {
const iotHub =
case ComponentType.IoTHub: {
const iotHub =
new ioTHubModule.IoTHub(this.projectRootPath, this.channel);
await iotHub.load();
components[iotHub.id] = iotHub;
this.componentList.push(iotHub);
await iotHub.load();
components[iotHub.id] = iotHub;
this.componentList.push(iotHub);
const iothubDevice =
const iothubDevice =
new ioTHubDeviceModule.IoTHubDevice(this.channel);
this.componentList.push(iothubDevice);
this.componentList.push(iothubDevice);
break;
}
case ComponentType.AzureFunctions: {
const functionPath =
break;
}
case ComponentType.AzureFunctions: {
const functionPath =
ConfigHandler.get<string>(ConfigKey.functionPath);
if (!functionPath) {
throw new Error(
`Internal Error: Fail to get function path from configuration.`);
}
const functionLocation =
path.join(this.projectRootPath, functionPath);
if (functionLocation) {
const functionApp = new azureFunctionsModule.AzureFunctions(
functionLocation, functionPath, this.channel);
await functionApp.load();
components[functionApp.id] = functionApp;
this.componentList.push(functionApp);
}
break;
}
case ComponentType.StreamAnalyticsJob: {
const dependencies: Dependency[] = [];
for (const dependent of componentConfig.dependencies) {
const component = components[dependent.id];
if (!component) {
throw new Error(`Cannot find component with id ${dependent}.`);
}
dependencies.push({component, type: dependent.type});
}
const queryPath = path.join(
this.projectRootPath, folderName.asaFolderName, 'query.asaql');
const asa = new streamAnalyticsJobModule.StreamAnalyticsJob(
queryPath, this.extensionContext, this.projectRootPath,
this.channel, dependencies);
await asa.load();
components[asa.id] = asa;
this.componentList.push(asa);
break;
}
case ComponentType.CosmosDB: {
const dependencies: Dependency[] = [];
for (const dependent of componentConfig.dependencies) {
const component = components[dependent.id];
if (!component) {
throw new Error(`Cannot find component with id ${dependent}.`);
}
dependencies.push({component, type: dependent.type});
}
const cosmosDB = new cosmosDBModule.CosmosDB(
this.extensionContext, this.projectRootPath, this.channel,
dependencies);
await cosmosDB.load();
components[cosmosDB.id] = cosmosDB;
this.componentList.push(cosmosDB);
break;
}
default: {
if (!functionPath) {
throw new Error(
`Component not supported with type of ${componentConfig.type}.`);
`Internal Error: Fail to get function path from configuration.`);
}
const functionLocation =
path.join(this.projectRootPath, functionPath);
if (functionLocation) {
const functionApp = new azureFunctionsModule.AzureFunctions(
functionLocation, functionPath, this.channel);
await functionApp.load();
components[functionApp.id] = functionApp;
this.componentList.push(functionApp);
}
break;
}
case ComponentType.StreamAnalyticsJob: {
const dependencies: Dependency[] = [];
for (const dependent of componentConfig.dependencies) {
const component = components[dependent.id];
if (!component) {
throw new Error(`Cannot find component with id ${dependent}.`);
}
dependencies.push({ component, type: dependent.type });
}
const queryPath = path.join(
this.projectRootPath, folderName.asaFolderName, 'query.asaql');
const asa = new streamAnalyticsJobModule.StreamAnalyticsJob(
queryPath, this.extensionContext, this.projectRootPath,
this.channel, dependencies);
await asa.load();
components[asa.id] = asa;
this.componentList.push(asa);
break;
}
case ComponentType.CosmosDB: {
const dependencies: Dependency[] = [];
for (const dependent of componentConfig.dependencies) {
const component = components[dependent.id];
if (!component) {
throw new Error(`Cannot find component with id ${dependent}.`);
}
dependencies.push({ component, type: dependent.type });
}
const cosmosDB = new cosmosDBModule.CosmosDB(
this.extensionContext, this.projectRootPath, this.channel,
dependencies);
await cosmosDB.load();
components[cosmosDB.id] = cosmosDB;
this.componentList.push(cosmosDB);
break;
}
default: {
throw new Error(
`Component not supported with type of ${componentConfig.type}.`);
}
}
}
}
@ -375,7 +372,7 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
const azureConfigFileHandler =
new azureComponentConfigModule.AzureConfigFileHandler(
this.projectRootPath);
this.projectRootPath);
await azureConfigFileHandler.createIfNotExists(scaffoldType);
const componentConfigs =
@ -390,101 +387,101 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
}
private async createAzureComponentsWithProjectType(
projectType: ProjectTemplateType, scaffoldType: ScaffoldType,
workspaceConfig: Workspace): Promise<void> {
projectType: ProjectTemplateType, scaffoldType: ScaffoldType,
workspaceConfig: Workspace): Promise<void> {
this.validateProjectRootPath(scaffoldType);
// initialize the storage for azure component settings
const azureConfigFileHandler =
new azureComponentConfigModule.AzureConfigFileHandler(
this.projectRootPath);
this.projectRootPath);
await azureConfigFileHandler.createIfNotExists(scaffoldType);
switch (projectType) {
case ProjectTemplateType.Basic:
// Save data to configFile
break;
case ProjectTemplateType.IotHub: {
const iothub =
case ProjectTemplateType.Basic:
// Save data to configFile
break;
case ProjectTemplateType.IotHub: {
const iothub =
new ioTHubModule.IoTHub(this.projectRootPath, this.channel);
this.componentList.push(iothub);
break;
this.componentList.push(iothub);
break;
}
case ProjectTemplateType.AzureFunctions: {
const iothub =
new ioTHubModule.IoTHub(this.projectRootPath, this.channel);
const functionDir = path.join(
this.projectRootPath, folderName.functionDefaultFolderName);
if (!await FileUtility.directoryExists(scaffoldType, functionDir)) {
await FileUtility.mkdirRecursively(scaffoldType, functionDir);
}
case ProjectTemplateType.AzureFunctions: {
const iothub =
new ioTHubModule.IoTHub(this.projectRootPath, this.channel);
const azureFunctions = new azureFunctionsModule.AzureFunctions(
functionDir, folderName.functionDefaultFolderName, this.channel,
null, [{
component: iothub,
type: azureComponentConfigModule.DependencyType.Input
}] /*Dependencies*/);
const functionDir = path.join(
this.projectRootPath, folderName.functionDefaultFolderName);
if (!await FileUtility.directoryExists(scaffoldType, functionDir)) {
await FileUtility.mkdirRecursively(scaffoldType, functionDir);
}
const azureFunctions = new azureFunctionsModule.AzureFunctions(
functionDir, folderName.functionDefaultFolderName, this.channel,
null, [{
component: iothub,
type: azureComponentConfigModule.DependencyType.Input
}] /*Dependencies*/);
workspaceConfig.folders.push(
{path: folderName.functionDefaultFolderName});
workspaceConfig.settings[`IoTWorkbench.${ConfigKey.functionPath}`] =
workspaceConfig.folders.push(
{ path: folderName.functionDefaultFolderName });
workspaceConfig.settings[`IoTWorkbench.${ConfigKey.functionPath}`] =
folderName.functionDefaultFolderName;
this.componentList.push(iothub);
this.componentList.push(azureFunctions);
break;
}
case ProjectTemplateType.StreamAnalytics: {
const iothub =
this.componentList.push(iothub);
this.componentList.push(azureFunctions);
break;
}
case ProjectTemplateType.StreamAnalytics: {
const iothub =
new ioTHubModule.IoTHub(this.projectRootPath, this.channel);
const cosmosDB = new cosmosDBModule.CosmosDB(
this.extensionContext, this.projectRootPath, this.channel);
const cosmosDB = new cosmosDBModule.CosmosDB(
this.extensionContext, this.projectRootPath, this.channel);
const asaDir =
const asaDir =
path.join(this.projectRootPath, folderName.asaFolderName);
if (!await FileUtility.directoryExists(scaffoldType, asaDir)) {
await FileUtility.mkdirRecursively(scaffoldType, asaDir);
}
const asaFilePath = this.extensionContext.asAbsolutePath(
path.join(FileNames.resourcesFolderName, 'asaql', 'query.asaql'));
const queryPath = path.join(asaDir, 'query.asaql');
const asaQueryContent =
if (!await FileUtility.directoryExists(scaffoldType, asaDir)) {
await FileUtility.mkdirRecursively(scaffoldType, asaDir);
}
const asaFilePath = this.extensionContext.asAbsolutePath(
path.join(FileNames.resourcesFolderName, 'asaql', 'query.asaql'));
const queryPath = path.join(asaDir, 'query.asaql');
const asaQueryContent =
fs.readFileSync(asaFilePath, 'utf8')
.replace(/\[input\]/, `"iothub-${iothub.id}"`)
.replace(/\[output\]/, `"cosmosdb-${cosmosDB.id}"`);
await FileUtility.writeFile(scaffoldType, queryPath, asaQueryContent);
.replace(/\[input\]/, `"iothub-${iothub.id}"`)
.replace(/\[output\]/, `"cosmosdb-${cosmosDB.id}"`);
await FileUtility.writeFile(scaffoldType, queryPath, asaQueryContent);
const asa = new streamAnalyticsJobModule.StreamAnalyticsJob(
queryPath, this.extensionContext, this.projectRootPath,
this.channel, [
{
component: iothub,
type: azureComponentConfigModule.DependencyType.Input
},
{
component: cosmosDB,
type: azureComponentConfigModule.DependencyType.Other
}
]);
const asa = new streamAnalyticsJobModule.StreamAnalyticsJob(
queryPath, this.extensionContext, this.projectRootPath,
this.channel, [
{
component: iothub,
type: azureComponentConfigModule.DependencyType.Input
},
{
component: cosmosDB,
type: azureComponentConfigModule.DependencyType.Other
}
]);
workspaceConfig.folders.push({path: folderName.asaFolderName});
workspaceConfig.settings[`IoTWorkbench.${ConfigKey.asaPath}`] =
workspaceConfig.folders.push({ path: folderName.asaFolderName });
workspaceConfig.settings[`IoTWorkbench.${ConfigKey.asaPath}`] =
folderName.asaFolderName;
this.componentList.push(iothub);
this.componentList.push(cosmosDB);
this.componentList.push(asa);
break;
}
default:
break;
this.componentList.push(iothub);
this.componentList.push(cosmosDB);
this.componentList.push(asa);
break;
}
default:
break;
}
}
// Init workspace config file path at load time
private async loadAndInitWorkspaceConfigFilePath(scaffoldType: ScaffoldType) {
private async loadAndInitWorkspaceConfigFilePath(scaffoldType: ScaffoldType): Promise<void> {
this.validateProjectRootPath(scaffoldType);
const workspaceFile = getWorkspaceFile(this.projectRootPath);
@ -493,8 +490,8 @@ export class IoTWorkspaceProject extends IoTWorkbenchProjectBase {
path.join(this.projectRootPath, workspaceFile);
} else {
throw new Error(
`Fail to init iot project workspace file path: Cannot find workspace file under project root path: ${
this.projectRootPath}.`);
`Fail to init iot project workspace file path: Cannot find workspace file under project root path: ${
this.projectRootPath}.`);
}
}
}

Просмотреть файл

@ -1,11 +1,14 @@
import {crc16xmodem} from 'crc';
import { crc16xmodem } from 'crc';
import * as fs from 'fs-plus';
export class OTA {
static generateCrc(filePath: string) {
static generateCrc(filePath: string): {
crc: string;
size: number;
} {
const data = fs.readFileSync(filePath);
const size = fs.statSync(filePath).size;
const crc = crc16xmodem(data).toString(16);
return {crc, size};
return { crc, size };
}
}

Просмотреть файл

@ -5,17 +5,17 @@ import * as path from 'path';
import * as vscode from 'vscode';
import * as sdk from 'vscode-iot-device-cube-sdk';
import {CancelOperationError} from '../CancelOperationError';
import {ConfigHandler} from '../configHandler';
import {ConfigKey, FileNames, OperationType, ScaffoldType} from '../constants';
import {FileUtility} from '../FileUtility';
import {TelemetryContext} from '../telemetry';
import {askAndOpenInRemote, channelShowAndAppendLine, executeCommand} from '../utils';
import { CancelOperationError } from '../CancelOperationError';
import { ConfigHandler } from '../configHandler';
import { ConfigKey, FileNames, OperationType, ScaffoldType } from '../constants';
import { FileUtility } from '../FileUtility';
import { TelemetryContext } from '../telemetry';
import { askAndOpenInRemote, channelShowAndAppendLine, executeCommand } from '../utils';
import {ContainerDeviceBase} from './ContainerDeviceBase';
import {DeviceType} from './Interfaces/Device';
import {TemplateFileInfo} from './Interfaces/ProjectTemplate';
import {RemoteExtension} from './RemoteExtension';
import { ContainerDeviceBase } from './ContainerDeviceBase';
import { DeviceType } from './Interfaces/Device';
import { TemplateFileInfo } from './Interfaces/ProjectTemplate';
import { RemoteExtension } from './RemoteExtension';
class RaspberryPiUploadConfig {
static host = 'hostname';
@ -30,17 +30,17 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
private static _boardId = 'raspberrypi';
name = 'Raspberry Pi';
static get boardId() {
static get boardId(): string {
return RaspberryPiDevice._boardId;
}
constructor(
context: vscode.ExtensionContext, projectPath: string,
channel: vscode.OutputChannel, telemetryContext: TelemetryContext,
templateFilesInfo: TemplateFileInfo[] = []) {
context: vscode.ExtensionContext, projectPath: string,
channel: vscode.OutputChannel, telemetryContext: TelemetryContext,
templateFilesInfo: TemplateFileInfo[] = []) {
super(
context, projectPath, channel, telemetryContext,
DeviceType.Raspberry_Pi, templateFilesInfo);
context, projectPath, channel, telemetryContext,
DeviceType.RaspberryPi, templateFilesInfo);
}
private async getBinaryFileName(): Promise<string|undefined> {
@ -51,19 +51,19 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
return;
}
const getBinaryFileNameCmd = `cat ${
cmakeFilePath} | grep 'add_executable' | sed -e 's/^add_executable(//' | awk '{$1=$1};1' | cut -d ' ' -f1 | tr -d '\n'`;
cmakeFilePath} | grep 'add_executable' | sed -e 's/^add_executable(//' | awk '{$1=$1};1' | cut -d ' ' -f1 | tr -d '\n'`;
const binaryName = await executeCommand(getBinaryFileNameCmd);
return binaryName;
}
private async enableBinaryExecutability(ssh: sdk.SSH, binaryName: string) {
private async enableBinaryExecutability(ssh: sdk.SSH, binaryName: string): Promise<void> {
if (!binaryName) {
return;
}
const chmodCmd = `cd ${RaspberryPiUploadConfig.projectPath} && [ -f ${
binaryName} ] && chmod +x ${binaryName}`;
binaryName} ] && chmod +x ${binaryName}`;
await ssh.exec(chmodCmd);
return;
@ -80,7 +80,7 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
const binaryName = await this.getBinaryFileName();
if (!binaryName) {
const message = `No executable file specified in ${
FileNames.cmakeFileName}. Nothing to upload to target machine.`;
FileNames.cmakeFileName}. Nothing to upload to target machine.`;
vscode.window.showWarningMessage(message);
channelShowAndAppendLine(this.channel, message);
return false;
@ -88,9 +88,9 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
const binaryFilePath = path.join(this.outputPath, binaryName);
if (!await FileUtility.fileExists(
ScaffoldType.Workspace, binaryFilePath)) {
ScaffoldType.Workspace, binaryFilePath)) {
const message = `Executable file ${binaryName} does not exist under ${
this.outputPath}. Please compile device code first.`;
this.outputPath}. Please compile device code first.`;
vscode.window.showWarningMessage(message);
channelShowAndAppendLine(this.channel, message);
return false;
@ -105,16 +105,16 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
const ssh = new sdk.SSH();
await ssh.open(
RaspberryPiUploadConfig.host, RaspberryPiUploadConfig.port,
RaspberryPiUploadConfig.user, RaspberryPiUploadConfig.password);
RaspberryPiUploadConfig.host, RaspberryPiUploadConfig.port,
RaspberryPiUploadConfig.user, RaspberryPiUploadConfig.password);
try {
await ssh.uploadFile(
binaryFilePath, RaspberryPiUploadConfig.projectPath);
binaryFilePath, RaspberryPiUploadConfig.projectPath);
} catch (error) {
const message =
`SSH traffic is too busy. Please wait a second and retry. Error: ${
error}.`;
error}.`;
channelShowAndAppendLine(this.channel, message);
console.log(error);
throw new Error(message);
@ -124,14 +124,14 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
await this.enableBinaryExecutability(ssh, binaryName);
} catch (error) {
throw new Error(
`Failed to enable binary executability. Error: ${error.message}`);
`Failed to enable binary executability. Error: ${error.message}`);
}
try {
await ssh.close();
} catch (error) {
throw new Error(
`Failed to close SSH connection. Error: ${error.message}`);
`Failed to close SSH connection. Error: ${error.message}`);
}
const message = `Successfully deploy compiled files to device board.`;
@ -139,8 +139,8 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
vscode.window.showInformationMessage(message);
} catch (error) {
throw new Error(
`Upload binary file to device ${RaspberryPiUploadConfig.user}@${
RaspberryPiUploadConfig.host} failed. ${error}`);
`Upload binary file to device ${RaspberryPiUploadConfig.user}@${
RaspberryPiUploadConfig.host} failed. ${error}`);
}
return true;
@ -199,14 +199,14 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
});
sshDevicePickItems.push(
{
label: '$(sync) Discover again',
detail: 'Auto discover SSH enabled device in LAN'
},
{
label: '$(gear) Manual setup',
detail: 'Setup device SSH configuration manually'
});
{
label: '$(sync) Discover again',
detail: 'Auto discover SSH enabled device in LAN'
},
{
label: '$(gear) Manual setup',
detail: 'Setup device SSH configuration manually'
});
return sshDevicePickItems;
}
@ -283,8 +283,8 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
return false;
}
const raspiPort = raspiPortString && !isNaN(Number(raspiPortString)) ?
Number(raspiPortString) :
RaspberryPiUploadConfig.port;
Number(raspiPortString) :
RaspberryPiUploadConfig.port;
// Raspberry Pi user name
const raspiUserOption: vscode.InputBoxOptions = {
@ -335,7 +335,7 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
const projectFolderPath = this.projectFolder;
if (!FileUtility.directoryExists(
ScaffoldType.Workspace, projectFolderPath)) {
ScaffoldType.Workspace, projectFolderPath)) {
throw new Error('Unable to find the device folder inside the project.');
}
@ -358,13 +358,13 @@ export class RaspberryPiDevice extends ContainerDeviceBase {
ConfigHandler.get<string>(ConfigKey.iotHubDeviceConnectionString);
if (!deviceConnectionString) {
throw new Error(
'Unable to get the device connection string, please invoke the command of Azure Provision first.');
'Unable to get the device connection string, please invoke the command of Azure Provision first.');
}
const ssh = new sdk.SSH();
await ssh.clipboardCopy(deviceConnectionString);
await ssh.close();
vscode.window.showInformationMessage(
'Device connection string has been copied.');
'Device connection string has been copied.');
return true;
}
}

Просмотреть файл

@ -2,14 +2,14 @@
'use strict';
import * as vscode from 'vscode';
import {DependentExtensions} from '../constants';
import {DialogResponses} from '../DialogResponses';
import {WorkbenchExtension} from '../WorkbenchExtension';
import {VscodeCommands} from '../common/Commands';
import {CancelOperationError} from '../CancelOperationError';
import { DependentExtensions } from '../constants';
import { DialogResponses } from '../DialogResponses';
import { WorkbenchExtension } from '../WorkbenchExtension';
import { VscodeCommands } from '../common/Commands';
import { CancelOperationError } from '../CancelOperationError';
export class RemoteExtension {
static isRemote(context: vscode.ExtensionContext) {
static isRemote(context: vscode.ExtensionContext): boolean {
const extension = WorkbenchExtension.getExtension(context);
if (!extension) {
throw new Error('Fail to get workbench extension.');
@ -28,11 +28,11 @@ export class RemoteExtension {
const message =
'Remote extension is required for the current project. Do you want to install it from marketplace?';
const choice = await vscode.window.showInformationMessage(
message, DialogResponses.yes, DialogResponses.no);
message, DialogResponses.yes, DialogResponses.no);
if (choice === DialogResponses.yes) {
vscode.commands.executeCommand(
VscodeCommands.VscodeOpen,
vscode.Uri.parse('vscode:extension/' + DependentExtensions.remote));
VscodeCommands.VscodeOpen,
vscode.Uri.parse('vscode:extension/' + DependentExtensions.remote));
}
return false;
}
@ -43,8 +43,8 @@ export class RemoteExtension {
const res = await RemoteExtension.isAvailable();
if (!res) {
throw new CancelOperationError(
`Remote extension is not available. Please install ${
DependentExtensions.remote} first.`);
`Remote extension is not available. Please install ${
DependentExtensions.remote} first.`);
}
}

Просмотреть файл

@ -5,7 +5,7 @@ import * as fs from 'fs-plus';
import * as path from 'path';
import * as ssh2 from 'ssh2';
import * as vscode from 'vscode';
import {channelShowAndAppendLine} from '../utils';
import { channelShowAndAppendLine } from '../utils';
export class SSH {
private _client: ssh2.Client;
@ -19,276 +19,271 @@ export class SSH {
}
}
async connect(
host: string, port: number, username: string, password: string) {
async connect(host: string, port: number, username: string, password: string): Promise<boolean> {
return new Promise(
(resolve: (value: boolean) => void,
reject: (reason: boolean) => void) => {
const conn = this._client;
conn.on('ready',
() => {
this._connected = true;
return resolve(true);
})
.on('end',
() => {
this._connected = false;
return resolve(false);
})
.on('close',
() => {
this._connected = false;
return resolve(false);
})
.connect({host, port, username, password});
});
(resolve: (value: boolean) => void) => {
const conn = this._client;
conn.on('ready',
() => {
this._connected = true;
return resolve(true);
})
.on('end',
() => {
this._connected = false;
return resolve(false);
})
.on('close',
() => {
this._connected = false;
return resolve(false);
})
.connect({ host, port, username, password });
});
}
async upload(filePath: string, remoteRootPath: string) {
async upload(filePath: string, remoteRootPath: string): Promise<boolean> {
return new Promise(
(resolve: (value: boolean) => void,
reject: (reason: boolean) => void) => {
if (!this._connected) {
return resolve(false);
}
(resolve: (value: boolean) => void) => {
if (!this._connected) {
return resolve(false);
}
if (!fs.existsSync(filePath)) {
return resolve(false);
}
if (!fs.existsSync(filePath)) {
return resolve(false);
}
filePath = filePath.replace(/[\\\/]+/g, '/');
filePath = filePath.replace(/[\\/]+/g, '/');
const rootPath =
const rootPath =
(fs.isDirectorySync(filePath) ? filePath : path.dirname(filePath))
.replace(/\/$/, '');
const files = fs.listTreeSync(filePath);
.replace(/\/$/, '');
const files = fs.listTreeSync(filePath);
if (this._channel) {
channelShowAndAppendLine(this._channel, '');
}
const conn = this._client;
conn.sftp(async (err, sftp) => {
if (err) {
if (this._channel) {
channelShowAndAppendLine(this._channel, `SFTP Error:`);
channelShowAndAppendLine(this._channel, err.message);
}
return resolve(false);
}
const rootPathExist = await this.isExist(sftp, remoteRootPath);
if (rootPathExist) {
const overwriteOption =
await vscode.window.showInformationMessage(
`${remoteRootPath} exists, overwrite?`, 'Yes', 'No',
'Cancel');
if (overwriteOption === 'Cancel') {
if (this._channel) {
channelShowAndAppendLine(
this._channel, 'Device upload cancelled.');
}
vscode.window.showWarningMessage('Device upload cancelled.');
return resolve(true);
}
if (overwriteOption === 'No') {
const raspiPathOption: vscode.InputBoxOptions = {
value: 'IoTProject',
prompt: `Please input Raspberry Pi path here.`,
ignoreFocusOut: true
};
let raspiPath =
await vscode.window.showInputBox(raspiPathOption);
if (!raspiPath) {
return false;
}
raspiPath = raspiPath || 'IoTProject';
const res = await this.upload(filePath, raspiPath);
return resolve(res);
}
const rmDirRes = await this.shell(`rm -rf ${remoteRootPath}`);
if (!rmDirRes) {
if (this._channel) {
channelShowAndAppendLine(
this._channel,
`Directory Error: remove ${remoteRootPath} failed.`);
}
return resolve(false);
}
}
const rootPathCreated = await this.ensureDir(sftp, remoteRootPath);
if (!rootPathCreated) {
if (this._channel) {
channelShowAndAppendLine(
this._channel, `Directory Error: ${remoteRootPath}`);
channelShowAndAppendLine(this._channel, err);
}
return resolve(false);
}
for (const file of files) {
const res = await this.uploadSingleFile(
sftp, file, rootPath, remoteRootPath);
if (!res) {
return resolve(false);
}
}
return resolve(true);
});
});
}
private async isExist(sftp: ssh2.SFTPWrapper, remotePath: string): Promise<boolean> {
return new Promise(
(resolve: (value: boolean) => void) => {
sftp.readdir(remotePath, (err) => {
if (err) {
return resolve(false);
}
return resolve(true);
});
});
}
private async ensureDir(sftp: ssh2.SFTPWrapper, remotePath: string): Promise<boolean> {
return new Promise(
// eslint-disable-next-line no-async-promise-executor
async (
resolve: (value: boolean) => void) => {
const dirExist = await this.isExist(sftp, remotePath);
if (!dirExist) {
sftp.mkdir(remotePath, async err => {
if (err) {
return resolve(false);
}
return resolve(true);
});
}
return resolve(true);
});
}
private async uploadSingleFile(sftp: ssh2.SFTPWrapper, filePath: string, rootPath: string, remoteRootPath: string): Promise<boolean> {
return new Promise(
// eslint-disable-next-line no-async-promise-executor
async (
resolve: (value: boolean) => void) => {
const relativePath =
filePath.replace(/[\\/]+/g, '/').substr(rootPath.length + 1);
if (/(^|\/)node_modules(\/|$)/.test(relativePath) ||
/(^|\/).vscode(\/|$)/.test(relativePath) ||
relativePath === '.iotworkbenchproject') {
return resolve(true);
}
const remotePath =
path.join(remoteRootPath, relativePath).replace(/[\\/]+/g, '/');
if (fs.isDirectorySync(filePath)) {
const pathCreated = await this.ensureDir(sftp, remotePath);
if (!pathCreated) {
if (this._channel) {
channelShowAndAppendLine(
this._channel, `Directory Error: ${relativePath}`);
}
return resolve(false);
}
return resolve(true);
} else {
sftp.fastPut(filePath, remotePath, err => {
if (err) {
if (this._channel) {
channelShowAndAppendLine(
this._channel, `File Error: ${relativePath}`);
}
return resolve(false);
}
if (this._channel) {
channelShowAndAppendLine(
this._channel, `File Uploaded: ${relativePath}`);
}
return resolve(true);
});
}
});
}
async shell(command: string, timeout?: number): Promise<boolean> {
return new Promise(
(resolve: (value: boolean) => void) => {
if (!this._connected) {
return resolve(false);
}
let timeoutCounter: NodeJS.Timer;
if (timeout) {
timeoutCounter = setTimeout(() => {
return resolve(false);
}, timeout);
}
const conn = this._client;
conn.shell((err, stream) => {
if (err) {
if (this._channel) {
channelShowAndAppendLine(this._channel, `Shell Error:`);
channelShowAndAppendLine(this._channel, err.message);
}
return resolve(false);
}
if (this._channel) {
channelShowAndAppendLine(this._channel, '');
}
const conn = this._client;
conn.sftp(async (err, sftp) => {
if (err) {
if (this._channel) {
channelShowAndAppendLine(this._channel, `SFTP Error:`);
channelShowAndAppendLine(this._channel, err.message);
}
return resolve(false);
}
const rootPathExist = await this.isExist(sftp, remoteRootPath);
if (rootPathExist) {
const overwriteOption =
await vscode.window.showInformationMessage(
`${remoteRootPath} exists, overwrite?`, 'Yes', 'No',
'Cancel');
if (overwriteOption === 'Cancel') {
stream
.on('close',
() => {
clearTimeout(timeoutCounter);
if (this._channel) {
channelShowAndAppendLine(
this._channel, 'Device upload cancelled.');
channelShowAndAppendLine(this._channel, '');
}
vscode.window.showWarningMessage('Device upload cancelled.');
return resolve(true);
}
if (overwriteOption === 'No') {
const raspiPathOption: vscode.InputBoxOptions = {
value: 'IoTProject',
prompt: `Please input Raspberry Pi path here.`,
ignoreFocusOut: true
};
let raspiPath =
await vscode.window.showInputBox(raspiPathOption);
if (!raspiPath) {
return false;
}
raspiPath = raspiPath || 'IoTProject';
const res = await this.upload(filePath, raspiPath);
return resolve(res);
}
const rmDirRes = await this.shell(`rm -rf ${remoteRootPath}`);
if (!rmDirRes) {
})
.on('data',
(data: string|Buffer) => {
if (this._channel) {
channelShowAndAppendLine(
this._channel,
`Directory Error: remove ${remoteRootPath} failed.`);
const output = data.toString().replace(
// eslint-disable-next-line no-control-regex
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
'');
this._channel.append(output);
}
return resolve(false);
}
}
const rootPathCreated = await this.ensureDir(sftp, remoteRootPath);
if (!rootPathCreated) {
})
.stderr.on('data', (data: string|Buffer) => {
if (this._channel) {
channelShowAndAppendLine(
this._channel, `Directory Error: ${remoteRootPath}`);
channelShowAndAppendLine(this._channel, err);
const output = data.toString().replace(
// eslint-disable-next-line no-control-regex
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
'');
this._channel.append(output);
}
return resolve(false);
}
for (const file of files) {
const res = await this.uploadSingleFile(
sftp, file, rootPath, remoteRootPath);
if (!res) {
return resolve(false);
}
}
return resolve(true);
});
});
}
private async isExist(sftp: ssh2.SFTPWrapper, remotePath: string) {
return new Promise(
(resolve: (value: boolean) => void,
reject: (reason: boolean) => void) => {
sftp.readdir(remotePath, (err, list) => {
if (err) {
return resolve(false);
}
return resolve(true);
});
});
}
private async ensureDir(sftp: ssh2.SFTPWrapper, remotePath: string) {
return new Promise(
async (
resolve: (value: boolean) => void,
reject: (reason: boolean) => void) => {
const dirExist = await this.isExist(sftp, remotePath);
if (!dirExist) {
sftp.mkdir(remotePath, async err => {
if (err) {
return resolve(false);
}
return resolve(true);
});
}
return resolve(true);
stream.setWindow(10, 500, 10, 100);
stream.end(command + '\nexit\n');
});
});
}
private async uploadSingleFile(
sftp: ssh2.SFTPWrapper, filePath: string, rootPath: string,
remoteRootPath: string) {
return new Promise(
async (
resolve: (value: boolean) => void,
reject: (reason: boolean) => void) => {
const relativePath =
filePath.replace(/[\\\/]+/g, '/').substr(rootPath.length + 1);
if (/(^|\/)node_modules(\/|$)/.test(relativePath) ||
/(^|\/).vscode(\/|$)/.test(relativePath) ||
relativePath === '.iotworkbenchproject') {
return resolve(true);
}
const remotePath =
path.join(remoteRootPath, relativePath).replace(/[\\\/]+/g, '/');
if (fs.isDirectorySync(filePath)) {
const pathCreated = await this.ensureDir(sftp, remotePath);
if (!pathCreated) {
if (this._channel) {
channelShowAndAppendLine(
this._channel, `Directory Error: ${relativePath}`);
}
return resolve(false);
}
return resolve(true);
} else {
sftp.fastPut(filePath, remotePath, err => {
if (err) {
if (this._channel) {
channelShowAndAppendLine(
this._channel, `File Error: ${relativePath}`);
}
return resolve(false);
}
if (this._channel) {
channelShowAndAppendLine(
this._channel, `File Uploaded: ${relativePath}`);
}
return resolve(true);
});
}
});
}
async shell(command: string, timeout?: number) {
return new Promise(
(resolve: (value: boolean) => void,
reject: (reason: boolean) => void) => {
if (!this._connected) {
return resolve(false);
}
let timeoutCounter: NodeJS.Timer;
if (timeout) {
timeoutCounter = setTimeout(() => {
return resolve(false);
}, timeout);
}
const conn = this._client;
conn.shell((err, stream) => {
if (err) {
if (this._channel) {
channelShowAndAppendLine(this._channel, `Shell Error:`);
channelShowAndAppendLine(this._channel, err.message);
}
return resolve(false);
}
if (this._channel) {
channelShowAndAppendLine(this._channel, '');
}
stream
.on('close',
() => {
clearTimeout(timeoutCounter);
if (this._channel) {
channelShowAndAppendLine(this._channel, '');
}
return resolve(true);
})
.on('data',
(data: string|Buffer) => {
if (this._channel) {
const output = data.toString().replace(
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
'');
this._channel.append(output);
}
})
.stderr.on('data', (data: string|Buffer) => {
if (this._channel) {
const output = data.toString().replace(
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
'');
this._channel.append(output);
}
});
stream.setWindow(10, 500, 10, 100);
stream.end(command + '\nexit\n');
});
});
}
async close() {
async close(): Promise<boolean> {
this._client.end();
return Promise.resolve(true);
}

Просмотреть файл

@ -1,17 +1,17 @@
import {ResourceManagementClient} from 'azure-arm-resource';
import { ResourceManagementClient } from 'azure-arm-resource';
import * as fs from 'fs-plus';
import {Guid} from 'guid-typescript';
import { Guid } from 'guid-typescript';
import * as path from 'path';
import * as vscode from 'vscode';
import {AzureComponentsStorage, FileNames, ScaffoldType} from '../constants';
import {channelPrintJsonObject, channelShowAndAppendLine} from '../utils';
import { AzureComponentsStorage, FileNames, ScaffoldType } from '../constants';
import { channelPrintJsonObject, channelShowAndAppendLine } from '../utils';
import {AzureComponentConfig, AzureConfigFileHandler, AzureConfigs, ComponentInfo, Dependency, DependencyConfig, DependencyType} from './AzureComponentConfig';
import {ARMTemplate, AzureUtility} from './AzureUtility';
import {Component, ComponentType} from './Interfaces/Component';
import {Deployable} from './Interfaces/Deployable';
import {Provisionable} from './Interfaces/Provisionable';
import { AzureComponentConfig, AzureConfigFileHandler, AzureConfigs, ComponentInfo, Dependency, DependencyConfig, DependencyType } from './AzureComponentConfig';
import { ARMTemplate, AzureUtility } from './AzureUtility';
import { Component, ComponentType } from './Interfaces/Component';
import { Deployable } from './Interfaces/Deployable';
import { Provisionable } from './Interfaces/Provisionable';
enum StreamAnalyticsAction {
Start = 1,
@ -34,17 +34,17 @@ export class StreamAnalyticsJob implements Component, Provisionable,
private azureClient: ResourceManagementClient|null = null;
private catchedStreamAnalyticsList: Array<{name: string}> = [];
private async initAzureClient() {
private async initAzureClient(): Promise<ResourceManagementClient> {
if (this.subscriptionId && this.resourceGroup &&
this.streamAnalyticsJobName && this.azureClient) {
return this.azureClient;
}
const componentConfig = await this.azureConfigHandler.getComponentById(
ScaffoldType.Workspace, this.id);
ScaffoldType.Workspace, this.id);
if (!componentConfig) {
throw new Error(
`Cannot find Azure Stream Analytics component with id ${this.id}.`);
`Cannot find Azure Stream Analytics component with id ${this.id}.`);
}
const componentInfo = componentConfig.componentInfo;
@ -69,16 +69,17 @@ export class StreamAnalyticsJob implements Component, Provisionable,
return azureClient;
}
private async callAction(action: StreamAnalyticsAction) {
private async callAction(action: StreamAnalyticsAction): Promise<unknown> {
const actionResource = `/subscriptions/${
this.subscriptionId}/resourceGroups/${
this.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs/${
this.streamAnalyticsJobName}/${
StreamAnalyticsAction[action].toLowerCase()}?api-version=2015-10-01`;
this.subscriptionId}/resourceGroups/${
this.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs/${
this.streamAnalyticsJobName}/${
StreamAnalyticsAction[action].toLowerCase()}?api-version=2015-10-01`;
await AzureUtility.postRequest(actionResource);
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
const timeout = setTimeout(() => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
clearTimeout(timer);
return resolve(false);
}, 10 * 60 * 1000);
@ -96,35 +97,35 @@ export class StreamAnalyticsJob implements Component, Provisionable,
});
}
private getStreamAnalyticsByNameFromCache(name: string) {
private getStreamAnalyticsByNameFromCache(name: string): {name: string}|undefined {
return this.catchedStreamAnalyticsList.find(item => item.name === name);
}
private async getStreamAnalyticsInResourceGroup() {
private async getStreamAnalyticsInResourceGroup(): Promise<vscode.QuickPickItem[]>{
const resource = `/subscriptions/${
AzureUtility.subscriptionId}/resourceGroups/${
AzureUtility
.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs?api-version=2015-10-01`;
AzureUtility.subscriptionId}/resourceGroups/${
AzureUtility
.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs?api-version=2015-10-01`;
const asaListRes = await AzureUtility.getRequest(resource) as
{value: Array<{name: string, properties: {jobState: string}}>};
{value: Array<{name: string; properties: {jobState: string}}>};
const asaList: vscode.QuickPickItem[] =
[{label: '$(plus) Create New Stream Analytics Job', description: ''}];
[{ label: '$(plus) Create New Stream Analytics Job', description: '' }];
for (const item of asaListRes.value) {
asaList.push({label: item.name, description: item.properties.jobState});
asaList.push({ label: item.name, description: item.properties.jobState });
}
this.catchedStreamAnalyticsList = asaListRes.value;
return asaList;
}
get id() {
get id(): string {
return this.componentId;
}
constructor(
queryPath: string, context: vscode.ExtensionContext, projectRoot: string,
channel: vscode.OutputChannel,
dependencyComponents: Dependency[]|null = null) {
queryPath: string, context: vscode.ExtensionContext, projectRoot: string,
channel: vscode.OutputChannel,
dependencyComponents: Dependency[]|null = null) {
this.queryPath = queryPath;
this.componentType = ComponentType.StreamAnalyticsJob;
this.channel = channel;
@ -134,8 +135,8 @@ export class StreamAnalyticsJob implements Component, Provisionable,
this.extensionContext = context;
if (dependencyComponents && dependencyComponents.length > 0) {
dependencyComponents.forEach(
dependency => this.dependencies.push(
{id: dependency.component.id, type: dependency.type}));
dependency => this.dependencies.push(
{ id: dependency.component.id, type: dependency.type }));
}
}
@ -151,8 +152,8 @@ export class StreamAnalyticsJob implements Component, Provisionable,
async load(): Promise<boolean> {
const azureConfigFilePath = path.join(
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
this.projectRootPath, AzureComponentsStorage.folderName,
AzureComponentsStorage.fileName);
if (!fs.existsSync(azureConfigFilePath)) {
return false;
@ -163,7 +164,7 @@ export class StreamAnalyticsJob implements Component, Provisionable,
try {
azureConfigs = JSON.parse(fs.readFileSync(azureConfigFilePath, 'utf8'));
const asaConfig = azureConfigs.componentConfigs.find(
config => config.type === this.componentType);
config => config.type === this.componentType);
if (asaConfig) {
this.componentId = asaConfig.id;
this.dependencies = asaConfig.dependencies;
@ -188,7 +189,7 @@ export class StreamAnalyticsJob implements Component, Provisionable,
return;
}
await this.azureConfigHandler.updateComponent(
type, asaComponentIndex, componentInfo);
type, asaComponentIndex, componentInfo);
} else {
const newAsaConfig: AzureComponentConfig = {
id: this.id,
@ -206,8 +207,8 @@ export class StreamAnalyticsJob implements Component, Provisionable,
const asaList = this.getStreamAnalyticsInResourceGroup();
const asaNameChoose = await vscode.window.showQuickPick(
asaList,
{placeHolder: 'Select Stream Analytics Job', ignoreFocusOut: true});
asaList,
{ placeHolder: 'Select Stream Analytics Job', ignoreFocusOut: true });
if (!asaNameChoose) {
return false;
}
@ -217,10 +218,10 @@ export class StreamAnalyticsJob implements Component, Provisionable,
if (!asaNameChoose.description) {
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Creating Stream Analytics Job...');
this.channel, 'Creating Stream Analytics Job...');
}
const asaArmTemplatePath = this.extensionContext.asAbsolutePath(path.join(
FileNames.resourcesFolderName, 'arm', 'streamanalytics.json'));
FileNames.resourcesFolderName, 'arm', 'streamanalytics.json'));
const asaArmTemplate =
JSON.parse(fs.readFileSync(asaArmTemplatePath, 'utf8')) as
ARMTemplate;
@ -238,7 +239,7 @@ export class StreamAnalyticsJob implements Component, Provisionable,
} else {
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Creating Stream Analytics Job...');
this.channel, 'Creating Stream Analytics Job...');
}
streamAnalyticsJobName = asaNameChoose.label;
const asaDetail =
@ -250,114 +251,114 @@ export class StreamAnalyticsJob implements Component, Provisionable,
for (const dependency of this.dependencies) {
const componentConfig = await this.azureConfigHandler.getComponentById(
scaffoldType, dependency.id);
scaffoldType, dependency.id);
if (!componentConfig) {
throw new Error(`Cannot find component with id ${dependency.id}.`);
}
if (dependency.type === DependencyType.Input) {
switch (componentConfig.type) {
case 'IoTHub': {
if (!componentConfig.componentInfo) {
return false;
}
const iotHubConnectionString =
case 'IoTHub': {
if (!componentConfig.componentInfo) {
return false;
}
const iotHubConnectionString =
componentConfig.componentInfo.values.iotHubConnectionString;
let iotHubName = '';
let iotHubKeyName = '';
let iotHubKey = '';
const iotHubNameMatches =
let iotHubName = '';
let iotHubKeyName = '';
let iotHubKey = '';
const iotHubNameMatches =
iotHubConnectionString.match(/HostName=(.*?)\./);
const iotHubKeyMatches =
const iotHubKeyMatches =
iotHubConnectionString.match(/SharedAccessKey=(.*?)(;|$)/);
const iotHubKeyNameMatches =
const iotHubKeyNameMatches =
iotHubConnectionString.match(/SharedAccessKeyName=(.*?)(;|$)/);
if (iotHubNameMatches) {
iotHubName = iotHubNameMatches[1];
}
if (iotHubKeyMatches) {
iotHubKey = iotHubKeyMatches[1];
}
if (iotHubKeyNameMatches) {
iotHubKeyName = iotHubKeyNameMatches[1];
}
if (iotHubNameMatches) {
iotHubName = iotHubNameMatches[1];
}
if (iotHubKeyMatches) {
iotHubKey = iotHubKeyMatches[1];
}
if (iotHubKeyNameMatches) {
iotHubKeyName = iotHubKeyNameMatches[1];
}
if (!iotHubName || !iotHubKeyName || !iotHubKey) {
throw new Error('Cannot parse IoT Hub connection string.');
}
if (!iotHubName || !iotHubKeyName || !iotHubKey) {
throw new Error('Cannot parse IoT Hub connection string.');
}
const asaIoTHubArmTemplatePath =
const asaIoTHubArmTemplatePath =
this.extensionContext.asAbsolutePath(path.join(
FileNames.resourcesFolderName, 'arm',
'streamanalytics-input-iothub.json'));
const asaIoTHubArmTemplate =
FileNames.resourcesFolderName, 'arm',
'streamanalytics-input-iothub.json'));
const asaIoTHubArmTemplate =
JSON.parse(fs.readFileSync(asaIoTHubArmTemplatePath, 'utf8')) as
ARMTemplate;
const asaIotHubArmParameters = {
streamAnalyticsJobName: {value: streamAnalyticsJobName},
inputName: {value: `iothub-${componentConfig.id}`},
iotHubName: {value: iotHubName},
iotHubKeyName: {value: iotHubKeyName},
iotHubKey: {value: iotHubKey}
};
const asaIotHubArmParameters = {
streamAnalyticsJobName: { value: streamAnalyticsJobName },
inputName: { value: `iothub-${componentConfig.id}` },
iotHubName: { value: iotHubName },
iotHubKeyName: { value: iotHubKeyName },
iotHubKey: { value: iotHubKey }
};
const asaInputDeploy = await AzureUtility.deployARMTemplate(
asaIoTHubArmTemplate, asaIotHubArmParameters);
if (!asaInputDeploy) {
throw new Error('Provision Stream Analytics Job failed.');
}
const asaInputDeploy = await AzureUtility.deployARMTemplate(
asaIoTHubArmTemplate, asaIotHubArmParameters);
if (!asaInputDeploy) {
throw new Error('Provision Stream Analytics Job failed.');
}
break;
}
default: {
throw new Error(
`Not supported ASA input type: ${componentConfig.type}.`);
}
break;
}
default: {
throw new Error(
`Not supported ASA input type: ${componentConfig.type}.`);
}
}
} else {
switch (componentConfig.type) {
case 'CosmosDB': {
if (!componentConfig.componentInfo) {
return false;
}
const cosmosDBAccountName =
case 'CosmosDB': {
if (!componentConfig.componentInfo) {
return false;
}
const cosmosDBAccountName =
componentConfig.componentInfo.values.cosmosDBAccountName;
const cosmosDBDatabase =
const cosmosDBDatabase =
componentConfig.componentInfo.values.cosmosDBDatabase;
const cosmosDBCollection =
const cosmosDBCollection =
componentConfig.componentInfo.values.cosmosDBCollection;
if (!cosmosDBAccountName || !cosmosDBDatabase ||
if (!cosmosDBAccountName || !cosmosDBDatabase ||
!cosmosDBCollection) {
throw new Error('Cannot get Cosmos DB connection information.');
}
throw new Error('Cannot get Cosmos DB connection information.');
}
const asaCosmosDBArmTemplatePath =
const asaCosmosDBArmTemplatePath =
this.extensionContext.asAbsolutePath(path.join(
FileNames.resourcesFolderName, 'arm',
'streamanalytics-output-cosmosdb.json'));
const asaCosmosDBArmTemplate =
FileNames.resourcesFolderName, 'arm',
'streamanalytics-output-cosmosdb.json'));
const asaCosmosDBArmTemplate =
JSON.parse(fs.readFileSync(
asaCosmosDBArmTemplatePath, 'utf8')) as ARMTemplate;
const asaCosmosArmParameters = {
streamAnalyticsJobName: {value: streamAnalyticsJobName},
outputName: {value: `cosmosdb-${componentConfig.id}`},
cosmosDBName: {value: cosmosDBAccountName},
cosmosDBDatabase: {value: cosmosDBDatabase},
cosmosDBCollection: {value: cosmosDBCollection}
};
asaCosmosDBArmTemplatePath, 'utf8')) as ARMTemplate;
const asaCosmosArmParameters = {
streamAnalyticsJobName: { value: streamAnalyticsJobName },
outputName: { value: `cosmosdb-${componentConfig.id}` },
cosmosDBName: { value: cosmosDBAccountName },
cosmosDBDatabase: { value: cosmosDBDatabase },
cosmosDBCollection: { value: cosmosDBCollection }
};
const asaOutputDeploy = await AzureUtility.deployARMTemplate(
asaCosmosDBArmTemplate, asaCosmosArmParameters);
if (!asaOutputDeploy) {
throw new Error('Provision Stream Analytics Job failed.');
}
const asaOutputDeploy = await AzureUtility.deployARMTemplate(
asaCosmosDBArmTemplate, asaCosmosArmParameters);
if (!asaOutputDeploy) {
throw new Error('Provision Stream Analytics Job failed.');
}
break;
}
default: {
throw new Error(
`Not supported ASA output type: ${componentConfig.type}.`);
}
break;
}
default: {
throw new Error(
`Not supported ASA output type: ${componentConfig.type}.`);
}
}
}
}
@ -372,7 +373,7 @@ export class StreamAnalyticsJob implements Component, Provisionable,
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Stream Analytics Job provision succeeded.');
this.channel, 'Stream Analytics Job provision succeeded.');
}
return true;
}
@ -384,7 +385,7 @@ export class StreamAnalyticsJob implements Component, Provisionable,
let stopPending: NodeJS.Timer|null = null;
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Stopping Stream Analytics Job...');
this.channel, 'Stopping Stream Analytics Job...');
stopPending = setInterval(() => {
this.channel.append('.');
}, 1000);
@ -393,7 +394,7 @@ export class StreamAnalyticsJob implements Component, Provisionable,
if (!jobStopped) {
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Stop Stream Analytics Job failed.');
this.channel, 'Stop Stream Analytics Job failed.');
}
return false;
} else {
@ -401,44 +402,44 @@ export class StreamAnalyticsJob implements Component, Provisionable,
clearInterval(stopPending);
channelShowAndAppendLine(this.channel, '.');
channelShowAndAppendLine(
this.channel, 'Stop Stream Analytics Job succeeded.');
this.channel, 'Stop Stream Analytics Job succeeded.');
}
}
const resourceId = `/subscriptions/${this.subscriptionId}/resourceGroups/${
this.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs/${
this.streamAnalyticsJobName}/transformations/Transformation`;
this.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs/${
this.streamAnalyticsJobName}/transformations/Transformation`;
const apiVersion = '2015-10-01';
if (!fs.existsSync(this.queryPath)) {
throw new Error(`Cannot find query file at ${this.queryPath}`);
}
const query = fs.readFileSync(this.queryPath, 'utf8');
const parameters = {properties: {streamingUnits: 1, query}};
const parameters = { properties: { streamingUnits: 1, query } };
let deployPending: NodeJS.Timer|null = null;
try {
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Deploying Stream Analytics Job...');
this.channel, 'Deploying Stream Analytics Job...');
deployPending = setInterval(() => {
this.channel.append('.');
}, 1000);
}
const deployment = await azureClient.resources.createOrUpdateById(
resourceId, apiVersion, parameters);
resourceId, apiVersion, parameters);
if (this.channel && deployPending) {
clearInterval(deployPending);
channelShowAndAppendLine(this.channel, '.');
channelPrintJsonObject(this.channel, deployment);
channelShowAndAppendLine(
this.channel, 'Stream Analytics Job query deploy succeeded.');
this.channel, 'Stream Analytics Job query deploy succeeded.');
}
// Start Job
let startPending: NodeJS.Timer|null = null;
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Starting Stream Analytics Job...');
this.channel, 'Starting Stream Analytics Job...');
startPending = setInterval(() => {
this.channel.append('.');
}, 1000);
@ -447,14 +448,14 @@ export class StreamAnalyticsJob implements Component, Provisionable,
if (!jobStarted) {
if (this.channel) {
channelShowAndAppendLine(
this.channel, 'Start Stream Analytics Job failed.');
this.channel, 'Start Stream Analytics Job failed.');
}
return false;
} else if (this.channel && startPending) {
clearInterval(startPending);
channelShowAndAppendLine(this.channel, '.');
channelShowAndAppendLine(
this.channel, 'Start Stream Analytics Job succeeded.');
this.channel, 'Start Stream Analytics Job succeeded.');
}
} catch (error) {
if (this.channel && deployPending) {
@ -466,20 +467,21 @@ export class StreamAnalyticsJob implements Component, Provisionable,
return true;
}
async stop() {
async stop(): Promise<unknown> {
return await this.callAction(StreamAnalyticsAction.Stop);
}
async start() {
async start(): Promise<unknown> {
return await this.callAction(StreamAnalyticsAction.Start);
}
async getState() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async getState(): Promise<any> {
const azureClient = this.azureClient || await this.initAzureClient();
const resourceId = `/subscriptions/${this.subscriptionId}/resourceGroups/${
this.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs/${
this.streamAnalyticsJobName}`;
this.resourceGroup}/providers/Microsoft.StreamAnalytics/streamingjobs/${
this.streamAnalyticsJobName}`;
const apiVersion = '2015-10-01';
const res = await azureClient.resources.getById(resourceId, apiVersion);
return res.properties.jobState;

Просмотреть файл

@ -7,13 +7,13 @@ import * as vscode from 'vscode';
import * as utils from './utils';
import * as path from 'path';
import {TelemetryContext} from './telemetry';
import {ScaffoldType, PlatformType} from './constants';
import {RemoteExtension} from './Models/RemoteExtension';
import {IoTWorkbenchProjectBase, OpenScenario} from './Models/IoTWorkbenchProjectBase';
import {ProjectHostType} from './Models/Interfaces/ProjectHostType';
import {configExternalCMakeProjectToIoTContainerProject} from './utils';
import {CancelOperationError} from './CancelOperationError';
import { TelemetryContext } from './telemetry';
import { ScaffoldType, PlatformType } from './constants';
import { RemoteExtension } from './Models/RemoteExtension';
import { IoTWorkbenchProjectBase, OpenScenario } from './Models/IoTWorkbenchProjectBase';
import { ProjectHostType } from './Models/Interfaces/ProjectHostType';
import { configExternalCMakeProjectToIoTContainerProject } from './utils';
import { CancelOperationError } from './CancelOperationError';
const impor = require('impor')(__dirname);
const ioTWorkspaceProjectModule = impor('./Models/IoTWorkspaceProject') as
@ -24,8 +24,8 @@ const ioTContainerizedProjectModule =
export class ProjectEnvironmentConfiger {
async configureCmakeProjectEnvironment(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> {
// Only configure project when not in remote environment
const isLocal = RemoteExtension.checkLocalBeforeRunCommand(context);
if (!isLocal) {
@ -40,34 +40,34 @@ export class ProjectEnvironmentConfiger {
}
await vscode.window.withProgress(
{
title: 'CMake Project development container configuration',
location: vscode.ProgressLocation.Window,
},
async () => {
await ProjectEnvironmentConfiger
.configureProjectEnvironmentAsPlatform(
context, channel, telemetryContext,
PlatformType.EmbeddedLinux, projectRootPath, scaffoldType);
{
title: 'CMake Project development container configuration',
location: vscode.ProgressLocation.Window,
},
async () => {
await ProjectEnvironmentConfiger
.configureProjectEnvironmentAsPlatform(
context, channel, telemetryContext,
PlatformType.EmbeddedLinux, projectRootPath, scaffoldType);
const message =
const message =
`Successfully configured development container for CMake project.`;
utils.channelShowAndAppendLine(channel, message);
vscode.window.showInformationMessage(message);
});
utils.channelShowAndAppendLine(channel, message);
vscode.window.showInformationMessage(message);
});
return;
}
static async configureProjectEnvironmentAsPlatform(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, platform: PlatformType,
projectFileRootPath: string, scaffoldType: ScaffoldType): Promise<void> {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, platform: PlatformType,
projectFileRootPath: string, scaffoldType: ScaffoldType): Promise<void> {
let project;
if (platform === PlatformType.Arduino) {
// Verify it is an iot workbench Arduino project
const projectHostType = await IoTWorkbenchProjectBase.getProjectType(
scaffoldType, projectFileRootPath);
scaffoldType, projectFileRootPath);
if (projectHostType !== ProjectHostType.Workspace) {
const message =
`This is not an iot workbench Arduino project. You cannot configure it as Arduino platform.`;
@ -77,7 +77,7 @@ export class ProjectEnvironmentConfiger {
const projectRootPath = path.join(projectFileRootPath, '..');
project = new ioTWorkspaceProjectModule.IoTWorkspaceProject(
context, channel, telemetryContext, projectRootPath);
context, channel, telemetryContext, projectRootPath);
if (!project) {
// Ensure the project is correctly open.
await utils.properlyOpenIoTWorkspaceProject(telemetryContext);
@ -90,7 +90,7 @@ export class ProjectEnvironmentConfiger {
await RemoteExtension.checkRemoteExtension();
project = new ioTContainerizedProjectModule.IoTContainerizedProject(
context, channel, telemetryContext, projectFileRootPath);
context, channel, telemetryContext, projectFileRootPath);
} else {
throw new Error('unsupported platform');
}
@ -99,9 +99,9 @@ export class ProjectEnvironmentConfiger {
// Add configuration files
await project.configureProjectEnvironmentCore(
projectFileRootPath, scaffoldType);
projectFileRootPath, scaffoldType);
await project.openProject(
scaffoldType, false, OpenScenario.configureProject);
scaffoldType, false, OpenScenario.configureProject);
}
}

Просмотреть файл

@ -4,11 +4,11 @@ import * as vscode from 'vscode';
import * as fs from 'fs';
export class WorkbenchExtension {
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static extension: vscode.Extension<any>|undefined;
static getExtension(context: vscode.ExtensionContext):
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
vscode.Extension<any>|undefined {
if (!WorkbenchExtension.extension) {
const extensionId = WorkbenchExtension.getExtensionId(context);

Просмотреть файл

@ -2,8 +2,8 @@
// Licensed under the MIT License.
'use strict';
import {FileNames} from './constants';
import {Board} from './Models/Interfaces/Board';
import { FileNames } from './constants';
import { Board } from './Models/Interfaces/Board';
import * as path from 'path';
interface BoardList {
@ -25,14 +25,14 @@ export class BoardProvider {
this.boardFolderPath = boardFolderPath;
}
get list() {
get list(): Board[] {
const boardList =
path.join(this.boardFolderPath, FileNames.boardListFileName);
const boardsJson: BoardList = require(boardList);
return boardsJson.boards;
}
find(option: BoardOption) {
find(option: BoardOption): Board|undefined {
const list = this.list;
return list.find(board => {
for (const key of Object.keys(option)) {
@ -49,8 +49,8 @@ export class BoardProvider {
if (key === 'vendorId' || key === 'productId') {
const optionId = typeof optionProperty.value === 'number' ?
optionProperty.value :
Number(`0x${optionProperty.value}`);
optionProperty.value :
Number(`0x${optionProperty.value}`);
const boardId = Number(`0x${boardProperty.value}`);
if (optionId !== boardId) {
return false;

Просмотреть файл

@ -0,0 +1,9 @@
import { InternalError } from './InternalError';
export class BoardNotFoundError extends InternalError {
constructor (board: string) {
const errorMessage = `${board} is not found in board list.`;
super(errorMessage);
this.name = 'BoardNotFoundError';
}
}

119
src/common/Error/Error.ts Normal file
Просмотреть файл

@ -0,0 +1,119 @@
import { ExtensionName } from '../../Models/Interfaces/Api';
// User Error
/**
* Error class used when user cancel operation.
*/
export class OperationCanceledError extends Error {
constructor (message: string) {
super(`Operation cancelled: ${message}`);
this.name = 'CancelOperationError';
}
}
/**
* Error class used when remote environment does not support a operation.
*/
export class RemoteEnvNotSupportedError extends Error {
/**
* Construct a remote environemt not supported error.
* @param suggestedOperation message of the recommended operation for user
*/
constructor (suggestedOperation: string) {
super(`The operation is not supported to be run in remote environment. ${
suggestedOperation}`);
this.name = 'RemoteEnvNotSupportedError';
}
}
/**
* Error class used when resource (file, directory, etc) is not found
*/
export class ResourceNotFoundError extends Error {
/**
* Construct a resource not found error.
* @param resource The name of resource that is missing
* @param suggestedOperation Recommended operation for user.
*/
constructor (
operation: string, resource: string, suggestedOperation?: string) {
super(`Failed to ${operation}: Unable to find ${resource}. ${
suggestedOperation}`);
this.name = 'ResourceNotFoundError';
}
}
export class DependentExtensionNotFoundError extends Error {
constructor (extension: ExtensionName) {
super(`Dependent extension ${
extension} is not found. Please install it from Marketplace.`);
this.name = 'DependentExtensionNotFound';
}
}
export class WorkspaceNotOpenError extends Error {
constructor () {
super(
'You have not yet opened a folder in Visual Studio Code. Please select a folder first.');
this.name = 'WorkspaceNotOpenError';
}
}
export class PrerequisiteNotMetError extends Error {
constructor (operation: string, suggestedOperation?: string) {
super(`Failed to ${operation} because prerequisite is not met. ${
suggestedOperation}`);
this.name = 'PrerequisiteNotMetError';
}
}
// System Error
export class OperationFailedError extends Error {
constructor (operation: string, suggestedOperation?: string) {
super(`Failed to ${operation}. ${suggestedOperation}`);
this.name = 'OperationFailedError';
}
}
export class BoardNotFoundError extends Error {
constructor (board: string) {
super(`${board} is not found in board list.`);
this.name = 'BoardNotFoundError';
}
}
export class ConfigNotFoundError extends Error {
constructor (configKey: string, suggestedOperation?: string) {
super(`Failed to get ${configKey} from workspace settings. ${
suggestedOperation}`);
this.name = 'ConfigNotFoundError';
}
}
export class TypeNotSupportedError extends Error {
constructor (typeName: string, typeValue: string) {
super(`Unsupported ${typeName}: ${typeValue}`);
this.name = 'TypeNotSupportedError';
}
}
export class InternalError extends Error {
constructor (message: string) {
super(`Internal Error: ${message}.`);
this.name = 'InternalError';
}
}
export class ArgumentEmptyOrNullError extends Error {
constructor (argument: string, suggestedOperation?: string) {
super(`Argument ${argument} is empty or null. ${suggestedOperation}`);
this.name = 'ArgumentEmptyOrNullError';
}
}
export class ArgumentInvalidError extends Error {
constructor (argument: string, suggestedOperation?: string) {
super(`${argument} is invalid. ${suggestedOperation}`);
this.name = 'ArgumentInvalidError';
}
}

Просмотреть файл

@ -0,0 +1,24 @@
export class InternalError extends Error {
constructor (errorMessage: string) {
super(`Internal Error: ${errorMessage}.`);
this.name = 'InternalError';
}
}
/*
- BoardNotFoundError
- TypeNotSupportedError
*/
export class UserError extends Error {
constructor (operation: string, suggestedOperation?: string) {
super(`Failed to ${operation}. ${suggestedOperation}`);
this.name = 'UserError';
}
}
export class OperationCanceledError extends UserError {
constructor (message: string) {
super(`Operation cancelled: ${message}`);
this.name = 'CancelOperationError';
}
}

Просмотреть файл

@ -0,0 +1,8 @@
import { InternalError } from './InternalError';
export class TypeNotSupportedError extends InternalError {
constructor (typeName: string, typeValue: string) {
super(`Unsupported ${typeName}: ${typeValue}`);
this.name = 'TypeNotSupportedError';
}
}

Просмотреть файл

@ -5,16 +5,16 @@ import * as vscode from 'vscode';
export class ConfigHandler {
static async update(
key: string, value: {}, target = vscode.ConfigurationTarget.Workspace) {
key: string, value: {}, target = vscode.ConfigurationTarget.Workspace): Promise<void> {
if (!key) {
throw new Error('Key is empty.');
}
return await vscode.workspace.getConfiguration('IoTWorkbench')
.update(key, value, target);
.update(key, value, target);
}
static get<T>(key: string) {
static get<T>(key: string): T|undefined {
if (!key) {
throw new Error('Key is empty.');
}

Просмотреть файл

@ -7,17 +7,17 @@ import * as fs from 'fs-plus';
import * as path from 'path';
import * as vscode from 'vscode';
import * as AdmZip from 'adm-zip';
import {IoTWorkbenchSettings} from './IoTSettings';
import { IoTWorkbenchSettings } from './IoTSettings';
import * as utils from './utils';
import {Board, BoardQuickPickItem} from './Models/Interfaces/Board';
import {TelemetryContext} from './telemetry';
import {FileNames} from './constants';
import {ArduinoPackageManager} from './ArduinoPackageManager';
import {BoardProvider} from './boardProvider';
import {VSCExpress} from 'vscode-express';
import {RemoteExtension} from './Models/RemoteExtension';
import {CancelOperationError} from './CancelOperationError';
import {IoTCubeCommands} from './common/Commands';
import { Board, BoardQuickPickItem } from './Models/Interfaces/Board';
import { TelemetryContext } from './telemetry';
import { FileNames } from './constants';
import { ArduinoPackageManager } from './ArduinoPackageManager';
import { BoardProvider } from './boardProvider';
import { VSCExpress } from 'vscode-express';
import { RemoteExtension } from './Models/RemoteExtension';
import { CancelOperationError } from './CancelOperationError';
import { IoTCubeCommands } from './common/Commands';
type OptionsWithUri = import('request-promise').OptionsWithUri;
@ -31,7 +31,7 @@ export class ExampleExplorer {
private static _vscexpress: VSCExpress|undefined;
private async moveTempFiles(fsPath: string) {
private async moveTempFiles(fsPath: string): Promise<boolean> {
const tempPath = path.join(fsPath, '.temp');
const tempPathList = fs.listSync(tempPath);
let examplePath: string|undefined = undefined;
@ -50,7 +50,7 @@ export class ExampleExplorer {
examplePathList.forEach(item => {
if (item !== '.' && item !== '..') {
fs.moveSync(
path.join(examplePath as string, item), path.join(fsPath, item));
path.join(examplePath as string, item), path.join(fsPath, item));
}
});
@ -58,9 +58,7 @@ export class ExampleExplorer {
return true;
}
private async downloadExamplePackage(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
url: string, fsPath: string): Promise<boolean> {
private async downloadExamplePackage(channel: vscode.OutputChannel, url: string, fsPath: string): Promise<boolean> {
const loading = setInterval(() => {
channel.append('.');
}, 1000);
@ -89,7 +87,7 @@ export class ExampleExplorer {
}
}
private async generateExampleFolder(exampleName: string) {
private async generateExampleFolder(exampleName: string): Promise<string> {
const settings = await IoTWorkbenchSettings.getInstance();
const workbench = settings.getWorkbenchPath();
@ -109,24 +107,24 @@ export class ExampleExplorer {
const workspaceFile = workspaceFiles[0]; // just pick the first one
if (fs.existsSync(workspaceFile)) {
const selection = await vscode.window.showQuickPick(
[
{
label: `Open an existing example`,
description: '',
detail: `Example exists: ${name}`
},
{
label: 'Generate a new example',
description: '',
detail: 'Create a new folder to generate the example'
}
],
[
{
ignoreFocusOut: true,
matchOnDescription: true,
matchOnDetail: true,
placeHolder: 'Select an option',
});
label: `Open an existing example`,
description: '',
detail: `Example exists: ${name}`
},
{
label: 'Generate a new example',
description: '',
detail: 'Create a new folder to generate the example'
}
],
{
ignoreFocusOut: true,
matchOnDescription: true,
matchOnDetail: true,
placeHolder: 'Select an option',
});
if (!selection) {
return '';
@ -148,7 +146,7 @@ export class ExampleExplorer {
const name = path.join(workbench, 'examples', exampleName);
if (!utils.fileExistsSync(name) && !utils.directoryExistsSync(name)) {
if (!/^([a-z0-9_]|[a-z0-9_][-a-z0-9_.]*[a-z0-9_])$/i.test(
exampleName)) {
exampleName)) {
return 'Folder name can only contain letters, numbers, "-" and ".", and cannot start or end with "-" or ".".';
}
return;
@ -175,16 +173,14 @@ export class ExampleExplorer {
return customizedPath;
}
async selectBoard(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
async selectBoard(context: vscode.ExtensionContext, telemetryContext: TelemetryContext): Promise<void> {
const isLocal = RemoteExtension.checkLocalBeforeRunCommand(context);
if (!isLocal) {
return;
}
const boardFolderPath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName));
FileNames.resourcesFolderName, FileNames.templatesFolderName));
const boardProvider = new BoardProvider(boardFolderPath);
const boardItemList: BoardQuickPickItem[] = [];
const boards = boardProvider.list.filter(board => board.exampleUrl);
@ -221,7 +217,7 @@ export class ExampleExplorer {
return;
} else {
telemetryContext.properties.board = boardSelection.label;
const board = boardProvider.find({id: boardSelection.id});
const board = boardProvider.find({ id: boardSelection.id });
if (board) {
// To avoid block example gallery, use async to install board here
@ -232,28 +228,25 @@ export class ExampleExplorer {
ExampleExplorer._vscexpress =
ExampleExplorer._vscexpress || new VSCExpress(context, 'views');
ExampleExplorer._vscexpress.open(
exampleUrl,
board.examplePageName + ' samples - Azure IoT Device Workbench',
vscode.ViewColumn.One, {
enableScripts: true,
enableCommandUris: true,
retainContextWhenHidden: true
});
exampleUrl,
board.examplePageName + ' samples - Azure IoT Device Workbench',
vscode.ViewColumn.One, {
enableScripts: true,
enableCommandUris: true,
retainContextWhenHidden: true
});
}
}
}
async initializeExample(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, name?: string, url?: string,
boardId?: string) {
async initializeExample(context: vscode.ExtensionContext, channel: vscode.OutputChannel, telemetryContext: TelemetryContext, name?: string, url?: string, boardId?: string): Promise<void> {
if (name && url && boardId) {
this._exampleName = name;
this._exampleUrl = url;
this._boardId = boardId;
}
const res = await this.initializeExampleInternal(
context, channel, telemetryContext);
context, channel, telemetryContext);
if (!res) {
throw new CancelOperationError(`Example load cancelled.`);
@ -262,22 +255,22 @@ export class ExampleExplorer {
vscode.window.showInformationMessage('Example load successfully.');
}
setSelectedExample(name: string, url: string, boardId: string) {
setSelectedExample(name: string, url: string, boardId: string): void {
this._exampleName = name;
this._exampleUrl = url;
this._boardId = boardId;
}
private async initializeExampleInternal(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<boolean> {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<boolean> {
if (!this._exampleName || !this._exampleUrl) {
return false;
}
const boardList = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.boardListFileName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.boardListFileName));
const boardsJson: {boards: Board[]} = require(boardList);
telemetryContext.properties.Example = this._exampleName;
@ -294,13 +287,13 @@ export class ExampleExplorer {
const items = fs.listSync(fsPath, [FileNames.workspaceExtensionName]);
if (items.length !== 0) {
await vscode.commands.executeCommand(
IoTCubeCommands.OpenLocally, items[0], true);
IoTCubeCommands.OpenLocally, items[0], true);
return true;
}
utils.channelShowAndAppendLine(channel, 'Downloading example package...');
const res =
await this.downloadExamplePackage(context, channel, url, fsPath);
await this.downloadExamplePackage(channel, url, fsPath);
if (res) {
// Follow the same pattern in Arduino extension to open examples in new
// VSCode instance
@ -308,16 +301,16 @@ export class ExampleExplorer {
fs.listSync(fsPath, [FileNames.workspaceExtensionName]);
if (workspaceFiles && workspaceFiles.length > 0) {
await vscode.commands.executeCommand(
IoTCubeCommands.OpenLocally, workspaceFiles[0], true);
IoTCubeCommands.OpenLocally, workspaceFiles[0], true);
return true;
} else {
// TODO: Add buttom to submit issue to iot-workbench repo.
throw new Error(
'The example does not contain a project for Azure IoT Device Workbench.');
'The example does not contain a project for Azure IoT Device Workbench.');
}
} else {
throw new Error(
'Downloading example package failed. Please check your network settings.');
'Downloading example package failed. Please check your network settings.');
}
}
}

Просмотреть файл

@ -20,8 +20,8 @@ export class ExceptionHelper {
channel: vscode.OutputChannel|undefined, errorMsg: string,
isPopupErrorMsg: boolean): void;
static logError(
channel: vscode.OutputChannel|undefined, errorValue: string|Error,
popupValue: string|boolean): void {
channel: vscode.OutputChannel|undefined, errorValue: string|Error,
popupValue: string|boolean): void {
let _error: Error;
let _message: string;
@ -43,9 +43,9 @@ export class ExceptionHelper {
let errorMessage: string;
if (_error.message) {
errorMessage = _error.message;
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} else if ((_error as any).body && (_error as any).body.message) {
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
errorMessage = (_error as any).body.message;
} else {
errorMessage = _error.toString();

Просмотреть файл

@ -6,45 +6,348 @@
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import * as path from 'path';
import {BoardProvider} from './boardProvider';
import {ProjectInitializer} from './projectInitializer';
import {DeviceOperator} from './DeviceOperator';
import {AzureOperator} from './AzureOperator';
import {IoTWorkbenchSettings} from './IoTSettings';
import {ConfigHandler} from './configHandler';
import {CodeGeneratorCore} from './DigitalTwin/CodeGeneratorCore';
import {ConfigKey, EventNames, FileNames} from './constants';
import {TelemetryContext, TelemetryWorker, TelemetryResult} from './telemetry';
import {RemoteExtension} from './Models/RemoteExtension';
import {constructAndLoadIoTProject} from './utils';
import {ProjectEnvironmentConfiger} from './ProjectEnvironmentConfiger';
import {WorkbenchExtension} from './WorkbenchExtension';
import {WorkbenchCommands, VscodeCommands} from './common/Commands';
import {ColorizedChannel} from './DigitalTwin/pnp/src/common/colorizedChannel';
import {Constants} from './DigitalTwin/pnp/src/common/constants';
import {DeviceModelManager, ModelType} from './DigitalTwin/pnp/src/deviceModel/deviceModelManager';
import {ModelRepositoryManager} from './DigitalTwin/pnp/src/modelRepository/modelRepositoryManager';
import {IntelliSenseUtility} from './DigitalTwin/pnp/src/intelliSense/intelliSenseUtility';
import {DigitalTwinCompletionItemProvider} from './DigitalTwin/pnp/src/intelliSense/digitalTwinCompletionItemProvider';
import {DigitalTwinHoverProvider} from './DigitalTwin/pnp/src/intelliSense/digitalTwinHoverProvider';
import {DigitalTwinDiagnosticProvider} from './DigitalTwin/pnp/src/intelliSense/digitalTwinDiagnosticProvider';
import {Command} from './DigitalTwin/pnp/src/common/command';
import {UserCancelledError} from './DigitalTwin/pnp/src/common/userCancelledError';
import {UI, MessageType} from './DigitalTwin/pnp/src/view/ui';
import {ProcessError} from './DigitalTwin/pnp/src/common/processError';
import {SearchResult} from './DigitalTwin/pnp/src/modelRepository/modelRepositoryInterface';
import {NSAT} from './nsat';
import {DigitalTwinUtility} from './DigitalTwin/DigitalTwinUtility';
import { BoardProvider } from './boardProvider';
import { ProjectInitializer } from './projectInitializer';
import { DeviceOperator } from './DeviceOperator';
import { AzureOperator } from './AzureOperator';
import { IoTWorkbenchSettings } from './IoTSettings';
import { ConfigHandler } from './configHandler';
import { CodeGeneratorCore } from './DigitalTwin/CodeGeneratorCore';
import { ConfigKey, EventNames, FileNames } from './constants';
import { TelemetryContext, TelemetryWorker, TelemetryResult } from './telemetry';
import { RemoteExtension } from './Models/RemoteExtension';
import { constructAndLoadIoTProject } from './utils';
import { ProjectEnvironmentConfiger } from './ProjectEnvironmentConfiger';
import { WorkbenchExtension } from './WorkbenchExtension';
import { WorkbenchCommands, VscodeCommands } from './common/Commands';
import { ColorizedChannel } from './DigitalTwin/pnp/src/common/colorizedChannel';
import { Constants } from './DigitalTwin/pnp/src/common/constants';
import { DeviceModelManager, ModelType } from './DigitalTwin/pnp/src/deviceModel/deviceModelManager';
import { ModelRepositoryManager } from './DigitalTwin/pnp/src/modelRepository/modelRepositoryManager';
import { IntelliSenseUtility } from './DigitalTwin/pnp/src/intelliSense/intelliSenseUtility';
import { DigitalTwinCompletionItemProvider } from './DigitalTwin/pnp/src/intelliSense/digitalTwinCompletionItemProvider';
import { DigitalTwinHoverProvider } from './DigitalTwin/pnp/src/intelliSense/digitalTwinHoverProvider';
import { DigitalTwinDiagnosticProvider } from './DigitalTwin/pnp/src/intelliSense/digitalTwinDiagnosticProvider';
import { Command } from './DigitalTwin/pnp/src/common/command';
import { UserCancelledError } from './DigitalTwin/pnp/src/common/userCancelledError';
import { UI, MessageType } from './DigitalTwin/pnp/src/view/ui';
import { ProcessError } from './DigitalTwin/pnp/src/common/processError';
import { SearchResult } from './DigitalTwin/pnp/src/modelRepository/modelRepositoryInterface';
import { NSAT } from './nsat';
import { DigitalTwinUtility } from './DigitalTwin/DigitalTwinUtility';
const impor = require('impor')(__dirname);
const exampleExplorerModule =
impor('./exampleExplorer') as typeof import('./exampleExplorer');
const request = impor('request-promise') as typeof import('request-promise');
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let telemetryWorker: any = undefined;
export async function activate(context: vscode.ExtensionContext) {
function printHello(context: vscode.ExtensionContext): void {
const extension = WorkbenchExtension.getExtension(context);
if (!extension) {
return;
}
const extensionId = extension.id;
console.log(`Congratulations, your extension ${extensionId} is now active!`);
}
function initCommandWithTelemetry(
context: vscode.ExtensionContext, telemetryWorker: TelemetryWorker,
outputChannel: vscode.OutputChannel, command: WorkbenchCommands,
eventName: string, enableSurvey: boolean,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
callback: (
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
telemetrycontext: TelemetryContext, ...args: any[]) => any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
additionalProperties?: {[key: string]: string}): void {
context.subscriptions.push(vscode.commands.registerCommand(
command,
async (...commandArgs) => telemetryWorker.callCommandWithTelemetry(
context, outputChannel, eventName, enableSurvey, callback,
additionalProperties, ...commandArgs)));
}
function initCommand(
context: vscode.ExtensionContext, command: WorkbenchCommands,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
callback: (...args: any[]) => Promise<any>): void {
context.subscriptions.push(
vscode.commands.registerCommand(command, callback));
}
function initIntelliSense(context: vscode.ExtensionContext): void {
// init DigitalTwin graph
IntelliSenseUtility.initGraph(context);
// register providers of completionItem and hover
const selector: vscode.DocumentSelector = {
language: 'json',
scheme: 'file',
};
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
selector,
new DigitalTwinCompletionItemProvider(),
Constants.COMPLETION_TRIGGER,
),
);
context.subscriptions.push(vscode.languages.registerHoverProvider(
selector, new DigitalTwinHoverProvider()));
// register diagnostic
let pendingDiagnostic: NodeJS.Timer;
const diagnosticCollection: vscode.DiagnosticCollection =
vscode.languages.createDiagnosticCollection(
Constants.CHANNEL_NAME,
);
const diagnosticProvider = new DigitalTwinDiagnosticProvider();
const activeTextEditor: vscode.TextEditor|undefined =
vscode.window.activeTextEditor;
if (activeTextEditor) {
diagnosticProvider.updateDiagnostics(
activeTextEditor.document, diagnosticCollection);
}
context.subscriptions.push(diagnosticCollection);
context.subscriptions.push(
vscode.window.onDidChangeActiveTextEditor((event) => {
if (event) {
diagnosticProvider.updateDiagnostics(
event.document, diagnosticCollection);
}
}),
);
context.subscriptions.push(
vscode.workspace.onDidChangeTextDocument((event) => {
if (event) {
if (pendingDiagnostic) {
clearTimeout(pendingDiagnostic);
}
pendingDiagnostic = setTimeout(
() => diagnosticProvider.updateDiagnostics(
event.document, diagnosticCollection),
Constants.DEFAULT_TIMER_MS,
);
}
}),
);
context.subscriptions.push(
vscode.workspace.onDidCloseTextDocument(
(document) => diagnosticCollection.delete(document.uri)),
);
}
function initDigitalTwinCommand(
context: vscode.ExtensionContext,
telemetryWorker: TelemetryWorker,
outputChannel: ColorizedChannel,
enableSurvey: boolean,
command: Command,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
callback: (telemetryContext: TelemetryContext, ...args: any[]) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Promise<any>,
): void {
context.subscriptions.push(
vscode.commands.registerCommand(
command,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async (...args: any[]) => {
const start: number = Date.now();
const telemetryContext: TelemetryContext =
telemetryWorker.createContext();
try {
return await callback(telemetryContext, ...args);
} catch (error) {
telemetryContext.properties.error = error.name;
telemetryContext.properties.errorMessage = error.message;
if (error instanceof UserCancelledError) {
telemetryContext.properties.result = TelemetryResult.Cancelled;
outputChannel.warn(error.message);
} else {
telemetryContext.properties.result = TelemetryResult.Failed;
UI.showNotification(MessageType.Error, error.message);
if (error instanceof ProcessError) {
const message = `${error.message}\n${error.stack}`;
outputChannel.error(message, error.component);
} else {
outputChannel.error(error.message);
}
}
} finally {
telemetryContext.measurements.duration =
(Date.now() - start) / 1000;
telemetryWorker.sendEvent(command, telemetryContext);
outputChannel.show();
if (enableSurvey) {
NSAT.takeSurvey(context);
}
}
}),
);
}
// DigitalTwin extension part
function initDigitalTwin(
context: vscode.ExtensionContext,
outputChannel: vscode.OutputChannel): void {
const colorizedChannel = new ColorizedChannel(Constants.CHANNEL_NAME);
context.subscriptions.push(colorizedChannel);
const deviceModelManager = new DeviceModelManager(context, colorizedChannel);
const modelRepositoryManager = new ModelRepositoryManager(
context, Constants.WEB_VIEW_PATH, colorizedChannel);
DigitalTwinUtility.init(modelRepositoryManager, outputChannel);
initIntelliSense(context);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.CreateInterface,
async():
Promise<void> => {
return deviceModelManager.createModel(ModelType.Interface);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.CreateCapabilityModel,
async():
Promise<void> => {
return deviceModelManager.createModel(ModelType.CapabilityModel);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.OpenRepository,
async():
Promise<void> => {
return modelRepositoryManager.signIn();
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.SignOutRepository,
async():
Promise<void> => {
return modelRepositoryManager.signOut();
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.SubmitFiles,
async(telemetryContext: TelemetryContext):
Promise<void> => {
return modelRepositoryManager.submitFiles(telemetryContext);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.DeleteModels,
async(
_telemetryContext: TelemetryContext, publicRepository: boolean,
modelIds: string[]):
Promise<void> => {
return modelRepositoryManager.deleteModels(
publicRepository, modelIds);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.DownloadModels,
async(
_telemetryContext: TelemetryContext, publicRepository: boolean,
modelIds: string[]):
Promise<void> => {
return modelRepositoryManager.downloadModels(
publicRepository, modelIds);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.SearchInterface,
async(
_telemetryContext: TelemetryContext,
publicRepository: boolean,
keyword?: string,
pageSize?: number,
continuationToken?: string,
):
Promise<SearchResult> => {
return modelRepositoryManager.searchModel(
ModelType.Interface,
publicRepository,
keyword,
pageSize,
continuationToken,
);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.SearchCapabilityModel,
async(
_telemetryContext: TelemetryContext,
publicRepository: boolean,
keyword?: string,
pageSize?: number,
continuationToken?: string,
):
Promise<SearchResult> => {
return modelRepositoryManager.searchModel(
ModelType.CapabilityModel,
publicRepository,
keyword,
pageSize,
continuationToken,
);
},
);
}
function enableUsbDetector(
context: vscode.ExtensionContext,
outputChannel: vscode.OutputChannel): void {
if (RemoteExtension.isRemote(context)) {
return;
}
// delay to detect usb
const usbDetectorModule =
impor('./usbDetector') as typeof import('./usbDetector');
const usbDetector = new usbDetectorModule.UsbDetector(context, outputChannel);
usbDetector.startListening(context);
}
export async function activate(context: vscode.ExtensionContext): Promise<void> {
printHello(context);
const channelName = 'Azure IoT Device Workbench';
@ -57,160 +360,162 @@ export async function activate(context: vscode.ExtensionContext) {
// project open since no command has been triggered yet.
const telemetryContext = telemetryWorker.createContext();
await constructAndLoadIoTProject(
context, outputChannel, telemetryContext, true);
context, outputChannel, telemetryContext, true);
const deviceOperator = new DeviceOperator();
const azureOperator = new AzureOperator();
const exampleExplorer = new exampleExplorerModule.ExampleExplorer();
initCommandWithTelemetry(
context, telemetryWorker, outputChannel,
WorkbenchCommands.InitializeProject, EventNames.createNewProjectEvent,
true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
const projectInitializer = new ProjectInitializer();
return projectInitializer.InitializeProject(
context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel,
WorkbenchCommands.InitializeProject, EventNames.createNewProjectEvent,
true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
const projectInitializer = new ProjectInitializer();
return projectInitializer.InitializeProject(
context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel,
WorkbenchCommands.ConfigureProjectEnvironment,
EventNames.configProjectEnvironmentEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
const projectEnvConfiger = new ProjectEnvironmentConfiger();
return projectEnvConfiger.configureCmakeProjectEnvironment(
context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel,
WorkbenchCommands.ConfigureProjectEnvironment,
EventNames.configProjectEnvironmentEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
const projectEnvConfiger = new ProjectEnvironmentConfiger();
return projectEnvConfiger.configureCmakeProjectEnvironment(
context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.AzureProvision,
EventNames.azureProvisionEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return azureOperator.provision(
context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel, WorkbenchCommands.AzureProvision,
EventNames.azureProvisionEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return azureOperator.provision(
context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.AzureDeploy,
EventNames.azureDeployEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return azureOperator.deploy(context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel, WorkbenchCommands.AzureDeploy,
EventNames.azureDeployEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return azureOperator.deploy(context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.DeviceCompile,
EventNames.deviceCompileEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return deviceOperator.compile(context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel, WorkbenchCommands.DeviceCompile,
EventNames.deviceCompileEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return deviceOperator.compile(context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.DeviceUpload,
EventNames.deviceUploadEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return deviceOperator.upload(context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel, WorkbenchCommands.DeviceUpload,
EventNames.deviceUploadEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return deviceOperator.upload(context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel,
WorkbenchCommands.ConfigureDevice, EventNames.configDeviceSettingsEvent,
true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return deviceOperator.configDeviceSettings(
context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel,
WorkbenchCommands.ConfigureDevice, EventNames.configDeviceSettingsEvent,
true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return deviceOperator.configDeviceSettings(
context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.Examples,
EventNames.openExamplePageEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return exampleExplorer.selectBoard(
context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel, WorkbenchCommands.Examples,
EventNames.openExamplePageEvent, true,
async(
context: vscode.ExtensionContext, _outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
return exampleExplorer.selectBoard(
context, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel,
WorkbenchCommands.ExampleInitialize, EventNames.loadExampleEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext, name?: string, url?: string,
boardId?: string): Promise<void> => {
return exampleExplorer.initializeExample(
context, outputChannel, telemetryContext, name, url, boardId);
});
context, telemetryWorker, outputChannel,
WorkbenchCommands.ExampleInitialize, EventNames.loadExampleEvent, true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext, name?: string, url?: string,
boardId?: string): Promise<void> => {
return exampleExplorer.initializeExample(
context, outputChannel, telemetryContext, name, url, boardId);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.SendTelemetry,
EventNames.openTutorial, true, async () => {});
context, telemetryWorker, outputChannel, WorkbenchCommands.SendTelemetry,
EventNames.openTutorial, true, async () => {
// Do nothing.
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel,
WorkbenchCommands.IotPnPGenerateCode, EventNames.scaffoldDeviceStubEvent,
true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
const codeGenerator = new CodeGeneratorCore();
return codeGenerator.generateDeviceCodeStub(
context, outputChannel, telemetryContext);
});
context, telemetryWorker, outputChannel,
WorkbenchCommands.IotPnPGenerateCode, EventNames.scaffoldDeviceStubEvent,
true,
async(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> => {
const codeGenerator = new CodeGeneratorCore();
return codeGenerator.generateDeviceCodeStub(
context, outputChannel, telemetryContext);
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.Help,
EventNames.help, true, async () => {
const boardId = ConfigHandler.get<string>(ConfigKey.boardId);
context, telemetryWorker, outputChannel, WorkbenchCommands.Help,
EventNames.help, true, async () => {
const boardId = ConfigHandler.get<string>(ConfigKey.boardId);
if (boardId) {
const boardListFolderPath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName));
const boardProvider = new BoardProvider(boardListFolderPath);
const board = boardProvider.find({id: boardId});
if (boardId) {
const boardListFolderPath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName));
const boardProvider = new BoardProvider(boardListFolderPath);
const board = boardProvider.find({ id: boardId });
if (board && board.helpUrl) {
await vscode.commands.executeCommand(
VscodeCommands.VscodeOpen, vscode.Uri.parse(board.helpUrl));
return;
}
}
const workbenchHelpUrl =
'https://github.com/microsoft/vscode-iot-workbench/blob/master/README.md';
await vscode.commands.executeCommand(
VscodeCommands.VscodeOpen, vscode.Uri.parse(workbenchHelpUrl));
return;
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.Workbench,
EventNames.setProjectDefaultPath, true, async () => {
const isLocal = RemoteExtension.checkLocalBeforeRunCommand(context);
if (!isLocal) {
if (board && board.helpUrl) {
await vscode.commands.executeCommand(
VscodeCommands.VscodeOpen, vscode.Uri.parse(board.helpUrl));
return;
}
const settings = await IoTWorkbenchSettings.getInstance();
await settings.setWorkbenchPath();
}
const workbenchHelpUrl =
'https://github.com/microsoft/vscode-iot-workbench/blob/master/README.md';
await vscode.commands.executeCommand(
VscodeCommands.VscodeOpen, vscode.Uri.parse(workbenchHelpUrl));
return;
});
initCommandWithTelemetry(
context, telemetryWorker, outputChannel, WorkbenchCommands.Workbench,
EventNames.setProjectDefaultPath, true, async () => {
const isLocal = RemoteExtension.checkLocalBeforeRunCommand(context);
if (!isLocal) {
return;
});
}
const settings = await IoTWorkbenchSettings.getInstance();
await settings.setWorkbenchPath();
return;
});
initCommand(context, WorkbenchCommands.OpenUri, async (uri: string) => {
vscode.commands.executeCommand(
VscodeCommands.VscodeOpen, vscode.Uri.parse(uri));
VscodeCommands.VscodeOpen, vscode.Uri.parse(uri));
});
initCommand(context, WorkbenchCommands.HttpRequest, async (uri: string) => {
@ -228,307 +533,6 @@ export async function activate(context: vscode.ExtensionContext) {
}
// this method is called when your extension is deactivated
export async function deactivate() {}
function enableUsbDetector(
context: vscode.ExtensionContext,
outputChannel: vscode.OutputChannel): void {
if (RemoteExtension.isRemote(context)) {
return;
}
// delay to detect usb
const usbDetectorModule =
impor('./usbDetector') as typeof import('./usbDetector');
const usbDetector = new usbDetectorModule.UsbDetector(context, outputChannel);
usbDetector.startListening(context);
}
function printHello(context: vscode.ExtensionContext) {
const extension = WorkbenchExtension.getExtension(context);
if (!extension) {
return;
}
const extensionId = extension.id;
console.log(`Congratulations, your extension ${extensionId} is now active!`);
}
function initCommandWithTelemetry(
context: vscode.ExtensionContext, telemetryWorker: TelemetryWorker,
outputChannel: vscode.OutputChannel, command: WorkbenchCommands,
eventName: string, enableSurvey: boolean,
// tslint:disable-next-line:no-any
callback: (
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
// tslint:disable-next-line:no-any
telemetrycontext: TelemetryContext, ...args: any[]) => any,
// tslint:disable-next-line:no-any
additionalProperties?: {[key: string]: string}): void {
context.subscriptions.push(vscode.commands.registerCommand(
command,
async (...commandArgs) => telemetryWorker.callCommandWithTelemetry(
context, outputChannel, eventName, enableSurvey, callback,
additionalProperties, ...commandArgs)));
}
function initCommand(
context: vscode.ExtensionContext, command: WorkbenchCommands,
// tslint:disable-next-line:no-any
callback: (...args: any[]) => Promise<any>): void {
context.subscriptions.push(
vscode.commands.registerCommand(command, callback));
}
// DigitalTwin extension part
function initDigitalTwin(
context: vscode.ExtensionContext,
outputChannel: vscode.OutputChannel): void {
const colorizedChannel = new ColorizedChannel(Constants.CHANNEL_NAME);
context.subscriptions.push(colorizedChannel);
const deviceModelManager = new DeviceModelManager(context, colorizedChannel);
const modelRepositoryManager = new ModelRepositoryManager(
context, Constants.WEB_VIEW_PATH, colorizedChannel);
DigitalTwinUtility.init(modelRepositoryManager, outputChannel);
initIntelliSense(context);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.CreateInterface,
async():
Promise<void> => {
return deviceModelManager.createModel(ModelType.Interface);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.CreateCapabilityModel,
async():
Promise<void> => {
return deviceModelManager.createModel(ModelType.CapabilityModel);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.OpenRepository,
async():
Promise<void> => {
return modelRepositoryManager.signIn();
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.SignOutRepository,
async():
Promise<void> => {
return modelRepositoryManager.signOut();
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
true,
Command.SubmitFiles,
async(telemetryContext: TelemetryContext):
Promise<void> => {
return modelRepositoryManager.submitFiles(telemetryContext);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.DeleteModels,
async(
telemetryContext: TelemetryContext, publicRepository: boolean,
modelIds: string[]):
Promise<void> => {
return modelRepositoryManager.deleteModels(
publicRepository, modelIds);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.DownloadModels,
async(
telemetryContext: TelemetryContext, publicRepository: boolean,
modelIds: string[]):
Promise<void> => {
return modelRepositoryManager.downloadModels(
publicRepository, modelIds);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.SearchInterface,
async(
telemetryContext: TelemetryContext,
publicRepository: boolean,
keyword?: string,
pageSize?: number,
continuationToken?: string,
):
Promise<SearchResult> => {
return modelRepositoryManager.searchModel(
ModelType.Interface,
publicRepository,
keyword,
pageSize,
continuationToken,
);
},
);
initDigitalTwinCommand(
context,
telemetryWorker,
colorizedChannel,
false,
Command.SearchCapabilityModel,
async(
telemetryContext: TelemetryContext,
publicRepository: boolean,
keyword?: string,
pageSize?: number,
continuationToken?: string,
):
Promise<SearchResult> => {
return modelRepositoryManager.searchModel(
ModelType.CapabilityModel,
publicRepository,
keyword,
pageSize,
continuationToken,
);
},
);
}
function initIntelliSense(context: vscode.ExtensionContext): void {
// init DigitalTwin graph
IntelliSenseUtility.initGraph(context);
// register providers of completionItem and hover
const selector: vscode.DocumentSelector = {
language: 'json',
scheme: 'file',
};
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
selector,
new DigitalTwinCompletionItemProvider(),
Constants.COMPLETION_TRIGGER,
),
);
context.subscriptions.push(vscode.languages.registerHoverProvider(
selector, new DigitalTwinHoverProvider()));
// register diagnostic
let pendingDiagnostic: NodeJS.Timer;
const diagnosticCollection: vscode.DiagnosticCollection =
vscode.languages.createDiagnosticCollection(
Constants.CHANNEL_NAME,
);
const diagnosticProvider = new DigitalTwinDiagnosticProvider();
const activeTextEditor: vscode.TextEditor|undefined =
vscode.window.activeTextEditor;
if (activeTextEditor) {
diagnosticProvider.updateDiagnostics(
activeTextEditor.document, diagnosticCollection);
}
context.subscriptions.push(diagnosticCollection);
context.subscriptions.push(
vscode.window.onDidChangeActiveTextEditor((event) => {
if (event) {
diagnosticProvider.updateDiagnostics(
event.document, diagnosticCollection);
}
}),
);
context.subscriptions.push(
vscode.workspace.onDidChangeTextDocument((event) => {
if (event) {
if (pendingDiagnostic) {
clearTimeout(pendingDiagnostic);
}
pendingDiagnostic = setTimeout(
() => diagnosticProvider.updateDiagnostics(
event.document, diagnosticCollection),
Constants.DEFAULT_TIMER_MS,
);
}
}),
);
context.subscriptions.push(
vscode.workspace.onDidCloseTextDocument(
(document) => diagnosticCollection.delete(document.uri)),
);
}
function initDigitalTwinCommand(
context: vscode.ExtensionContext,
telemetryWorker: TelemetryWorker,
outputChannel: ColorizedChannel,
enableSurvey: boolean,
command: Command,
// tslint:disable-next-line:no-any
callback: (telemetryContext: TelemetryContext, ...args: any[]) =>
// tslint:disable-next-line:no-any
Promise<any>,
): void {
context.subscriptions.push(
vscode.commands.registerCommand(
command,
// tslint:disable-next-line:no-any
async (...args: any[]) => {
const start: number = Date.now();
const telemetryContext: TelemetryContext =
telemetryWorker.createContext();
try {
return await callback(telemetryContext, ...args);
} catch (error) {
telemetryContext.properties.error = error.name;
telemetryContext.properties.errorMessage = error.message;
if (error instanceof UserCancelledError) {
telemetryContext.properties.result = TelemetryResult.Cancelled;
outputChannel.warn(error.message);
} else {
telemetryContext.properties.result = TelemetryResult.Failed;
UI.showNotification(MessageType.Error, error.message);
if (error instanceof ProcessError) {
const message = `${error.message}\n${error.stack}`;
outputChannel.error(message, error.component);
} else {
outputChannel.error(error.message);
}
}
} finally {
telemetryContext.measurements.duration =
(Date.now() - start) / 1000;
telemetryWorker.sendEvent(command, telemetryContext);
outputChannel.show();
if (enableSurvey) {
NSAT.takeSurvey(context);
}
}
}),
);
export async function deactivate(): Promise<void> {
// Do nothing.
}

4
src/getmac.d.ts поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
// reference code from https://github.com/0815fox/DefinitelyTyped
declare module "getmac" {
function getMac(opts:(err:Error,macAddress:string)=>void):void;
function isMac(macAddress:string):boolean;
function getMac(opts: (err: Error,macAddress: string) => void): void;
function isMac(macAddress: string): boolean;
}

Просмотреть файл

@ -3,11 +3,11 @@
'use strict';
import {commands, ExtensionContext, Uri, window} from 'vscode';
import {EventNames} from './constants';
import {TelemetryWorker} from './telemetry';
import {WorkbenchExtension} from './WorkbenchExtension';
import {VscodeCommands} from './common/Commands';
import { commands, ExtensionContext, Uri, window } from 'vscode';
import { EventNames } from './constants';
import { TelemetryWorker } from './telemetry';
import { WorkbenchExtension } from './WorkbenchExtension';
import { VscodeCommands } from './common/Commands';
const NSAT_SURVEY_URL = 'https://aka.ms/vscode-iot-workbench-survey';
const PROBABILITY = 1;
@ -20,7 +20,7 @@ const SKIP_VERSION_KEY = 'nsat/skipVersion';
const IS_CANDIDATE_KEY = 'nsat/isCandidate';
export class NSAT {
static async takeSurvey(context: ExtensionContext) {
static async takeSurvey(context: ExtensionContext): Promise<void> {
const globalState = context.globalState;
const skipVersion = globalState.get(SKIP_VERSION_KEY, '');
if (skipVersion) {
@ -63,14 +63,14 @@ export class NSAT {
const take = {
title: 'Take Survey',
run: async () => {
run: async (): Promise<void> => {
telemetryContext.properties.message = 'nsat.survey/takeShortSurvey';
telemetryWorker.sendEvent(EventNames.nsatsurvery, telemetryContext);
commands.executeCommand(
VscodeCommands.VscodeOpen,
Uri.parse(`${NSAT_SURVEY_URL}?o=${
encodeURIComponent(process.platform)}&v=${
encodeURIComponent(extensionVersion)}`));
VscodeCommands.VscodeOpen,
Uri.parse(`${NSAT_SURVEY_URL}?o=${
encodeURIComponent(process.platform)}&v=${
encodeURIComponent(extensionVersion)}`));
await globalState.update(IS_CANDIDATE_KEY, false);
await globalState.update(SKIP_VERSION_KEY, extensionVersion);
await globalState.update(TAKE_SURVEY_DATE_KEY, date);
@ -78,7 +78,7 @@ export class NSAT {
};
const remind = {
title: 'Remind Me Later',
run: async () => {
run: async (): Promise<void> => {
telemetryContext.properties.message = 'nsat.survey/remindMeLater';
telemetryWorker.sendEvent(EventNames.nsatsurvery, telemetryContext);
await globalState.update(SESSION_COUNT_KEY, 0);
@ -86,7 +86,7 @@ export class NSAT {
};
const never = {
title: 'Don\'t Show Again',
run: async () => {
run: async (): Promise<void> => {
telemetryContext.properties.message = 'nsat.survey/dontShowAgain';
telemetryWorker.sendEvent(EventNames.nsatsurvery, telemetryContext);
await globalState.update(IS_CANDIDATE_KEY, false);
@ -97,8 +97,8 @@ export class NSAT {
telemetryContext.properties.message = 'nsat.survey/userAsked';
telemetryWorker.sendEvent(EventNames.nsatsurvery, telemetryContext);
const button = await window.showInformationMessage(
'Do you mind taking a quick feedback survey about the Azure IoT Device Workbench Extension for VS Code?',
take, remind, never);
'Do you mind taking a quick feedback survey about the Azure IoT Device Workbench Extension for VS Code?',
take, remind, never);
await (button || remind).run();
}
}

Просмотреть файл

@ -7,13 +7,13 @@ import * as vscode from 'vscode';
import * as path from 'path';
import * as utils from './utils';
import {TelemetryContext} from './telemetry';
import {FileNames, ScaffoldType, PlatformType, TemplateTag} from './constants';
import {IoTWorkbenchSettings} from './IoTSettings';
import {FileUtility} from './FileUtility';
import {ProjectTemplate, ProjectTemplateType, TemplatesType} from './Models/Interfaces/ProjectTemplate';
import {RemoteExtension} from './Models/RemoteExtension';
import {CancelOperationError} from './CancelOperationError';
import { TelemetryContext } from './telemetry';
import { FileNames, ScaffoldType, PlatformType, TemplateTag } from './constants';
import { IoTWorkbenchSettings } from './IoTSettings';
import { FileUtility } from './FileUtility';
import { ProjectTemplate, ProjectTemplateType, TemplatesType } from './Models/Interfaces/ProjectTemplate';
import { RemoteExtension } from './Models/RemoteExtension';
import { CancelOperationError } from './CancelOperationError';
const impor = require('impor')(__dirname);
const ioTWorkspaceProjectModule = impor('./Models/IoTWorkspaceProject') as
@ -30,8 +30,8 @@ const constants = {
export class ProjectInitializer {
async InitializeProject(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext): Promise<void> {
// Only create project when not in remote environment
const isLocal = RemoteExtension.checkLocalBeforeRunCommand(context);
if (!isLocal) {
@ -48,103 +48,102 @@ export class ProjectInitializer {
// Initial project
await vscode.window.withProgress(
{
title: 'Project initialization',
location: vscode.ProgressLocation.Window,
},
async (progress) => {
progress.report({
message: 'Updating a list of available template',
});
{
title: 'Project initialization',
location: vscode.ProgressLocation.Window,
},
async (progress) => {
progress.report({
message: 'Updating a list of available template',
});
const scaffoldType = ScaffoldType.Local;
const scaffoldType = ScaffoldType.Local;
// Step 1: Get project name
const projectPath =
// Step 1: Get project name
const projectPath =
await this.generateProjectFolder(telemetryContext, scaffoldType);
if (!projectPath) {
throw new CancelOperationError(
`Project initialization cancelled: Project name input cancelled.`);
}
if (!projectPath) {
throw new CancelOperationError(
`Project initialization cancelled: Project name input cancelled.`);
}
// Step 2: Select platform
const platformSelection =
// Step 2: Select platform
const platformSelection =
await utils.selectPlatform(scaffoldType, context);
if (!platformSelection) {
throw new CancelOperationError(
`Project initialization cancelled: Platform selection cancelled.`);
} else {
telemetryContext.properties.platform = platformSelection.label;
}
if (!platformSelection) {
throw new CancelOperationError(
`Project initialization cancelled: Platform selection cancelled.`);
} else {
telemetryContext.properties.platform = platformSelection.label;
}
// Step 3: Select template
let template: ProjectTemplate|undefined;
const resourceRootPath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName));
const templateJsonFilePath =
// Step 3: Select template
const resourceRootPath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName));
const templateJsonFilePath =
path.join(resourceRootPath, FileNames.templateFileName);
const templateJsonFileString =
const templateJsonFileString =
await FileUtility.readFile(
scaffoldType, templateJsonFilePath, 'utf8') as string;
const templateJson = JSON.parse(templateJsonFileString);
if (!templateJson) {
throw new Error(`Fail to load template json.`);
}
scaffoldType, templateJsonFilePath, 'utf8') as string;
const templateJson = JSON.parse(templateJsonFileString);
if (!templateJson) {
throw new Error(`Fail to load template json.`);
}
let templateName: string|undefined;
if (platformSelection.label === PlatformType.Arduino) {
const templateSelection =
let templateName: string|undefined;
if (platformSelection.label === PlatformType.Arduino) {
const templateSelection =
await this.selectTemplate(templateJson, PlatformType.Arduino);
if (!templateSelection) {
throw new CancelOperationError(
`Project initialization cancelled: Project template selection cancelled.`);
} else {
telemetryContext.properties.template = templateSelection.label;
if (templateSelection.label === constants.noDeviceMessage) {
await utils.takeNoDeviceSurvey(telemetryContext, context);
return;
}
}
templateName = templateSelection.label;
if (!templateSelection) {
throw new CancelOperationError(
`Project initialization cancelled: Project template selection cancelled.`);
} else {
// If choose Embedded Linux platform, generate C project template
// directly
templateName = constants.embeddedLinuxProjectName;
telemetryContext.properties.template = templateSelection.label;
if (templateSelection.label === constants.noDeviceMessage) {
await utils.takeNoDeviceSurvey(telemetryContext, context);
return;
}
}
templateName = templateSelection.label;
} else {
// If choose Embedded Linux platform, generate C project template
// directly
templateName = constants.embeddedLinuxProjectName;
}
template =
const template =
templateJson.templates.find((template: ProjectTemplate) => {
return template.platform === platformSelection.label &&
template.name === templateName;
});
if (!template) {
throw new Error(
`Fail to find the wanted project template in template json file.`);
}
if (!template) {
throw new Error(
`Fail to find the wanted project template in template json file.`);
}
// Step 4: Load the list of template files
const projectTemplateType: ProjectTemplateType =
// Step 4: Load the list of template files
const projectTemplateType: ProjectTemplateType =
utils.getEnumKeyByEnumValue(ProjectTemplateType, template.type);
const templateFolder = path.join(resourceRootPath, template.path);
const templateFilesInfo =
const templateFolder = path.join(resourceRootPath, template.path);
const templateFilesInfo =
await utils.getTemplateFilesInfo(templateFolder);
let project;
if (template.platform === PlatformType.EmbeddedLinux) {
project = new ioTContainerizedProjectModule.IoTContainerizedProject(
context, channel, telemetryContext, projectPath);
} else if (template.platform === PlatformType.Arduino) {
project = new ioTWorkspaceProjectModule.IoTWorkspaceProject(
context, channel, telemetryContext, projectPath);
} else {
throw new Error('unsupported platform');
}
await project.create(
templateFilesInfo, projectTemplateType, template.boardId,
openInNewWindow);
});
let project;
if (template.platform === PlatformType.EmbeddedLinux) {
project = new ioTContainerizedProjectModule.IoTContainerizedProject(
context, channel, telemetryContext, projectPath);
} else if (template.platform === PlatformType.Arduino) {
project = new ioTWorkspaceProjectModule.IoTWorkspaceProject(
context, channel, telemetryContext, projectPath);
} else {
throw new Error('unsupported platform');
}
await project.create(
templateFilesInfo, projectTemplateType, template.boardId,
openInNewWindow);
});
}
private async selectTemplate(templateJson: TemplatesType, platform: string):
@ -152,7 +151,7 @@ export class ProjectInitializer {
const result =
templateJson.templates.filter((template: ProjectTemplate) => {
return (
template.platform === platform &&
template.platform === platform &&
template.tag === TemplateTag.General);
});
@ -178,8 +177,8 @@ export class ProjectInitializer {
}
private async generateProjectFolder(
telemetryContext: TelemetryContext,
scaffoldType: ScaffoldType): Promise<string|undefined> {
telemetryContext: TelemetryContext,
scaffoldType: ScaffoldType): Promise<string|undefined> {
// Get default workbench path.
const settings = await IoTWorkbenchSettings.getInstance();
const workbench = settings.getWorkbenchPath();
@ -192,6 +191,7 @@ export class ProjectInitializer {
let counter = 0;
const name = constants.defaultProjectName;
let candidateName = name;
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
while (true) {
const projectPath = path.join(projectRootPath, candidateName);
const isValid = await this.isProjectPathValid(scaffoldType, projectPath);
@ -209,7 +209,7 @@ export class ProjectInitializer {
ignoreFocusOut: true,
validateInput: async (projectName: string) => {
if (!/^([a-z0-9_]|[a-z0-9_][-a-z0-9_.]*[a-z0-9_])(\.ino)?$/i.test(
projectName)) {
projectName)) {
return 'Project name can only contain letters, numbers, "-" and ".", and cannot start or end with "-" or ".".';
}
@ -237,7 +237,7 @@ export class ProjectInitializer {
}
private async isProjectPathValid(
scaffoldType: ScaffoldType, projectPath: string): Promise<boolean> {
scaffoldType: ScaffoldType, projectPath: string): Promise<boolean> {
const projectPathExists =
await FileUtility.fileExists(scaffoldType, projectPath);
const projectDirectoryExists =

Просмотреть файл

@ -4,12 +4,12 @@
import * as vscode from 'vscode';
import TelemetryReporter from 'vscode-extension-telemetry';
import {CancelOperationError} from './CancelOperationError';
import {DevelopEnvironment} from './constants';
import {ExceptionHelper} from './exceptionHelper';
import {RemoteExtension} from './Models/RemoteExtension';
import {NSAT} from './nsat';
import {WorkbenchExtension} from './WorkbenchExtension';
import { CancelOperationError } from './CancelOperationError';
import { DevelopEnvironment } from './constants';
import { ExceptionHelper } from './exceptionHelper';
import { RemoteExtension } from './Models/RemoteExtension';
import { NSAT } from './nsat';
import { WorkbenchExtension } from './WorkbenchExtension';
interface PackageInfo {
@ -50,11 +50,11 @@ export class TelemetryWorker {
}
if (!packageInfo.aiKey) {
console.log(
'Unable to initialize telemetry, please make sure AIKey is set in package.json');
'Unable to initialize telemetry, please make sure AIKey is set in package.json');
return;
}
this._reporter = new TelemetryReporter(
packageInfo.name, packageInfo.version, packageInfo.aiKey);
packageInfo.name, packageInfo.version, packageInfo.aiKey);
this._isInternal = TelemetryWorker.isInternalUser();
}
@ -70,8 +70,8 @@ export class TelemetryWorker {
*/
private static isInternalUser(): boolean {
const userDomain: string = process.env.USERDNSDOMAIN ?
process.env.USERDNSDOMAIN.toLowerCase() :
'';
process.env.USERDNSDOMAIN.toLowerCase() :
'';
return userDomain.endsWith('microsoft.com');
}
@ -79,14 +79,14 @@ export class TelemetryWorker {
* Create telemetry context
*/
createContext(): TelemetryContext {
const context: TelemetryContext = {properties: {}, measurements: {}};
const context: TelemetryContext = { properties: {}, measurements: {} };
context.properties.result = TelemetryResult.Succeeded;
context.properties.isInternal = this._isInternal.toString();
if (this._extensionContext) {
context.properties.developEnvironment =
RemoteExtension.isRemote(this._extensionContext) ?
DevelopEnvironment.RemoteEnv :
DevelopEnvironment.LocalEnv;
DevelopEnvironment.RemoteEnv :
DevelopEnvironment.LocalEnv;
}
return context;
}
@ -104,7 +104,7 @@ export class TelemetryWorker {
telemetryContext = this.createContext();
}
this._reporter.sendTelemetryEvent(
eventName, telemetryContext.properties, telemetryContext.measurements);
eventName, telemetryContext.properties, telemetryContext.measurements);
}
/**
@ -118,25 +118,25 @@ export class TelemetryWorker {
* @param additionalProperties
*/
async callCommandWithTelemetry(
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
eventName: string, enableSurvey: boolean,
// tslint:disable-next-line:no-any
callback:
context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel,
eventName: string, enableSurvey: boolean,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
callback:
(context: vscode.ExtensionContext,
outputChannel: vscode.OutputChannel,
// tslint:disable-next-line:no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
telemetrycontext: TelemetryContext, ...args: any[]) => any,
// tslint:disable-next-line:no-any
additionalProperties?: {[key: string]: string},
// tslint:disable-next-line:no-any
...commandArgs: any[]): Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
additionalProperties?: {[key: string]: string},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...commandArgs: any[]): Promise<any> {
const telemetryWorker = TelemetryWorker.getInstance(context);
const telemetryContext = telemetryWorker.createContext();
const start: number = Date.now();
if (additionalProperties) {
for (const key of Object.keys(additionalProperties)) {
if (!telemetryContext.properties.hasOwnProperty(key)) {
if (!Object.prototype.hasOwnProperty.call(telemetryContext.properties, key)) {
telemetryContext.properties[key] = additionalProperties[key];
}
}
@ -144,7 +144,7 @@ export class TelemetryWorker {
try {
return await callback(
context, outputChannel, telemetryContext, ...commandArgs);
context, outputChannel, telemetryContext, ...commandArgs);
} catch (error) {
telemetryContext.properties.errorMessage = error.message;
let isPopupErrorMsg = true;
@ -172,7 +172,7 @@ export class TelemetryWorker {
/**
* dispose telemetry worker
*/
async dispose() {
async dispose(): Promise<void> {
if (this._reporter) {
await this._reporter.dispose();
}

Просмотреть файл

@ -4,13 +4,14 @@
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import {VSCExpress} from 'vscode-express';
import { VSCExpress } from 'vscode-express';
import {ArduinoPackageManager} from './ArduinoPackageManager';
import {BoardProvider} from './boardProvider';
import {ConfigKey, EventNames, FileNames, OSPlatform} from './constants';
import {TelemetryWorker} from './telemetry';
import {shouldShowLandingPage} from './utils';
import { ArduinoPackageManager } from './ArduinoPackageManager';
import { BoardProvider } from './boardProvider';
import { ConfigKey, EventNames, FileNames, OSPlatform } from './constants';
import { TelemetryWorker } from './telemetry';
import { shouldShowLandingPage } from './utils';
import { Board } from './Models/Interfaces/Board';
export interface DeviceInfo {
vendorId: number;
@ -19,7 +20,7 @@ export interface DeviceInfo {
export class UsbDetector {
private static _vscexpress: VSCExpress|undefined;
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private static _usbDetector: any;
constructor(
@ -34,53 +35,53 @@ export class UsbDetector {
}
}
getBoardFromDeviceInfo(device: DeviceInfo) {
getBoardFromDeviceInfo(device: DeviceInfo): Board|undefined {
if (device.vendorId && device.productId) {
const boardFolderPath = this.context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName));
FileNames.resourcesFolderName, FileNames.templatesFolderName));
const boardProvider = new BoardProvider(boardFolderPath);
const board = boardProvider.find(
{vendorId: device.vendorId, productId: device.productId});
{ vendorId: device.vendorId, productId: device.productId });
return board;
}
return undefined;
}
showLandingPage(device: DeviceInfo) {
showLandingPage(device: DeviceInfo): void {
const board = this.getBoardFromDeviceInfo(device);
if (board) {
const telemetryWorker = TelemetryWorker.getInstance(this.context);
telemetryWorker.callCommandWithTelemetry(
this.context, this.channel, EventNames.detectBoard,
false, async () => {
if (board.exampleUrl) {
ArduinoPackageManager.installBoard(board);
this.context, this.channel, EventNames.detectBoard,
false, async () => {
if (board.exampleUrl) {
ArduinoPackageManager.installBoard(board);
const exampleUrl = 'example.html?board=' + board.id +
const exampleUrl = 'example.html?board=' + board.id +
'&url=' + encodeURIComponent(board.exampleUrl || '');
UsbDetector._vscexpress = UsbDetector._vscexpress ||
UsbDetector._vscexpress = UsbDetector._vscexpress ||
new VSCExpress(this.context, 'views');
UsbDetector._vscexpress.open(
exampleUrl,
board.examplePageName +
UsbDetector._vscexpress.open(
exampleUrl,
board.examplePageName +
' samples - Azure IoT Device Workbench',
vscode.ViewColumn.One, {
enableScripts: true,
enableCommandUris: true,
retainContextWhenHidden: true
});
}
}, {}, {board: board.name});
vscode.ViewColumn.One, {
enableScripts: true,
enableCommandUris: true,
retainContextWhenHidden: true
});
}
}, {}, { board: board.name });
}
// Will not auto pop up landing page next time.
this.context.globalState.update(ConfigKey.hasPopUp, true);
}
async startListening(context: vscode.ExtensionContext) {
async startListening(context: vscode.ExtensionContext): Promise<void> {
const enableUSBDetection = shouldShowLandingPage(context);
if (os.platform() === OSPlatform.LINUX || !enableUSBDetection) {
return;
@ -98,7 +99,7 @@ export class UsbDetector {
devices.forEach(device => {
if (uniqueDevices.findIndex(
item => item.vendorId === device.vendorId &&
item => item.vendorId === device.vendorId &&
item.productId === device.productId) < 0) {
uniqueDevices.push(device);
}

Просмотреть файл

@ -6,23 +6,23 @@ import * as crypto from 'crypto';
import * as fs from 'fs-plus';
import * as path from 'path';
import * as vscode from 'vscode';
import {MessageItem} from 'vscode';
import { MessageItem } from 'vscode';
import * as sdk from 'vscode-iot-device-cube-sdk';
import * as WinReg from 'winreg';
import {CancelOperationError} from './CancelOperationError';
import {IoTCubeCommands, RemoteContainersCommands, VscodeCommands, WorkbenchCommands} from './common/Commands';
import {AzureFunctionsLanguage, ConfigKey, FileNames, OperationType, PlatformType, ScaffoldType, TemplateTag} from './constants';
import {DialogResponses} from './DialogResponses';
import {FileUtility} from './FileUtility';
import {ProjectHostType} from './Models/Interfaces/ProjectHostType';
import {ProjectTemplate, TemplateFileInfo} from './Models/Interfaces/ProjectTemplate';
import {Platform} from './Models/Interfaces/ProjectTemplate';
import {IoTWorkbenchProjectBase} from './Models/IoTWorkbenchProjectBase';
import {RemoteExtension} from './Models/RemoteExtension';
import {ProjectEnvironmentConfiger} from './ProjectEnvironmentConfiger';
import {TelemetryContext, TelemetryResult} from './telemetry';
import {WorkbenchExtension} from './WorkbenchExtension';
import { CancelOperationError } from './CancelOperationError';
import { IoTCubeCommands, RemoteContainersCommands, VscodeCommands, WorkbenchCommands } from './common/Commands';
import { AzureFunctionsLanguage, ConfigKey, FileNames, OperationType, PlatformType, ScaffoldType, TemplateTag } from './constants';
import { DialogResponses } from './DialogResponses';
import { FileUtility } from './FileUtility';
import { ProjectHostType } from './Models/Interfaces/ProjectHostType';
import { ProjectTemplate, TemplateFileInfo } from './Models/Interfaces/ProjectTemplate';
import { Platform } from './Models/Interfaces/ProjectTemplate';
import { IoTWorkbenchProjectBase } from './Models/IoTWorkbenchProjectBase';
import { RemoteExtension } from './Models/RemoteExtension';
import { ProjectEnvironmentConfiger } from './ProjectEnvironmentConfiger';
import { TelemetryContext, TelemetryResult } from './telemetry';
import { WorkbenchExtension } from './WorkbenchExtension';
const impor = require('impor')(__dirname);
const ioTWorkspaceProjectModule = impor('./Models/IoTWorkspaceProject') as
@ -33,38 +33,50 @@ const ioTContainerizedProjectModule =
const raspberryPiDeviceModule = impor('./Models/RaspberryPiDevice') as
typeof import('./Models/RaspberryPiDevice');
export function delay(ms: number) {
export function delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
export function getRegistryValues(
hive: string, key: string, name: string): Promise<string> {
return new Promise(
async (
resolve: (value: string) => void, reject: (value: Error) => void) => {
try {
const regKey = new WinReg({hive, key});
export function channelShowAndAppend(
channel: vscode.OutputChannel, message: string): void {
channel.show();
channel.append(message);
}
regKey.valueExists(name, (e, exists) => {
if (e) {
return reject(e);
}
if (exists) {
regKey.get(name, (err, result) => {
if (!err) {
return resolve(result ? result.value : '');
} else {
return reject(err);
}
});
} else {
return resolve('');
}
});
} catch (ex) {
return reject(ex);
}
});
export function channelShowAndAppendLine(
channel: vscode.OutputChannel, message: string): void {
channel.show();
channel.appendLine(message);
}
export function getRegistryValues(
hive: string, key: string, name: string): Promise<string> {
return new Promise(
(
resolve: (value: string) => void, reject: (value: Error) => void) => {
try {
const regKey = new WinReg({ hive, key });
regKey.valueExists(name, (e, exists) => {
if (e) {
return reject(e);
}
if (exists) {
regKey.get(name, (err, result) => {
if (!err) {
return resolve(result ? result.value : '');
} else {
return reject(err);
}
});
} else {
return resolve('');
}
});
} catch (ex) {
return reject(ex);
}
});
}
export function directoryExistsSync(dirPath: string): boolean {
@ -101,14 +113,14 @@ export function fileExistsSync(filePath: string): boolean {
export function getScriptTemplateNameFromLanguage(language: string): string|
undefined {
switch (language) {
case AzureFunctionsLanguage.CSharpScript:
return 'IoTHubTrigger-CSharp';
case AzureFunctionsLanguage.JavaScript:
return 'IoTHubTrigger-JavaScript';
case AzureFunctionsLanguage.CSharpLibrary:
return 'Azure.Function.CSharp.IotHubTrigger.2.x';
default:
return undefined;
case AzureFunctionsLanguage.CSharpScript:
return 'IoTHubTrigger-CSharp';
case AzureFunctionsLanguage.JavaScript:
return 'IoTHubTrigger-JavaScript';
case AzureFunctionsLanguage.CSharpLibrary:
return 'Azure.Function.CSharp.IotHubTrigger.2.x';
default:
return undefined;
}
}
@ -130,7 +142,7 @@ export function getFirstWorkspaceFolderPath(showWarningMessage = true): string {
!vscode.workspace.workspaceFolders[0].uri.fsPath) {
if (showWarningMessage) {
vscode.window.showWarningMessage(
'You have not yet opened a folder in Visual Studio Code. Please select a folder first.');
'You have not yet opened a folder in Visual Studio Code. Please select a folder first.');
}
return '';
}
@ -138,24 +150,6 @@ export function getFirstWorkspaceFolderPath(showWarningMessage = true): string {
return vscode.workspace.workspaceFolders[0].uri.fsPath;
}
export async function selectWorkspaceFolder(
placeHolder: string,
getSubPath?: (f: vscode.WorkspaceFolder) =>
string | undefined): Promise<string> {
return await selectWorkspaceItem(
placeHolder, {
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
defaultUri: vscode.workspace.workspaceFolders &&
vscode.workspace.workspaceFolders.length > 0 ?
vscode.workspace.workspaceFolders[0].uri :
undefined,
openLabel: 'Select'
},
getSubPath);
}
export async function showOpenDialog(options: vscode.OpenDialogOptions):
Promise<vscode.Uri[]> {
const result: vscode.Uri[]|undefined =
@ -169,37 +163,54 @@ export async function showOpenDialog(options: vscode.OpenDialogOptions):
}
export async function selectWorkspaceItem(
placeHolder: string, options: vscode.OpenDialogOptions,
getSubPath?: (f: vscode.WorkspaceFolder) =>
string | undefined): Promise<string> {
let folder: FolderQuickPickItem<string|undefined>|undefined;
placeHolder: string, options: vscode.OpenDialogOptions,
getSubPath?: (f: vscode.WorkspaceFolder) =>
string | undefined): Promise<string> {
let folderPicks: Array<FolderQuickPickItem<string|undefined>> = [];
if (vscode.workspace.workspaceFolders) {
folderPicks =
vscode.workspace.workspaceFolders.map((f: vscode.WorkspaceFolder) => {
let subpath: string|undefined;
if (getSubPath) {
subpath = getSubPath(f);
}
vscode.workspace.workspaceFolders.map((f: vscode.WorkspaceFolder) => {
let subpath: string|undefined;
if (getSubPath) {
subpath = getSubPath(f);
}
const fsPath: string =
subpath ? path.join(f.uri.fsPath, subpath) : f.uri.fsPath;
return {
label: path.basename(fsPath),
description: fsPath,
data: fsPath
};
});
const fsPath: string =
subpath ? path.join(f.uri.fsPath, subpath) : f.uri.fsPath;
return {
label: path.basename(fsPath),
description: fsPath,
data: fsPath
};
});
}
folderPicks.push({label: 'Browse...', description: '', data: undefined});
folder = await vscode.window.showQuickPick(
folderPicks, {placeHolder, ignoreFocusOut: true});
folderPicks.push({ label: 'Browse...', description: '', data: undefined });
const folder = await vscode.window.showQuickPick(
folderPicks, { placeHolder, ignoreFocusOut: true });
if (!folder) {
throw new Error('User cancelled the operation.');
}
return folder && folder.data ? folder.data :
(await showOpenDialog(options))[0].fsPath;
(await showOpenDialog(options))[0].fsPath;
}
export async function selectWorkspaceFolder(
placeHolder: string,
getSubPath?: (f: vscode.WorkspaceFolder) =>
string | undefined): Promise<string> {
return await selectWorkspaceItem(
placeHolder, {
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
defaultUri: vscode.workspace.workspaceFolders &&
vscode.workspace.workspaceFolders.length > 0 ?
vscode.workspace.workspaceFolders[0].uri :
undefined,
openLabel: 'Select'
},
getSubPath);
}
export function executeCommand(command: string): Promise<string> {
@ -217,12 +228,12 @@ export function executeCommand(command: string): Promise<string> {
}
export function runCommand(
command: string, args: string[], workingDir: string,
outputChannel: vscode.OutputChannel): Thenable<object> {
command: string, args: string[], workingDir: string,
outputChannel: vscode.OutputChannel): Thenable<object> {
return new Promise((resolve, reject) => {
const stdout = '';
const stderr = '';
const process = cp.spawn(command, args, {cwd: workingDir, shell: true});
const process = cp.spawn(command, args, { cwd: workingDir, shell: true });
process.stdout.on('data', (data: string) => {
console.log(data);
outputChannel.appendLine(data);
@ -231,12 +242,12 @@ export function runCommand(
console.log(data);
outputChannel.appendLine(data);
});
process.on('error', error => reject({error, stderr, stdout}));
process.on('error', error => reject({ error, stderr, stdout }));
process.on('close', status => {
if (status === 0) {
resolve({status, stdout, stderr});
resolve({ status, stdout, stderr });
} else {
reject({status, stdout, stderr});
reject({ status, stdout, stderr });
}
});
});
@ -247,36 +258,36 @@ export function runCommand(
* first.
*/
export async function askToConfigureEnvironment(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, platform: PlatformType,
deviceRootPath: string, scaffoldType: ScaffoldType,
operation: OperationType): Promise<void> {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, platform: PlatformType,
deviceRootPath: string, scaffoldType: ScaffoldType,
operation: OperationType): Promise<void> {
telemetryContext.properties.result = TelemetryResult.Failed;
channelShowAndAppendLine(
channel,
`${operation} operation failed because the project environment needs configuring.`);
channel,
`${operation} operation failed because the project environment needs configuring.`);
const message = `${
operation} operation failed because the project environment needs configuring. Do you want to configure project environment first?`;
operation} operation failed because the project environment needs configuring. Do you want to configure project environment first?`;
const result: vscode.MessageItem|undefined =
await vscode.window.showInformationMessage(
message, DialogResponses.yes, DialogResponses.no);
message, DialogResponses.yes, DialogResponses.no);
if (result === DialogResponses.yes) {
telemetryContext.properties.errorMessage = `${
operation} operation failed and user configures project environment.`;
operation} operation failed and user configures project environment.`;
await ProjectEnvironmentConfiger.configureProjectEnvironmentAsPlatform(
context, channel, telemetryContext, platform, deviceRootPath,
scaffoldType);
context, channel, telemetryContext, platform, deviceRootPath,
scaffoldType);
const message =
`Configuration of project environmnet done. You can run the ${
operation.toLocaleLowerCase()} operation now.`;
operation.toLocaleLowerCase()} operation now.`;
channelShowAndAppendLine(channel, message);
vscode.window.showInformationMessage(message);
} else {
const message = `${
operation} operation failed and user cancels to configure project environment.`;
operation} operation failed and user cancels to configure project environment.`;
throw new CancelOperationError(message);
}
}
@ -288,26 +299,26 @@ export async function askToConfigureEnvironment(
* @param telemetryContext telemetry context
*/
export async function askAndOpenProject(
rootPath: string, workspaceFile: string,
telemetryContext: TelemetryContext): Promise<void> {
rootPath: string, workspaceFile: string,
telemetryContext: TelemetryContext): Promise<void> {
telemetryContext.properties.result = TelemetryResult.Failed;
const message =
`Operation failed because the IoT project is not opened. Current folder contains an IoT project '${
workspaceFile}', do you want to open it?`;
workspaceFile}', do you want to open it?`;
const result: vscode.MessageItem|undefined =
await vscode.window.showInformationMessage(
message, DialogResponses.yes, DialogResponses.no);
message, DialogResponses.yes, DialogResponses.no);
if (result === DialogResponses.yes) {
telemetryContext.properties.errorMessage =
'Operation failed and user opens project folder as workspace.';
const workspaceFilePath = path.join(rootPath, workspaceFile);
await vscode.commands.executeCommand(
IoTCubeCommands.OpenLocally, workspaceFilePath, false);
IoTCubeCommands.OpenLocally, workspaceFilePath, false);
} else {
throw new CancelOperationError(
`Operation failed and user cancels to open current folder as workspace.`);
`Operation failed and user cancels to open current folder as workspace.`);
}
}
@ -318,14 +329,14 @@ export async function askAndOpenProject(
* @param telemetryContext telemetry context
*/
export async function askAndOpenInRemote(
operation: OperationType, telemetryContext: TelemetryContext) {
operation: OperationType, telemetryContext: TelemetryContext): Promise<void> {
telemetryContext.properties.result = TelemetryResult.Failed;
const message = `${
operation} can only be executed in remote container. Do you want to reopen the IoT project in container?`;
operation} can only be executed in remote container. Do you want to reopen the IoT project in container?`;
const result: vscode.MessageItem|undefined =
await vscode.window.showInformationMessage(
message, DialogResponses.yes, DialogResponses.no);
message, DialogResponses.yes, DialogResponses.no);
if (result === DialogResponses.yes) {
telemetryContext.properties.errorMessage =
@ -333,22 +344,22 @@ export async function askAndOpenInRemote(
await RemoteExtension.checkRemoteExtension();
await vscode.commands.executeCommand(
RemoteContainersCommands.ReopenInContainer);
RemoteContainersCommands.ReopenInContainer);
} else {
throw new CancelOperationError(`${
operation} operation failed and user cancels to reopen project in container.`);
operation} operation failed and user cancels to reopen project in container.`);
}
}
const noDeviceSurveyUrl = 'https://www.surveymonkey.com/r/C7NY7KJ';
export async function takeNoDeviceSurvey(
telemetryContext: TelemetryContext, context: vscode.ExtensionContext) {
telemetryContext: TelemetryContext, context: vscode.ExtensionContext): Promise<void> {
const message =
'Could you help to take a quick survey about what IoT development kit(s) you want Azure IoT Device Workbench to support?';
const result: vscode.MessageItem|undefined =
await vscode.window.showWarningMessage(
message, DialogResponses.yes, DialogResponses.cancel);
message, DialogResponses.yes, DialogResponses.cancel);
if (result === DialogResponses.yes) {
// Open the survey page
telemetryContext.properties.message = 'User takes no-device survey.';
@ -360,10 +371,10 @@ export async function takeNoDeviceSurvey(
}
const extensionVersion = extension.packageJSON.version || 'unknown';
await vscode.commands.executeCommand(
VscodeCommands.VscodeOpen,
vscode.Uri.parse(
`${noDeviceSurveyUrl}?o=${encodeURIComponent(process.platform)}&v=${
encodeURIComponent(extensionVersion)}`));
VscodeCommands.VscodeOpen,
vscode.Uri.parse(
`${noDeviceSurveyUrl}?o=${encodeURIComponent(process.platform)}&v=${
encodeURIComponent(extensionVersion)}`));
}
return;
}
@ -388,8 +399,8 @@ export async function getTemplateFilesInfo(templateFolder: string):
sourcePath: fileInfo.sourcePath,
targetPath: fileInfo.targetPath,
overwrite: typeof fileInfo.overwrite !== 'undefined' ?
fileInfo.overwrite :
true, // if it is not defined, we will overwrite the existing file.
fileInfo.overwrite :
true, // if it is not defined, we will overwrite the existing file.
fileContent
});
});
@ -398,7 +409,7 @@ export async function getTemplateFilesInfo(templateFolder: string):
}
export async function generateTemplateFile(
root: string, type: ScaffoldType, fileInfo: TemplateFileInfo) {
root: string, type: ScaffoldType, fileInfo: TemplateFileInfo): Promise<void> {
const targetFolderPath = path.join(root, fileInfo.targetPath);
if (!(await FileUtility.directoryExists(type, targetFolderPath))) {
await FileUtility.mkdirRecursively(type, targetFolderPath);
@ -413,27 +424,15 @@ export async function generateTemplateFile(
}
} catch (error) {
throw new Error(`Failed to create sketch file ${fileInfo.fileName}: ${
error.message}`);
error.message}`);
}
}
return;
}
export function channelShowAndAppend(
channel: vscode.OutputChannel, message: string) {
channel.show();
channel.append(message);
}
export function channelShowAndAppendLine(
channel: vscode.OutputChannel, message: string) {
channel.show();
channel.appendLine(message);
}
export function channelPrintJsonObject(
// tslint:disable-next-line: no-any
channel: vscode.OutputChannel, data: any) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
channel: vscode.OutputChannel, data: any): void {
const indentationSpace = 4;
const jsonString = JSON.stringify(data, null, indentationSpace);
channelShowAndAppendLine(channel, jsonString);
@ -444,32 +443,98 @@ export function channelPrintJsonObject(
* Project or create an IoT Project
*/
export async function handleExternalProject(
telemetryContext: TelemetryContext) {
telemetryContext: TelemetryContext): Promise<void> {
telemetryContext.properties.result = TelemetryResult.Failed;
const message =
'An IoT project is needed to process the operation, do you want to configure current project to be an IoT Embedded Linux Project or create an IoT project?';
class Choice {
static configureAsContainerProject:
MessageItem = {title: 'Configure as Embedded Linux Project'};
static createNewProject: MessageItem = {title: 'Create IoT Project'};
MessageItem = { title: 'Configure as Embedded Linux Project' };
static createNewProject: MessageItem = { title: 'Create IoT Project' };
}
const result: vscode.MessageItem|undefined =
await vscode.window.showInformationMessage(
message, Choice.configureAsContainerProject, Choice.createNewProject);
message, Choice.configureAsContainerProject, Choice.createNewProject);
if (result === Choice.configureAsContainerProject) {
telemetryContext.properties.errorMessage =
'Operation failed and user configures external project to be an IoT Embedded Linux Project';
await vscode.commands.executeCommand(
WorkbenchCommands.ConfigureProjectEnvironment);
WorkbenchCommands.ConfigureProjectEnvironment);
} else if (result === Choice.createNewProject) {
telemetryContext.properties.errorMessage =
'Operation failed and user creates new project';
await vscode.commands.executeCommand(WorkbenchCommands.InitializeProject);
} else {
throw new CancelOperationError(
`Operation failed and user cancels to configure external project.`);
`Operation failed and user cancels to configure external project.`);
}
}
/**
* Get project configs from iot workbench project file
* @param type Scaffold type
*/
export async function getProjectConfig(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: ScaffoldType, iotWorkbenchProjectFilePath: string): Promise<any> {
let projectConfig: {[key: string]: string} = {};
if (await FileUtility.fileExists(type, iotWorkbenchProjectFilePath)) {
const projectConfigContent =
(await FileUtility.readFile(
type, iotWorkbenchProjectFilePath, 'utf8') as string)
.trim();
if (projectConfigContent) {
projectConfig = JSON.parse(projectConfigContent);
}
}
return projectConfig;
}
export function getWorkspaceFile(rootPath: string): string {
const workspaceFiles = fs.readdirSync(rootPath).filter(
file => path.extname(file).endsWith(FileNames.workspaceExtensionName));
if (workspaceFiles && workspaceFiles.length >= 0) {
return workspaceFiles[0];
} else {
return '';
}
}
/**
* Update project host type configuration in iot workbench project file.
* Create one if not exists.
* @param type Scaffold type
*/
export async function updateProjectHostTypeConfig(
type: ScaffoldType, iotWorkbenchProjectFilePath: string,
projectHostType: ProjectHostType): Promise<void> {
try {
if (!iotWorkbenchProjectFilePath) {
throw new Error(`Iot workbench project file path is empty.`);
}
// Get original configs from config file
const projectConfig =
await getProjectConfig(type, iotWorkbenchProjectFilePath);
// Update project host type
projectConfig[`${ConfigKey.projectHostType}`] =
ProjectHostType[projectHostType];
// Add config version for easier backward compatibility in the future.
const workbenchVersion = '1.0.0';
if (!projectConfig[`${ConfigKey.workbenchVersion}`]) {
projectConfig[`${ConfigKey.workbenchVersion}`] = workbenchVersion;
}
await FileUtility.writeJsonFile(
type, iotWorkbenchProjectFilePath, projectConfig);
} catch (error) {
throw new Error(`Update ${
FileNames.iotWorkbenchProjectFileName} file failed: ${error.message}`);
}
}
@ -480,13 +545,13 @@ export async function handleExternalProject(
* @param scaffoldType
*/
export async function configExternalCMakeProjectToIoTContainerProject(
scaffoldType: ScaffoldType): Promise<void> {
scaffoldType: ScaffoldType): Promise<void> {
const projectRootPath = getFirstWorkspaceFolderPath();
// Check if it is a cmake project
const cmakeFile = path.join(projectRootPath, FileNames.cmakeFileName);
if (!await FileUtility.fileExists(scaffoldType, cmakeFile)) {
const message = `Missing ${
FileNames.cmakeFileName} to be configured as Embedded Linux project.`;
FileNames.cmakeFileName} to be configured as Embedded Linux project.`;
vscode.window.showWarningMessage(message);
throw new CancelOperationError(message);
}
@ -496,7 +561,7 @@ export async function configExternalCMakeProjectToIoTContainerProject(
// Update project host type in IoT Workbench Project file
await updateProjectHostTypeConfig(
scaffoldType, iotWorkbenchProjectFile, ProjectHostType.Container);
scaffoldType, iotWorkbenchProjectFile, ProjectHostType.Container);
// Update board Id as Raspberry Pi in IoT Workbench Project file
const projectConfig =
@ -505,73 +570,7 @@ export async function configExternalCMakeProjectToIoTContainerProject(
raspberryPiDeviceModule.RaspberryPiDevice.boardId;
await FileUtility.writeJsonFile(
scaffoldType, iotWorkbenchProjectFile, projectConfig);
}
/**
* Update project host type configuration in iot workbench project file.
* Create one if not exists.
* @param type Scaffold type
*/
export async function updateProjectHostTypeConfig(
type: ScaffoldType, iotWorkbenchProjectFilePath: string,
projectHostType: ProjectHostType): Promise<void> {
try {
if (!iotWorkbenchProjectFilePath) {
throw new Error(`Iot workbench project file path is empty.`);
}
// Get original configs from config file
const projectConfig =
await getProjectConfig(type, iotWorkbenchProjectFilePath);
// Update project host type
projectConfig[`${ConfigKey.projectHostType}`] =
ProjectHostType[projectHostType];
// Add config version for easier backward compatibility in the future.
const workbenchVersion = '1.0.0';
if (!projectConfig[`${ConfigKey.workbenchVersion}`]) {
projectConfig[`${ConfigKey.workbenchVersion}`] = workbenchVersion;
}
await FileUtility.writeJsonFile(
type, iotWorkbenchProjectFilePath, projectConfig);
} catch (error) {
throw new Error(`Update ${
FileNames.iotWorkbenchProjectFileName} file failed: ${error.message}`);
}
}
/**
* Get project configs from iot workbench project file
* @param type Scaffold type
*/
export async function getProjectConfig(
// tslint:disable-next-line: no-any
type: ScaffoldType, iotWorkbenchProjectFilePath: string): Promise<any> {
let projectConfig: {[key: string]: string} = {};
if (await FileUtility.fileExists(type, iotWorkbenchProjectFilePath)) {
const projectConfigContent =
(await FileUtility.readFile(
type, iotWorkbenchProjectFilePath, 'utf8') as string)
.trim();
if (projectConfigContent) {
projectConfig = JSON.parse(projectConfigContent);
}
}
return projectConfig;
}
export function getWorkspaceFile(rootPath: string): string {
const workspaceFiles = fs.readdirSync(rootPath).filter(
file => path.extname(file).endsWith(FileNames.workspaceExtensionName));
if (workspaceFiles && workspaceFiles.length >= 0) {
return workspaceFiles[0];
} else {
return '';
}
scaffoldType, iotWorkbenchProjectFile, projectConfig);
}
/**
@ -579,7 +578,7 @@ export function getWorkspaceFile(rootPath: string): string {
* Ask to open as workspace.
*/
export async function properlyOpenIoTWorkspaceProject(
telemetryContext: TelemetryContext): Promise<void> {
telemetryContext: TelemetryContext): Promise<void> {
const rootPath = getFirstWorkspaceFolderPath();
const workbenchFileName =
path.join(rootPath, 'Device', FileNames.iotWorkbenchProjectFileName);
@ -607,22 +606,22 @@ export function isWorkspaceProject(): boolean {
* check project validation and throw error if any.
*/
export async function constructAndLoadIoTProject(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, isTriggeredWhenExtensionLoad = false) {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, isTriggeredWhenExtensionLoad = false): Promise<IoTWorkbenchProjectBase|undefined> {
const scaffoldType = ScaffoldType.Workspace;
const projectFileRootPath = getFirstWorkspaceFolderPath(false);
const projectHostType = await IoTWorkbenchProjectBase.getProjectType(
scaffoldType, projectFileRootPath);
scaffoldType, projectFileRootPath);
let iotProject;
if (projectHostType === ProjectHostType.Container) {
iotProject = new ioTContainerizedProjectModule.IoTContainerizedProject(
context, channel, telemetryContext, projectFileRootPath);
context, channel, telemetryContext, projectFileRootPath);
} else if (projectHostType === ProjectHostType.Workspace) {
const projectRootPath = path.join(projectFileRootPath, '..');
iotProject = new ioTWorkspaceProjectModule.IoTWorkspaceProject(
context, channel, telemetryContext, projectRootPath);
context, channel, telemetryContext, projectRootPath);
}
if (isTriggeredWhenExtensionLoad) {
@ -652,7 +651,7 @@ export async function constructAndLoadIoTProject(
// Ignore if user cancel operation
if (!(err instanceof CancelOperationError)) {
throw new Error(
`Failed to handle external project. Error: ${err.message}`);
`Failed to handle external project. Error: ${err.message}`);
}
}
}
@ -664,9 +663,9 @@ export async function constructAndLoadIoTProject(
return iotProject;
}
// tslint:disable-next-line: no-any
export function getEnumKeyByEnumValue(myEnum: any, enumValue: any) {
// tslint:disable-next-line: no-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getEnumKeyByEnumValue(myEnum: any, enumValue: any): any {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const keys = Object.keys(myEnum).filter(x => myEnum[x] === enumValue);
const key = keys.length > 0 ? keys[0] : null;
if (key === null) {
@ -676,11 +675,11 @@ export function getEnumKeyByEnumValue(myEnum: any, enumValue: any) {
}
export async function selectPlatform(
type: ScaffoldType,
context: vscode.ExtensionContext): Promise<vscode.QuickPickItem|undefined> {
type: ScaffoldType,
context: vscode.ExtensionContext): Promise<vscode.QuickPickItem|undefined> {
const platformListPath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.platformListFileName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.platformListFileName));
const platformListJsonString =
await FileUtility.readFile(type, platformListPath, 'utf8') as string;
const platformListJson = JSON.parse(platformListJsonString);
@ -693,7 +692,7 @@ export async function selectPlatform(
platformListJson.platforms.forEach((platform: Platform) => {
platformList.push(
{label: platform.name, description: platform.description});
{ label: platform.name, description: platform.description });
});
const platformSelection = await vscode.window.showQuickPick(platformList, {
@ -711,6 +710,40 @@ enum OverwriteLabel {
No = 'No',
YesToAll = 'Yes to all'
}
/**
* Ask whether to overwrite all configuration files
*/
export async function askToOverwriteFile(fileName: string):
Promise<vscode.QuickPickItem> {
const overwriteTasksJsonOption: vscode.QuickPickItem[] = [];
overwriteTasksJsonOption.push(
{
label: OverwriteLabel.No,
detail:
'Do not overwrite existed file and cancel the configuration process.'
},
{
label: OverwriteLabel.YesToAll,
detail: 'Automatically overwrite all configuration files.'
});
const overwriteSelection =
await vscode.window.showQuickPick(overwriteTasksJsonOption, {
ignoreFocusOut: true,
placeHolder: `Configuration file ${
fileName} already exists. Do you want to overwrite all existed configuration files or cancel the configuration process?`
});
if (!overwriteSelection) {
// Selection was cancelled
throw new CancelOperationError(
`Ask to overwrite ${fileName} selection cancelled.`);
}
return overwriteSelection;
}
/**
* If one of any configuration files already exists, ask to overwrite all or
* cancel configuration process.
@ -718,8 +751,8 @@ enum OverwriteLabel {
* configuration process.
*/
export async function askToOverwrite(
scaffoldType: ScaffoldType, projectPath: string,
templateFilesInfo: TemplateFileInfo[]): Promise<boolean> {
scaffoldType: ScaffoldType, projectPath: string,
templateFilesInfo: TemplateFileInfo[]): Promise<boolean> {
// Check whether configuration file exists
for (const fileInfo of templateFilesInfo) {
const targetFilePath =
@ -734,44 +767,12 @@ export async function askToOverwrite(
return true;
}
/**
* Ask whether to overwrite all configuration files
*/
export async function askToOverwriteFile(fileName: string):
Promise<vscode.QuickPickItem> {
const overwriteTasksJsonOption: vscode.QuickPickItem[] = [];
overwriteTasksJsonOption.push(
{
label: OverwriteLabel.No,
detail:
'Do not overwrite existed file and cancel the configuration process.'
},
{
label: OverwriteLabel.YesToAll,
detail: 'Automatically overwrite all configuration files.'
});
const overwriteSelection =
await vscode.window.showQuickPick(overwriteTasksJsonOption, {
ignoreFocusOut: true,
placeHolder: `Configuration file ${
fileName} already exists. Do you want to overwrite all existed configuration files or cancel the configuration process?`
});
if (!overwriteSelection) {
// Selection was cancelled
throw new CancelOperationError(
`Ask to overwrite ${fileName} selection cancelled.`);
}
return overwriteSelection;
}
export async function fetchAndExecuteTask(
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, deviceRootPath: string,
operationType: OperationType, platform: PlatformType,
taskName: string): Promise<void> {
context: vscode.ExtensionContext, channel: vscode.OutputChannel,
telemetryContext: TelemetryContext, deviceRootPath: string,
operationType: OperationType, platform: PlatformType,
taskName: string): Promise<void> {
const scaffoldType = ScaffoldType.Workspace;
if (!await FileUtility.directoryExists(scaffoldType, deviceRootPath)) {
throw new Error('Unable to find the device root folder.');
@ -783,8 +784,8 @@ export async function fetchAndExecuteTask(
channelShowAndAppendLine(channel, message);
await askToConfigureEnvironment(
context, channel, telemetryContext, platform, deviceRootPath,
scaffoldType, operationType);
context, channel, telemetryContext, platform, deviceRootPath,
scaffoldType, operationType);
return;
}
@ -793,12 +794,12 @@ export async function fetchAndExecuteTask(
});
if (!operationTask || operationTask.length < 1) {
const message = `Failed to fetch default ${
operationType.toLowerCase()} task with task name ${taskName}.`;
operationType.toLowerCase()} task with task name ${taskName}.`;
channelShowAndAppendLine(channel, message);
await askToConfigureEnvironment(
context, channel, telemetryContext, platform, deviceRootPath,
scaffoldType, operationType);
context, channel, telemetryContext, platform, deviceRootPath,
scaffoldType, operationType);
return;
}
@ -806,7 +807,7 @@ export async function fetchAndExecuteTask(
await vscode.tasks.executeTask(operationTask[0]);
} catch (error) {
throw new Error(`Failed to execute task to ${
operationType.toLowerCase()}: ${error.message}`);
operationType.toLowerCase()}: ${error.message}`);
}
return;
}
@ -816,18 +817,18 @@ export async function fetchAndExecuteTask(
* overwrite files if any exists
*/
export async function getEnvTemplateFilesAndAskOverwrite(
context: vscode.ExtensionContext, projectPath: string,
scaffoldType: ScaffoldType,
templateName: string): Promise<TemplateFileInfo[]> {
context: vscode.ExtensionContext, projectPath: string,
scaffoldType: ScaffoldType,
templateName: string): Promise<TemplateFileInfo[]> {
if (!projectPath) {
throw new Error(
'Unable to find the project path, please open the folder and initialize project again.');
'Unable to find the project path, please open the folder and initialize project again.');
}
// Get template list json object
const templateJsonFilePath = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.templateFileName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
FileNames.templateFileName));
const templateJsonFileString =
await FileUtility.readFile(scaffoldType, templateJsonFilePath, 'utf8') as
string;
@ -840,17 +841,17 @@ export async function getEnvTemplateFilesAndAskOverwrite(
const projectEnvTemplate: ProjectTemplate[] =
templateJson.templates.filter((template: ProjectTemplate) => {
return (
template.tag === TemplateTag.DevelopmentEnvironment &&
template.tag === TemplateTag.DevelopmentEnvironment &&
template.name === templateName);
});
if (projectEnvTemplate.length === 0) {
throw new Error(
`Fail to get project development environment template files.`);
`Fail to get project development environment template files.`);
}
const templateFolderName = projectEnvTemplate[0].path;
const templateFolder = context.asAbsolutePath(path.join(
FileNames.resourcesFolderName, FileNames.templatesFolderName,
templateFolderName));
FileNames.resourcesFolderName, FileNames.templatesFolderName,
templateFolderName));
const templateFilesInfo: TemplateFileInfo[] =
await getTemplateFilesInfo(templateFolder);
@ -899,7 +900,7 @@ export function shouldShowLandingPage(context: vscode.ExtensionContext):
* @param algorithm hash algorithm
*/
export function getHashFromString(
stringToHash: string, algorithm = 'md5'): string {
stringToHash: string, algorithm = 'md5'): string {
const hash = crypto.createHash(algorithm);
hash.update(stringToHash);
const hashValue = hash.digest('hex');

Просмотреть файл

@ -1,12 +1,12 @@
import * as assert from 'assert';
import * as vscode from 'vscode';
import {AZ3166Device} from '../src/Models/AZ3166Device';
import {ComponentType} from '../src/Models/Interfaces/Component';
import {DeviceType} from '../src/Models/Interfaces/Device';
import {TelemetryContext, TelemetryWorker} from '../src/telemetry';
import { AZ3166Device } from '../src/Models/AZ3166Device';
import { ComponentType } from '../src/Models/Interfaces/Component';
import { DeviceType } from '../src/Models/Interfaces/Device';
import { TelemetryContext, TelemetryWorker } from '../src/telemetry';
import {TestExtensionContext} from './stub';
import { TestExtensionContext } from './stub';
suite('IoT Device Workbench: Device', () => {
// tslint:disable-next-line: only-arrow-functions
@ -16,7 +16,7 @@ suite('IoT Device Workbench: Device', () => {
const telemetryWorker = TelemetryWorker.getInstance(context);
const telemetryContext: TelemetryContext = telemetryWorker.createContext();
const device = new AZ3166Device(context, channel, telemetryContext, '', []);
assert.equal(device.getDeviceType(), DeviceType.MXChip_AZ3166);
assert.equal(device.getDeviceType(), DeviceType.MXChipAZ3166);
assert.equal(device.getComponentType(), ComponentType.Device);
done();
});

Просмотреть файл

@ -3,7 +3,7 @@
// Please refer to their documentation on https://mochajs.org/ for help.
//
import * as vscode from 'vscode';
import {WorkbenchCommands} from '../src/common/Commands';
import { WorkbenchCommands } from '../src/common/Commands';
suite('IoT Device Workbench: Commands Tests', () => {
// tslint:disable-next-line: only-arrow-functions
@ -16,12 +16,13 @@ suite('IoT Device Workbench: Commands Tests', () => {
done('Failed to activate extension');
} else if (!extension.isActive) {
extension.activate().then(
(api) => {
done();
},
() => {
done('Failed to activate extension');
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
(_api) => {
done();
},
() => {
done('Failed to activate extension');
});
} else {
done();
}
@ -29,25 +30,25 @@ suite('IoT Device Workbench: Commands Tests', () => {
// tslint:disable-next-line: only-arrow-functions
test(
'should be able to run command: iotworkbench.exampleInitialize',
function(done) {
this.timeout(60 * 1000);
try {
vscode.commands.executeCommand(WorkbenchCommands.InitializeProject)
.then((result) => {
done();
});
'should be able to run command: iotworkbench.exampleInitialize',
function(done) {
this.timeout(60 * 1000);
try {
vscode.commands.executeCommand(WorkbenchCommands.InitializeProject)
.then(() => {
done();
});
} catch (error) {
done(new Error(error));
}
});
} catch (error) {
done(new Error(error));
}
});
// tslint:disable-next-line: only-arrow-functions
test('should be able to run command: iotworkbench.help', function(done) {
this.timeout(60 * 1000);
try {
vscode.commands.executeCommand(WorkbenchCommands.Help).then((result) => {
vscode.commands.executeCommand(WorkbenchCommands.Help).then(() => {
done();
});

Просмотреть файл

@ -1,8 +1,7 @@
import * as assert from 'assert';
import * as vscode from 'vscode';
import {ConfigHandler} from '../src/configHandler';
import {ConfigKey} from '../src/constants';
import { ConfigHandler } from '../src/configHandler';
import { ConfigKey } from '../src/constants';
suite('IoT Device Workbench: Config', () => {
test('should set and get config value correctly', async function() {

Просмотреть файл

@ -9,13 +9,13 @@ import * as assert from 'assert';
// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
import * as vscode from 'vscode';
import * as myExtension from '../src/extension';
// Defines a Mocha test suite to group tests of similar kind together
suite('IoT Device Workbench Tests', () => {
test('should be present', () => {
assert.ok(
vscode.extensions.getExtension('vsciot-vscode.vscode-iot-workbench'));
vscode.extensions.getExtension('vsciot-vscode.vscode-iot-workbench'));
});
// tslint:disable-next-line:only-arrow-functions
@ -27,12 +27,12 @@ suite('IoT Device Workbench Tests', () => {
done('Failed to activate extension');
} else if (!extension.isActive) {
extension.activate().then(
(api) => {
done();
},
() => {
done('Failed to activate extension');
});
() => {
done();
},
() => {
done('Failed to activate extension');
});
} else {
done();
}

Просмотреть файл

@ -18,7 +18,7 @@ import * as testRunner from 'vscode/lib/testrunner';
// for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test,
// etc.)
// etc.)
useColors: true // colored output from test results
});

Просмотреть файл

@ -1,12 +1,13 @@
import * as vscode from 'vscode';
class DummyMemento implements vscode.Memento {
get<T>(key: string): Promise<T|undefined> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
get<T>(_key: string): Promise<T|undefined> {
return Promise.resolve(undefined);
}
// tslint:disable-next-line: no-any
update(key: string, value: any): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
update(_key: string, _value: any): Promise<void> {
return Promise.resolve();
}
}
@ -21,10 +22,11 @@ class TestExtensionContext implements vscode.ExtensionContext {
storagePath = '';
logPath = '';
asAbsolutePath(relativePath: string): string {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
asAbsolutePath(_relativePath: string): string {
return '';
}
}
export {DummyMemento, TestExtensionContext};
export { DummyMemento, TestExtensionContext };

Просмотреть файл

@ -10,7 +10,10 @@
"es2017"
],
"sourceMap": true,
"rootDir": "."
"rootDir": ".",
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true // Enable several strict checks
},
"include": [
"src/*.ts",

8
vendor/node-usb-native/.eslintrc поставляемый
Просмотреть файл

@ -1,9 +1,10 @@
{
"extends": [
"standard"
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": [
"require-path-exists"
"@typescript-eslint/eslint-plugin"
],
"env": {
"node": true,
@ -20,7 +21,6 @@
"require-path-exists/notEmpty": 2,
"require-path-exists/tooManyArguments": 2,
"semi": [2, "always", {"omitLastInOneLineBlock": true}],
"space-before-function-paren": [2, "never"],
"standard/object-curly-even-spacing": 0
"space-before-function-paren": [2, "never"]
}
}

6
vendor/node-usb-native/lib/bindings.js поставляемый
Просмотреть файл

@ -1,9 +1,9 @@
'use strict';
const path = require('path');
const bindings = require('./native_loader').load(path.join(__dirname, 'native'), 'usb-native');
var listUnix = require('./list-unix');
const listUnix = require('./list-unix');
var linux = process.platform !== 'win32' && process.platform !== 'darwin';
const linux = process.platform !== 'win32' && process.platform !== 'darwin';
function listLinux(callback) {
callback = callback || function(err) {
@ -14,7 +14,7 @@ function listLinux(callback) {
return listUnix(callback);
}
var platformOptions = {};
let platformOptions = {};
if (process.platform !== 'win32') {
platformOptions = {
vmin: 1,

10
vendor/node-usb-native/lib/detector.js поставляемый
Просмотреть файл

@ -1,7 +1,7 @@
var detection = require('./bindings');
var EventEmitter2 = require('eventemitter2').EventEmitter2;
const detection = require('./bindings');
const EventEmitter2 = require('eventemitter2').EventEmitter2;
var detector = new EventEmitter2({
const detector = new EventEmitter2({
wildcard: true,
delimiter: ':',
maxListeners: 1000 // default would be 10!
@ -20,7 +20,7 @@ detector.find = (vid, pid, callback) => {
return new Promise((resolve, reject) => {
// Assemble the optional args into something we can use with `apply`
var args = [];
let args = [];
if (vid) {
args = args.concat(vid);
}
@ -71,7 +71,7 @@ if (detection.registerAdded) {
detector.emit('change', device);
});
var started = true;
let started = true;
detector.startMonitoring = () => {
if (started) {

28
vendor/node-usb-native/lib/list-unix.js поставляемый
Просмотреть файл

@ -1,8 +1,8 @@
'use strict';
var childProcess = require('child_process');
var fs = require('fs');
var path = require('path');
const childProcess = require('child_process');
const fs = require('fs');
const path = require('path');
function promisify(func) {
return (arg) => {
@ -19,7 +19,7 @@ function promisify(func) {
function promisedFilter(func) {
return (data) => {
var shouldKeep = data.map(func);
const shouldKeep = data.map(func);
return Promise.all(shouldKeep).then((keep) => {
return data.filter((path, index) => {
return keep[index];
@ -28,16 +28,16 @@ function promisedFilter(func) {
};
}
var statAsync = promisify(fs.stat);
var readdirAsync = promisify(fs.readdir);
var execAsync = promisify(childProcess.exec);
const statAsync = promisify(fs.stat);
const readdirAsync = promisify(fs.readdir);
const execAsync = promisify(childProcess.exec);
function udevParser(output) {
var udevInfo = output.split('\n').reduce((info, line) => {
const udevInfo = output.split('\n').reduce((info, line) => {
if (!line || line.trim() === '') {
return info;
}
var parts = line.split('=').map((part) => {
const parts = line.split('=').map((part) => {
return part.trim();
});
@ -46,7 +46,7 @@ function udevParser(output) {
return info;
}, {});
var pnpId;
let pnpId;
if (udevInfo.devlinks) {
udevInfo.devlinks.split(' ').forEach((path) => {
if (path.indexOf('/by-id/') === -1) { return }
@ -54,12 +54,12 @@ function udevParser(output) {
});
}
var vendorId = udevInfo.id_vendor_id;
let vendorId = udevInfo.id_vendor_id;
if (vendorId && vendorId.substring(0, 2) !== '0x') {
vendorId = `0x${vendorId}`;
}
var productId = udevInfo.id_model_id;
let productId = udevInfo.id_model_id;
if (productId && productId.substring(0, 2) !== '0x') {
productId = `0x${productId}`;
}
@ -85,12 +85,12 @@ function checkPathAndDevice(path) {
}
function lookupPort(file) {
var udevadm = `udevadm info --query=property -p $(udevadm info -q path -n ${file})`;
const udevadm = `udevadm info --query=property -p $(udevadm info -q path -n ${file})`;
return execAsync(udevadm).then(udevParser);
}
function listUnix(callback) {
var dirName = '/dev';
const dirName = '/dev';
readdirAsync(dirName)
.catch((err) => {
// if this directory is not found we just pretend everything is OK

4
vendor/node-usb-native/lib/native_loader.js поставляемый
Просмотреть файл

@ -7,10 +7,10 @@ const loadLibrary = function(parentFolder, libraryName) {
const nodepregypFiles = glob(`${parentFolder.replace(/\\/g, '/')}/${libraryName}*${process.arch}*.node`, {
sync: true
});
var binding = null;
let binding = null;
nodegypFiles.concat(nodepregypFiles).forEach((file) => {
try {
var _temp = require(file);
const _temp = require(file);
binding = _temp;
console.log('using', file);
} catch (e) {

14
vendor/node-usb-native/lib/parsers.js поставляемый
Просмотреть файл

@ -13,12 +13,12 @@ module.exports = {
if (typeof delimiter === 'undefined' || delimiter === null) { delimiter = '\r' }
if (typeof encoding === 'undefined' || encoding === null) { encoding = 'utf8' }
// Delimiter buffer saved in closure
var data = '';
let data = '';
return function(emitter, buffer) {
// Collect data
data += buffer.toString(encoding);
// Split collected data by delimiter
var parts = data.split(delimiter);
const parts = data.split(delimiter);
data = parts.pop();
parts.forEach((part) => {
emitter.emit('data', part);
@ -28,11 +28,11 @@ module.exports = {
// Emit a data event every `length` bytes
byteLength: function(length) {
var data = Buffer.alloc(0);
let data = Buffer.alloc(0);
return function(emitter, buffer) {
data = Buffer.concat([data, buffer]);
while (data.length >= length) {
var out = data.slice(0, length);
const out = data.slice(0, length);
data = data.slice(length);
emitter.emit('data', out);
}
@ -45,10 +45,10 @@ module.exports = {
if (Object.prototype.toString.call(delimiter) !== '[object Array]') {
delimiter = [ delimiter ];
}
var buf = [];
var nextDelimIndex = 0;
let buf = [];
let nextDelimIndex = 0;
return function(emitter, buffer) {
for (var i = 0; i < buffer.length; i++) {
for (let i = 0; i < buffer.length; i++) {
buf[buf.length] = buffer[i];
if (buf[buf.length - 1] === delimiter[nextDelimIndex]) {
nextDelimIndex++;

62
vendor/node-usb-native/lib/serialport.js поставляемый
Просмотреть файл

@ -9,26 +9,26 @@ const debug = (message) => {
// shims
// Internal Dependencies
var SerialPortBinding = require('./bindings');
var parsers = require('./parsers');
const SerialPortBinding = require('./bindings');
const parsers = require('./parsers');
// Built-ins Dependencies
var fs = require('fs');
var stream = require('stream');
var util = require('util');
const fs = require('fs');
const stream = require('stream');
const util = require('util');
// VALIDATION ARRAYS
var DATABITS = [5, 6, 7, 8];
var STOPBITS = [1, 1.5, 2];
var PARITY = ['none', 'even', 'mark', 'odd', 'space'];
var FLOWCONTROLS = ['xon', 'xoff', 'xany', 'rtscts'];
var SET_OPTIONS = ['brk', 'cts', 'dtr', 'dts', 'rts'];
const DATABITS = [5, 6, 7, 8];
const STOPBITS = [1, 1.5, 2];
const PARITY = ['none', 'even', 'mark', 'odd', 'space'];
const FLOWCONTROLS = ['xon', 'xoff', 'xany', 'rtscts'];
const SET_OPTIONS = ['brk', 'cts', 'dtr', 'dts', 'rts'];
// Stuff from ReadStream, refactored for our usage:
var kPoolSize = 40 * 1024;
var kMinPoolSpace = 128;
const kPoolSize = 40 * 1024;
const kMinPoolSpace = 128;
var defaultSettings = {
const defaultSettings = {
baudRate: 9600,
autoOpen: true,
parity: 'none',
@ -45,7 +45,7 @@ var defaultSettings = {
platformOptions: SerialPortBinding.platformOptions
};
var defaultSetFlags = {
const defaultSetFlags = {
brk: false,
cts: false,
dtr: true,
@ -54,7 +54,7 @@ var defaultSetFlags = {
};
// deprecate the lowercase version of these options next major release
var LOWERCASE_OPTIONS = [
const LOWERCASE_OPTIONS = [
'baudRate',
'dataBits',
'stopBits',
@ -64,9 +64,9 @@ var LOWERCASE_OPTIONS = [
function correctOptions(options) {
LOWERCASE_OPTIONS.forEach((name) => {
var lowerName = name.toLowerCase();
const lowerName = name.toLowerCase();
if (options.hasOwnProperty(lowerName)) {
var value = options[lowerName];
const value = options[lowerName];
delete options[lowerName];
options[name] = value;
}
@ -94,8 +94,8 @@ function SerialPort(path, options, callback) {
this.path = path;
var correctedOptions = correctOptions(options);
var settings = Object.assign({}, defaultSettings, correctedOptions);
const correctedOptions = correctOptions(options);
const settings = Object.assign({}, defaultSettings, correctedOptions);
if (typeof settings.baudRate !== 'number') {
throw new TypeError(`Invalid "baudRate" must be a number got: ${settings.baudRate}`);
@ -198,8 +198,8 @@ SerialPort.prototype.update = function(options, callback) {
return this._error(new Error('Port is not open'), callback);
}
var correctedOptions = correctOptions(options);
var settings = Object.assign({}, defaultSettings, correctedOptions);
const correctedOptions = correctOptions(options);
const settings = Object.assign({}, defaultSettings, correctedOptions);
this.options.baudRate = settings.baudRate;
SerialPortBinding.update(this.fd, this.options, (err) => {
@ -256,10 +256,10 @@ if (process.platform !== 'win32') {
// Grab another reference to the pool in the case that while we're in the
// thread pool another read() finishes up the pool, and allocates a new
// one.
var toRead = Math.min(this.pool.length - this.pool.used, ~~this.bufferSize);
var start = this.pool.used;
const toRead = Math.min(this.pool.length - this.pool.used, ~~this.bufferSize);
const start = this.pool.used;
var _afterRead = (err, bytesRead, readPool, bytesRequested) => {
const _afterRead = (err, bytesRead, readPool, bytesRequested) => {
this.reading = false;
if (err) {
if (err.code && err.code === 'EAGAIN') {
@ -286,7 +286,7 @@ if (process.platform !== 'win32') {
this.serialPoller.start();
}
} else {
var b = this.pool.slice(start, start + bytesRead);
const b = this.pool.slice(start, start + bytesRead);
// do not emit events if the stream is paused
if (this.paused) {
@ -307,8 +307,8 @@ if (process.platform !== 'win32') {
};
fs.read(this.fd, this.pool, this.pool.used, toRead, null, (err, bytesRead) => {
var readPool = this.pool;
var bytesRequested = toRead;
const readPool = this.pool;
const bytesRequested = toRead;
_afterRead(err, bytesRead, readPool, bytesRequested);
});
@ -327,7 +327,7 @@ if (process.platform !== 'win32') {
this.paused = false;
if (this.buffer) {
var buffer = this.buffer;
const buffer = this.buffer;
this.buffer = null;
this._emitData(buffer);
}
@ -432,9 +432,9 @@ SerialPort.prototype.set = function(options, callback) {
options = {};
}
var settings = {};
for (var i = SET_OPTIONS.length - 1; i >= 0; i--) {
var flag = SET_OPTIONS[i];
const settings = {};
for (let i = SET_OPTIONS.length - 1; i >= 0; i--) {
const flag = SET_OPTIONS[i];
if (options[flag] !== undefined) {
settings[flag] = options[flag];
} else {

Просмотреть файл

@ -1,7 +1,8 @@
const callbackStack = [];
// eslint-disable-next-line no-undef
const vscode = acquireVsCodeApi();
var example = new Vue({
const example = new Vue({
el: '#main',
data: {
version: '',
@ -18,8 +19,8 @@ var example = new Vue({
'https://raw.githubusercontent.com/VSChina/azureiotdevkit_tools/gallery/workbench-example-devkit-v2.json';
this.boardId = query.board || '';
httpRequest(url, function(data) {
var examples = [];
var aside = [];
let examples = [];
let aside = [];
try {
if (data) {
data = JSON.parse(data);
@ -36,7 +37,7 @@ var example = new Vue({
document.getElementById('main').className = 'no-aside';
}
for (var i = 0; i < examples.length; i++) {
for (let i = 0; i < examples.length; i++) {
examples[i].fullDescription = examples[i].description;
if (examples[i].featured && !this.featuredExample) {
this.featuredExample = examples.splice(i, 1)[0];
@ -56,7 +57,7 @@ var example = new Vue({
}
if (example.name) {
let project_name = example.name.replace(/[^a-z0-9]/ig, '_').toLowerCase();
const project_name = example.name.replace(/[^a-z0-9]/ig, '_').toLowerCase();
return project_name;
}
@ -79,7 +80,7 @@ function openLink(url, example) {
}
command('iotworkbench.openUri', url);
if (example) {
command('iotworkbench.sendTelemetry', {example});
command('iotworkbench.sendTelemetry', { example });
}
}
@ -98,7 +99,7 @@ function parseQuery(url) {
return {};
}
const query = url.split('?')[1].split('&');
let res = {};
const res = {};
query.forEach(q => {
const item = q.split('=');
res[item[0]] = item[1] ? decodeURIComponent(item[1]) : undefined;
@ -108,14 +109,14 @@ function parseQuery(url) {
}
function generateSection(obj, className) {
let section = document.createElement('div');
const section = document.createElement('div');
section.className = 'section';
if (className) {
section.className += ' ' + className;
}
if (obj.title) {
let title = document.createElement('h1');
const title = document.createElement('h1');
title.innerText = obj.title;
section.appendChild(title);
}
@ -123,12 +124,12 @@ function generateSection(obj, className) {
}
function generateLinks(obj) {
let section = generateSection(obj, 'quick-links');
const section = generateSection(obj, 'quick-links');
if (obj.items && obj.items.length) {
let ulEl = document.createElement('ul');
const ulEl = document.createElement('ul');
ulEl.className = 'links';
obj.items.forEach((link) => {
let linkEl = document.createElement('li');
const linkEl = document.createElement('li');
linkEl.innerText = link.text;
linkEl.addEventListener('click', () => {
openLink(link.url);
@ -141,14 +142,14 @@ function generateLinks(obj) {
}
function generateTable(obj) {
let section = generateSection(obj, 'info');
const section = generateSection(obj, 'info');
if (obj.rows && obj.rows.length) {
let tableEl = document.createElement('table');
const tableEl = document.createElement('table');
obj.rows.forEach((row) => {
if (row.length) {
let trEl = document.createElement('tr');
const trEl = document.createElement('tr');
row.forEach((col) => {
let tdEl = document.createElement('td');
const tdEl = document.createElement('td');
tdEl.innerText = col.text;
if (col.url) {
tdEl.className = 'link';
@ -167,16 +168,16 @@ function generateTable(obj) {
}
function generateText(obj) {
let section = generateSection(obj);
let pEl = document.createElement('p');
const section = generateSection(obj);
const pEl = document.createElement('p');
pEl.innerText = obj.text;
section.appendChild(pEl);
return section;
}
function generateImage(obj) {
let section = generateSection(obj);
let imgEl = document.createElement('img');
const section = generateSection(obj);
const imgEl = document.createElement('img');
imgEl.src = obj.src;
if (obj.url) {
imgEl.className = 'link';
@ -189,10 +190,10 @@ function generateImage(obj) {
}
function generateBadge(obj) {
let section = generateSection(obj, 'badge');
const section = generateSection(obj, 'badge');
if (obj.items && obj.items.length) {
obj.items.forEach((item) => {
let spanEl = document.createElement('span');
const spanEl = document.createElement('span');
spanEl.className = item.icon;
spanEl.innerText = item.text;
if (item.url) {
@ -208,33 +209,33 @@ function generateBadge(obj) {
}
function generateFeed(obj) {
let section = generateSection(obj, 'blog');
const section = generateSection(obj, 'blog');
httpRequest(obj.url, function(data) {
let parser = new DOMParser();
let xmlDoc = parser.parseFromString(data,'text/xml');
let items = xmlDoc.getElementsByTagName('item');
let ulEl = document.createElement('ul');
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(data,'text/xml');
const items = xmlDoc.getElementsByTagName('item');
const ulEl = document.createElement('ul');
ulEl.className = 'blog';
for (let i = 0; i < Math.min(items.length, 3); i++) {
let title = items[i].getElementsByTagName('title')[0].textContent;
let link = items[i].getElementsByTagName('link')[0].textContent;
let date = new Date(items[i].getElementsByTagName('pubDate')[0].textContent).toISOString().slice(0, 10);
let description = items[i].getElementsByTagName('description')[0].textContent;
const title = items[i].getElementsByTagName('title')[0].textContent;
const link = items[i].getElementsByTagName('link')[0].textContent;
const date = new Date(items[i].getElementsByTagName('pubDate')[0].textContent).toISOString().slice(0, 10);
const description = items[i].getElementsByTagName('description')[0].textContent;
let liEl = document.createElement('li');
let h2El = document.createElement('h2');
const liEl = document.createElement('li');
const h2El = document.createElement('h2');
h2El.innerText = title;
h2El.addEventListener('click', () => {
openLink(link);
});
liEl.appendChild(h2El);
let divEl = document.createElement('div');
const divEl = document.createElement('div');
divEl.className = 'date';
divEl.innerText = date;
liEl.appendChild(divEl);
let pEl = document.createElement('p');
const pEl = document.createElement('p');
pEl.innerHTML = description;
pEl.innerText = pEl.innerText;
liEl.appendChild(pEl);
@ -253,26 +254,26 @@ function generateAside(data) {
data.forEach(item => {
let section;
switch(item.type) {
case 'links':
section = generateLinks(item);
break;
case 'table':
section = generateTable(item);
break;
case 'text':
section = generateText(item);
break;
case 'image':
section = generateImage(item);
break;
case 'badge':
section = generateBadge(item);
break;
case 'feed':
section = generateFeed(item);
break;
default:
break;
case 'links':
section = generateLinks(item);
break;
case 'table':
section = generateTable(item);
break;
case 'text':
section = generateText(item);
break;
case 'image':
section = generateImage(item);
break;
case 'badge':
section = generateBadge(item);
break;
case 'feed':
section = generateFeed(item);
break;
default:
break;
}
if (section) {
@ -286,7 +287,7 @@ function command(cmd, callback) {
if (!cmd) {
return;
}
let args = Array.from(arguments);
const args = Array.from(arguments);
if (typeof args[args.length - 1] === 'function') {
callback = args[args.length - 1];
args.length = args.length - 1;

17961
views/vue.js поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -42,21 +42,21 @@ function getDependeciesFromNpm(mod) {
/**@type {import('webpack').Configuration}*/
const config = {
target: 'node',
target: 'node',
entry: getEntry(),
output: {
path: path.resolve(__dirname, 'out/node_modules'),
filename: '[name].js',
libraryTarget: "commonjs2",
devtoolModuleFilenameTemplate: "../[resource-path]",
},
externals: {
vscode: "commonjs vscode"
},
resolve: {
extensions: ['.js', '.json']
}
entry: getEntry(),
output: {
path: path.resolve(__dirname, 'out/node_modules'),
filename: '[name].js',
libraryTarget: "commonjs2",
devtoolModuleFilenameTemplate: "../[resource-path]",
},
externals: {
vscode: "commonjs vscode"
},
resolve: {
extensions: ['.js', '.json']
}
}
module.exports = config;