Renable Strict TSLint (#5018)

* removes more builder references

* remove builder from profiler

* formatting

* fix profiler dailog

* remove builder from oatuhdialog

* remove the rest of builder references

* formatting

* add more strict null checks to base

* enable strict tslint rules

* fix formatting

* fix compile error

* fix the rest of the hygeny issues and add pipeline step

* fix pipeline files
This commit is contained in:
Anthony Dresser
2019-04-18 00:34:53 -07:00
committed by GitHub
parent b852f032d3
commit ddd89fc52a
431 changed files with 3147 additions and 3789 deletions

View File

@@ -24,12 +24,27 @@ steps:
- script: |
yarn
displayName: 'Install'
displayName: 'Install'
- script: |
node_modules/.bin/gulp electron
node_modules/.bin/gulp compile --max_old_space_size=4096
displayName: 'Scripts'
yarn gulp electron-x64
displayName: Download Electron
- script: |
yarn gulp hygiene
displayName: Run Hygiene Checks
- script: |
yarn tslint
displayName: 'Run TSLint'
- script: |
yarn strict-null-check
displayName: 'Run Strict Null Check'
- script: |
yarn compile
displayName: 'Compile'
- script: |
DISPLAY=:10 ./scripts/test.sh --reporter mocha-junit-reporter
@@ -39,11 +54,3 @@ steps:
inputs:
testResultsFiles: '**/test-results.xml'
condition: succeededOrFailed()
- script: |
yarn tslint
displayName: 'Run TSLint'
- script: |
yarn strict-null-check
displayName: 'Run Strict Null Check'

View File

@@ -9,11 +9,23 @@ steps:
displayName: 'Yarn Install'
- script: |
.\node_modules\.bin\gulp electron
yarn gulp electron-x64
displayName: 'Electron'
- script: |
npm run compile
yarn gulp hygiene
displayName: Run Hygiene Checks
- script: |
yarn tslint
displayName: 'Run TSLint'
- script: |
yarn strict-null-check
displayName: 'Run Strict Null Check'
- script: |
yarn compile
displayName: 'Compile'
- script: |
@@ -24,11 +36,3 @@ steps:
inputs:
testResultsFiles: 'test-results.xml'
condition: succeededOrFailed()
- script: |
yarn tslint
displayName: 'Run TSLint'
- script: |
yarn strict-null-check
displayName: 'Run Strict Null Check'

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';

View File

@@ -90,7 +90,13 @@ const indentationFilter = [
'!**/Dockerfile.*',
'!**/*.Dockerfile',
'!**/*.dockerfile',
'!extensions/markdown-language-features/media/*.js'
'!extensions/markdown-language-features/media/*.js',
// {{SQL CARBON EDIT}}
'!**/*.xlf',
'!**/*.docx',
'!**/*.sql',
'!extensions/mssql/sqltoolsservice/**',
'!extensions/import/flatfileimportservice/**',
];
const copyrightFilter = [
@@ -119,7 +125,36 @@ const copyrightFilter = [
'!resources/completions/**',
'!extensions/markdown-language-features/media/highlight.css',
'!extensions/html-language-features/server/src/modes/typescript/*',
'!extensions/*/server/bin/*'
'!extensions/*/server/bin/*',
// {{SQL CARBON EDIT}}
'!extensions/notebook/src/intellisense/text.ts',
'!extensions/mssql/src/objectExplorerNodeProvider/webhdfs.ts',
'!src/sql/workbench/parts/notebook/outputs/tableRenderers.ts',
'!src/sql/workbench/parts/notebook/outputs/common/url.ts',
'!src/sql/workbench/parts/notebook/outputs/common/renderMimeInterfaces.ts',
'!src/sql/workbench/parts/notebook/outputs/common/outputProcessor.ts',
'!src/sql/workbench/parts/notebook/outputs/common/mimemodel.ts',
'!src/sql/workbench/parts/notebook/cellViews/media/output.css',
'!src/sql/base/browser/ui/table/plugins/rowSelectionModel.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/rowDetailView.ts',
'!src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/checkboxSelectColumn.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/cellSelectionModel.plugin.ts',
'!src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts',
'!src/sql/workbench/parts/notebook/outputs/sanitizer.ts',
'!src/sql/workbench/parts/notebook/outputs/renderers.ts',
'!src/sql/workbench/parts/notebook/outputs/registry.ts',
'!src/sql/workbench/parts/notebook/outputs/factories.ts',
'!src/sql/workbench/parts/notebook/models/nbformat.ts',
'!extensions/markdown-language-features/media/tomorrow.css',
'!src/sql/parts/modelComponents/highlight.css',
'!extensions/mssql/sqltoolsservice/**',
'!extensions/import/flatfileimportservice/**',
'!extensions/notebook/src/prompts/**',
'!extensions/mssql/src/prompts/**',
'!extensions/notebook/resources/jupyter_config/**',
'!**/*.gif',
'!**/*.xlf'
];
const eslintFilter = [
@@ -165,8 +200,7 @@ gulp.task('eslint', () => {
});
gulp.task('tslint', () => {
// {{SQL CARBON EDIT}}
const options = { emitError: false };
const options = { emitError: true };
return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
.pipe(filter(tslintFilter))
@@ -264,9 +298,8 @@ function hygiene(some) {
.pipe(filter(f => !f.stat.isDirectory()))
.pipe(filter(indentationFilter))
.pipe(indentation)
.pipe(filter(copyrightFilter));
// {{SQL CARBON EDIT}}
// .pipe(copyrights);
.pipe(filter(copyrightFilter))
.pipe(copyrights);
const typescript = result
.pipe(filter(tslintFilter))
@@ -276,15 +309,38 @@ function hygiene(some) {
const javascript = result
.pipe(filter(eslintFilter))
.pipe(gulpeslint('src/.eslintrc'))
.pipe(gulpeslint.formatEach('compact'));
// {{SQL CARBON EDIT}}
// .pipe(gulpeslint.failAfterError());
.pipe(gulpeslint.formatEach('compact'))
.pipe(gulpeslint.failAfterError());
let count = 0;
return es.merge(typescript, javascript)
.pipe(es.through(function (data) {
// {{SQL CARBON EDIT}}
this.emit('end');
count++;
if (process.env['TRAVIS'] && count % 10 === 0) {
process.stdout.write('.');
}
this.emit('data', data);
}, function () {
process.stdout.write('\n');
const tslintResult = tsLinter.getResult();
if (tslintResult.failures.length > 0) {
for (const failure of tslintResult.failures) {
const name = failure.getFileName();
const position = failure.getStartPosition();
const line = position.getLineAndCharacter().line;
const character = position.getLineAndCharacter().character;
console.error(`${name}:${line + 1}:${character + 1}:${failure.getFailure()}`);
}
errorCount += tslintResult.failures.length;
}
if (errorCount > 0) {
this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
} else {
this.emit('end');
}
}));
}

View File

@@ -6,21 +6,12 @@
'use strict';
const gulp = require('gulp');
const json = require('gulp-json-editor');
const buffer = require('gulp-buffer');
const filter = require('gulp-filter');
const es = require('event-stream');
const vfs = require('vinyl-fs');
const pkg = require('../package.json');
const cp = require('child_process');
const fancyLog = require('fancy-log');
const ansiColors = require('ansi-colors');
// {{SQL CARBON EDIT}}
const jeditor = require('gulp-json-editor');
gulp.task('mixin', function () {
// {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}}
const updateUrl = process.env['SQLOPS_UPDATEURL'];
if (!updateUrl) {
console.log('Missing SQLOPS_UPDATEURL, skipping mixin');

View File

@@ -28,7 +28,6 @@ const formatFiles = (some) => {
console.info('ran formatting on file ' + file.path + ' result: ' + result.message);
if (result.error) {
console.error(result.message);
errorCount++;
}
cb(null, file);
@@ -40,7 +39,7 @@ const formatFiles = (some) => {
.pipe(filter(f => !f.stat.isDirectory()))
.pipe(formatting);
}
};
const formatStagedFiles = () => {
const cp = require('child_process');
@@ -81,4 +80,4 @@ const formatStagedFiles = () => {
process.exit(1);
});
});
}
};

View File

@@ -27,7 +27,7 @@ function getDebPackageArch(arch) {
}
function prepareDebPackage(arch) {
// {{SQL CARBON EDIT}}
// {{SQL CARBON EDIT}}
const binaryDir = '../azuredatastudio-linux-' + arch;
const debArch = getDebPackageArch(arch);
const destination = '.build/linux/deb/' + debArch + '/' + product.applicationName + '-' + debArch;

View File

@@ -27,7 +27,7 @@ const zipPath = arch => path.join(zipDir(arch), `VSCode-win32-${arch}.zip`);
const setupDir = (arch, target) => path.join(repoPath, '.build', `win32-${arch}`, `${target}-setup`);
const issPath = path.join(__dirname, 'win32', 'code.iss');
const innoSetupPath = path.join(path.dirname(path.dirname(require.resolve('innosetup-compiler'))), 'bin', 'ISCC.exe');
const signPS1 = path.join(repoPath, 'build', 'azure-pipelines', 'win32', 'sign.ps1');
// const signPS1 = path.join(repoPath, 'build', 'azure-pipelines', 'win32', 'sign.ps1');
function packageInnoSetup(iss, options, cb) {
options = options || {};

View File

@@ -1,3 +1,3 @@
{
"adminToolExtWin.launchSsmsServerPropertiesDialog": "Properties"
"adminToolExtWin.launchSsmsServerPropertiesDialog": "Properties"
}

View File

@@ -1,12 +1,12 @@
{
"downloadUrl": "https://sqlopsextensions.blob.core.windows.net/tools/ssmsmin/{#version#}/{#fileName#}",
"version": "15.0.18092.0",
"downloadFileNames": {
"Windows_64": "SsmsMin-15.0.18092.0-win-x64.zip",
"Windows_86": "SsmsMin-15.0.18092.0-win-x86.zip"
},
"installDirectory": "ssmsmin/{#platform#}/{#version#}",
"executableFiles": [
"SsmsMin.exe"
]
"downloadUrl": "https://sqlopsextensions.blob.core.windows.net/tools/ssmsmin/{#version#}/{#fileName#}",
"version": "15.0.18092.0",
"downloadFileNames": {
"Windows_64": "SsmsMin-15.0.18092.0-win-x64.zip",
"Windows_86": "SsmsMin-15.0.18092.0-win-x86.zip"
},
"installDirectory": "ssmsmin/{#platform#}/{#version#}",
"executableFiles": [
"SsmsMin.exe"
]
}

View File

@@ -2,8 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
///
'use strict';
import * as nls from 'vscode-nls';
import * as path from 'path';
@@ -12,8 +10,7 @@ import * as vscode from 'vscode';
import { IConfig, ServerProvider } from 'service-downloader';
import { Telemetry } from './telemetry';
import * as utils from './utils';
import { ChildProcess, exec, ExecException } from 'child_process';
import { stringify } from 'querystring';
import { ChildProcess, exec } from 'child_process';
const baseConfig = require('./config.json');
const localize = nls.loadMessageBundle();
@@ -116,9 +113,9 @@ function launchSsmsDialog(action: string, connectionProfile: azdata.IConnectionP
let args = buildSsmsMinCommandArgs(params);
// This will be an async call since we pass in the callback
var proc: ChildProcess = exec(
/*command*/`"${exePath}" ${args}`,
/*options*/undefined,
let proc: ChildProcess = exec(
/*command*/`"${exePath}" ${args}`,
/*options*/undefined,
(execException, stdout, stderr) => {
// Process has exited so remove from map of running processes
runningProcesses.delete(proc.pid);

View File

@@ -13,123 +13,123 @@ import * as Utils from './utils';
const packageJson = require('../package.json');
export interface ITelemetryEventProperties {
[key: string]: string;
[key: string]: string;
}
export interface ITelemetryEventMeasures {
[key: string]: number;
[key: string]: number;
}
/**
* Filters error paths to only include source files. Exported to support testing
*/
export function filterErrorPath(line: string): string {
if (line) {
let values: string[] = line.split('/out/');
if (values.length <= 1) {
// Didn't match expected format
return line;
} else {
return values[1];
}
}
if (line) {
let values: string[] = line.split('/out/');
if (values.length <= 1) {
// Didn't match expected format
return line;
} else {
return values[1];
}
}
}
export class Telemetry {
private static reporter: TelemetryReporter;
private static userId: string;
private static platformInformation: PlatformInformation;
private static disabled: boolean;
private static reporter: TelemetryReporter;
private static userId: string;
private static platformInformation: PlatformInformation;
private static disabled: boolean;
public static getPlatformInformation(): Promise<PlatformInformation> {
if (this.platformInformation) {
return Promise.resolve(this.platformInformation);
} else {
return new Promise<PlatformInformation>(resolve => {
PlatformInformation.getCurrent().then(info => {
this.platformInformation = info;
resolve(this.platformInformation);
});
});
}
}
public static getPlatformInformation(): Promise<PlatformInformation> {
if (this.platformInformation) {
return Promise.resolve(this.platformInformation);
} else {
return new Promise<PlatformInformation>(resolve => {
PlatformInformation.getCurrent().then(info => {
this.platformInformation = info;
resolve(this.platformInformation);
});
});
}
}
/**
* Disable telemetry reporting
*/
public static disable(): void {
this.disabled = true;
}
/**
* Disable telemetry reporting
*/
public static disable(): void {
this.disabled = true;
}
/**
* Initialize the telemetry reporter for use.
*/
public static initialize(): void {
if (typeof this.reporter === 'undefined') {
// Check if the user has opted out of telemetry
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
this.disable();
return;
}
/**
* Initialize the telemetry reporter for use.
*/
public static initialize(): void {
if (typeof this.reporter === 'undefined') {
// Check if the user has opted out of telemetry
if (!vscode.workspace.getConfiguration('telemetry').get<boolean>('enableTelemetry', true)) {
this.disable();
return;
}
let packageInfo = Utils.getPackageInfo(packageJson);
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
}
}
let packageInfo = Utils.getPackageInfo(packageJson);
this.reporter = new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey);
}
}
/**
* Send a telemetry event for an exception
*/
public static sendTelemetryEventForException(
err: any, methodName: string, extensionConfigName: string): void {
try {
let stackArray: string[];
let firstLine: string = '';
if (err !== undefined && err.stack !== undefined) {
stackArray = err.stack.split('\n');
if (stackArray !== undefined && stackArray.length >= 2) {
firstLine = stackArray[1]; // The first line is the error message and we don't want to send that telemetry event
firstLine = filterErrorPath(firstLine);
}
}
/**
* Send a telemetry event for an exception
*/
public static sendTelemetryEventForException(
err: any, methodName: string, extensionConfigName: string): void {
try {
let stackArray: string[];
let firstLine: string = '';
if (err !== undefined && err.stack !== undefined) {
stackArray = err.stack.split('\n');
if (stackArray !== undefined && stackArray.length >= 2) {
firstLine = stackArray[1]; // The first line is the error message and we don't want to send that telemetry event
firstLine = filterErrorPath(firstLine);
}
}
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
} catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
console.error('Failed to send telemetry event. error: ' + telemetryErr, extensionConfigName);
}
}
// Only adding the method name and the fist line of the stack trace. We don't add the error message because it might have PII
this.sendTelemetryEvent('Exception', { methodName: methodName, errorLine: firstLine });
} catch (telemetryErr) {
// If sending telemetry event fails ignore it so it won't break the extension
console.error('Failed to send telemetry event. error: ' + telemetryErr, extensionConfigName);
}
}
/**
* Send a telemetry event using application insights
*/
public static sendTelemetryEvent(
eventName: string,
properties?: ITelemetryEventProperties,
measures?: ITelemetryEventMeasures): void {
/**
* Send a telemetry event using application insights
*/
public static sendTelemetryEvent(
eventName: string,
properties?: ITelemetryEventProperties,
measures?: ITelemetryEventMeasures): void {
if (typeof this.disabled === 'undefined') {
this.disabled = false;
}
if (typeof this.disabled === 'undefined') {
this.disabled = false;
}
if (this.disabled || typeof (this.reporter) === 'undefined') {
// Don't do anything if telemetry is disabled
return;
}
if (this.disabled || typeof (this.reporter) === 'undefined') {
// Don't do anything if telemetry is disabled
return;
}
if (!properties || typeof properties === 'undefined') {
properties = {};
}
if (!properties || typeof properties === 'undefined') {
properties = {};
}
// Augment the properties structure with additional common properties before sending
Promise.all([this.getPlatformInformation()]).then(() => {
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
// Augment the properties structure with additional common properties before sending
Promise.all([this.getPlatformInformation()]).then(() => {
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
this.reporter.sendTelemetryEvent(eventName, properties, measures);
});
}
this.reporter.sendTelemetryEvent(eventName, properties, measures);
});
}
}
Telemetry.initialize();

View File

@@ -9,20 +9,20 @@ const testRunner = require('vscode/lib/testrunner');
const suite = 'Database Admin Tool Extensions for Windows';
const options: any = {
ui: 'bdd',
useColors: true,
timeout: 600000
ui: 'bdd',
useColors: true,
timeout: 600000
};
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
options.reporter = 'mocha-multi-reporters';
options.reporterOptions = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
testsuitesTitle: `${suite} ${process.platform}`,
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
}
};
options.reporter = 'mocha-multi-reporters';
options.reporterOptions = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
testsuitesTitle: `${suite} ${process.platform}`,
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
}
};
}
testRunner.configure(options);

View File

@@ -11,57 +11,57 @@ import 'mocha';
import * as extensionMain from '../main';
describe('buildSsmsMinCommandArgs Method Tests', () => {
it('Should be built correctly with all params and UseAAD as false', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
password: 'password',
useAad: false,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -U "user" -u "Server\\Database\\Table"');
});
it('Should be built correctly with all params and UseAAD as false', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
password: 'password',
useAad: false,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -U "user" -u "Server\\Database\\Table"');
});
it('Should be built correctly with all params and UseAAD as true', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
password: 'password',
useAad: true,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -G -u "Server\\Database\\Table"');
});
it('Should be built correctly with all params and UseAAD as true', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer',
database: 'myDatabase',
user: 'user',
password: 'password',
useAad: true,
urn: 'Server\\Database\\Table'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
should(args).equal('-a "myAction" -S "myServer" -D "myDatabase" -G -u "Server\\Database\\Table"');
});
it('Should be built correctly and names escaped correctly', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction\'"/\\[]tricky',
server: 'myServer\'"/\\[]tricky',
database: 'myDatabase\'"/\\[]tricky',
user: 'user\'"/\\[]tricky',
password: 'password',
useAad: true,
urn: 'Server\\Database[\'myDatabase\'\'"/\\[]tricky\']\\Table["myTable\'""/\\[]tricky"]'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
should(args).equal('-a "myAction\'\\"/\\[]tricky" -S "myServer\'\\"/\\[]tricky" -D "myDatabase\'\\"/\\[]tricky" -G -u "Server\\Database[\'myDatabase\'\'\\"/\\[]tricky\']\\Table[\\"myTable\'\\"\\"/\\[]tricky\\"]"');
});
it('Should be built correctly and names escaped correctly', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction\'"/\\[]tricky',
server: 'myServer\'"/\\[]tricky',
database: 'myDatabase\'"/\\[]tricky',
user: 'user\'"/\\[]tricky',
password: 'password',
useAad: true,
urn: 'Server\\Database[\'myDatabase\'\'"/\\[]tricky\']\\Table["myTable\'""/\\[]tricky"]'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
// User is omitted since UseAAD is true
should(args).equal('-a "myAction\'\\"/\\[]tricky" -S "myServer\'\\"/\\[]tricky" -D "myDatabase\'\\"/\\[]tricky" -G -u "Server\\Database[\'myDatabase\'\'\\"/\\[]tricky\']\\Table[\\"myTable\'\\"\\"/\\[]tricky\\"]"');
});
it('Should be built correctly with only action and server', function (): void {
it('Should be built correctly with only action and server', function (): void {
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer"');
});
let params: extensionMain.LaunchSsmsDialogParams = {
action: 'myAction',
server: 'myServer'
};
let args = extensionMain.buildSsmsMinCommandArgs(params);
should(args).equal('-a "myAction" -S "myServer"');
});
});

View File

@@ -7,19 +7,19 @@
import * as vscode from 'vscode';
export interface IPackageInfo {
name: string;
version: string;
aiKey: string;
name: string;
version: string;
aiKey: string;
}
export function getPackageInfo(packageJson: any): IPackageInfo {
if (packageJson) {
return {
name: packageJson.name,
version: packageJson.version,
aiKey: packageJson.aiKey
};
}
if (packageJson) {
return {
name: packageJson.name,
version: packageJson.version,
aiKey: packageJson.aiKey
};
}
}
/**
@@ -28,15 +28,15 @@ export function getPackageInfo(packageJson: any): IPackageInfo {
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
*/
export function getConfiguration(extensionName?: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
} else if (!resource) {
// Fix to avoid adding lots of errors to debug console. Expects a valid resource or null, not undefined
resource = null;
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
} else if (!resource) {
// Fix to avoid adding lots of errors to debug console. Expects a valid resource or null, not undefined
resource = null;
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
}

View File

@@ -1,22 +1,22 @@
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"typeRoots": [
"./node_modules/@types"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": true
},
"exclude": [
"node_modules"
]
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"typeRoots": [
"./node_modules/@types"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": true
},
"exclude": [
"node_modules"
]
}

View File

@@ -1,3 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as data from 'azdata';
@@ -12,52 +11,51 @@ import * as data from 'azdata';
* this API from our code
*
* @export
* @class ApiWrapper
*/
export class ApiWrapper {
// Data APIs
// Data APIs
public registerWebviewProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
public registerWebviewProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
public registerControlHostProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
public registerControlHostProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
return data.dashboard.registerWebviewProvider(widgetId, handler);
}
/**
* Get the configuration for a extensionName
* @param extensionName The string name of the extension to get the configuration for
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
*/
public getConfiguration(extensionName: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
}
/**
* Get the configuration for a extensionName
* @param extensionName The string name of the extension to get the configuration for
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
*/
public getConfiguration(extensionName: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
}
/**
* Parse uri
*/
public parseUri(uri: string): vscode.Uri {
return vscode.Uri.parse(uri);
}
/**
* Parse uri
*/
public parseUri(uri: string): vscode.Uri {
return vscode.Uri.parse(uri);
}
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
return vscode.window.showOpenDialog(options);
}
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
return vscode.window.showOpenDialog(options);
}
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items);
}
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items);
}
public get workspaceRootPath(): string {
return vscode.workspace.rootPath;
}
public get workspaceRootPath(): string {
return vscode.workspace.rootPath;
}
}

View File

@@ -17,7 +17,7 @@ export class AlertData implements IAgentDialogData {
public static readonly AlertTypeSqlServerEventString: string = localize('alertData.DefaultAlertTypString', 'SQL Server event alert');
public static readonly AlertTypePerformanceConditionString: string = localize('alertDialog.PerformanceCondition', 'SQL Server performance condition alert');
public static readonly AlertTypeWmiEventString: string = localize('alertDialog.WmiEvent', 'WMI event alert');
public static readonly DefaultAlertTypeString: string = AlertData.AlertTypeSqlServerEventString;
public static readonly DefaultAlertTypeString: string = AlertData.AlertTypeSqlServerEventString;
ownerUri: string;
dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
@@ -50,7 +50,7 @@ export class AlertData implements IAgentDialogData {
private jobModel: JobData;
constructor(
ownerUri:string,
ownerUri: string,
alertInfo: azdata.AgentAlertInfo,
jobModel?: JobData,
viaJobDialog: boolean = false

View File

@@ -14,7 +14,7 @@ const localize = nls.loadMessageBundle();
export class JobData implements IAgentDialogData {
private readonly JobCompletionActionCondition_Always: string = localize('jobData.whenJobCompletes', 'When the job completes');
private readonly JobCompletionActionCondition_Always: string = localize('jobData.whenJobCompletes', 'When the job completes');
private readonly JobCompletionActionCondition_OnFailure: string = localize('jobData.whenJobFails', 'When the job fails');
private readonly JobCompletionActionCondition_OnSuccess: string = localize('jobData.whenJobSucceeds', 'When the job succeeds');
@@ -126,7 +126,7 @@ export class JobData implements IAgentDialogData {
public async save() {
let jobInfo: azdata.AgentJobInfo = this.toAgentJobInfo();
let result = this.dialogMode === AgentDialogMode.CREATE
? await this._agentService.createJob(this.ownerUri, jobInfo)
? await this._agentService.createJob(this.ownerUri, jobInfo)
: await this._agentService.updateJob(this.ownerUri, this.originalName, jobInfo);
if (!result || !result.success) {
if (this.dialogMode === AgentDialogMode.EDIT) {
@@ -142,7 +142,7 @@ export class JobData implements IAgentDialogData {
localize('jobData.saveSucessMessage', "Job '{0}' updated successfully", jobInfo.name));
} else {
vscode.window.showInformationMessage(
localize('jobData.newJobSuccessMessage',"Job '{0}' created successfully", jobInfo.name));
localize('jobData.newJobSuccessMessage', "Job '{0}' created successfully", jobInfo.name));
}
}

View File

@@ -48,7 +48,7 @@ export class JobStepData implements IAgentDialogData {
private jobModel: JobData;
private viaJobDialog: boolean;
constructor(ownerUri:string, jobModel?: JobData, viaJobDialog: boolean = false) {
constructor(ownerUri: string, jobModel?: JobData, viaJobDialog: boolean = false) {
this.ownerUri = ownerUri;
this.jobName = jobModel.name;
this.jobModel = jobModel;
@@ -102,26 +102,26 @@ export class JobStepData implements IAgentDialogData {
stepData.jobName = jobStepInfo.jobName;
stepData.script = jobStepInfo.script;
stepData.scriptName = jobStepInfo.scriptName,
stepData.stepName = jobStepInfo.stepName,
stepData.subSystem = jobStepInfo.subSystem,
stepData.id = jobStepInfo.id,
stepData.failureAction = jobStepInfo.failureAction,
stepData.successAction = jobStepInfo.successAction,
stepData.failStepId = jobStepInfo.failStepId,
stepData.successStepId = jobStepInfo.successStepId,
stepData.command = jobStepInfo.command,
stepData.commandExecutionSuccessCode = jobStepInfo.commandExecutionSuccessCode,
stepData.databaseName = jobStepInfo.databaseName,
stepData.databaseUserName = jobStepInfo.databaseUserName,
stepData.server = jobStepInfo.server,
stepData.outputFileName = jobStepInfo.outputFileName,
stepData.appendToLogFile = jobStepInfo.appendToLogFile,
stepData.appendToStepHist = jobStepInfo.appendToStepHist,
stepData.writeLogToTable = jobStepInfo.writeLogToTable,
stepData.appendLogToTable = jobStepInfo.appendLogToTable,
stepData.retryAttempts = jobStepInfo.retryAttempts,
stepData.retryInterval = jobStepInfo.retryInterval,
stepData.proxyName = jobStepInfo.proxyName;
stepData.stepName = jobStepInfo.stepName,
stepData.subSystem = jobStepInfo.subSystem,
stepData.id = jobStepInfo.id,
stepData.failureAction = jobStepInfo.failureAction,
stepData.successAction = jobStepInfo.successAction,
stepData.failStepId = jobStepInfo.failStepId,
stepData.successStepId = jobStepInfo.successStepId,
stepData.command = jobStepInfo.command,
stepData.commandExecutionSuccessCode = jobStepInfo.commandExecutionSuccessCode,
stepData.databaseName = jobStepInfo.databaseName,
stepData.databaseUserName = jobStepInfo.databaseUserName,
stepData.server = jobStepInfo.server,
stepData.outputFileName = jobStepInfo.outputFileName,
stepData.appendToLogFile = jobStepInfo.appendToLogFile,
stepData.appendToStepHist = jobStepInfo.appendToStepHist,
stepData.writeLogToTable = jobStepInfo.writeLogToTable,
stepData.appendLogToTable = jobStepInfo.appendLogToTable,
stepData.retryAttempts = jobStepInfo.retryAttempts,
stepData.retryInterval = jobStepInfo.retryInterval,
stepData.proxyName = jobStepInfo.proxyName;
stepData.dialogMode = AgentDialogMode.EDIT;
stepData.viaJobDialog = true;
return stepData;

View File

@@ -29,7 +29,7 @@ export class OperatorData implements IAgentDialogData {
weekdayPagerStartTime: string;
weekdayPagerEndTime: string;
constructor(ownerUri:string, operatorInfo: azdata.AgentOperatorInfo) {
constructor(ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) {
this.ownerUri = ownerUri;
if (operatorInfo) {
this.dialogMode = AgentDialogMode.EDIT;
@@ -58,7 +58,7 @@ export class OperatorData implements IAgentDialogData {
public async save() {
let agentService = await AgentUtils.getAgentService();
let result = await agentService.createOperator(this.ownerUri, this.toAgentOperatorInfo());
let result = await agentService.createOperator(this.ownerUri, this.toAgentOperatorInfo());
if (!result || !result.success) {
// TODO handle error here
}

View File

@@ -15,7 +15,7 @@ export class PickScheduleData implements IAgentDialogData {
public selectedSchedule: azdata.AgentJobScheduleInfo;
private jobName: string;
constructor(ownerUri:string, jobName: string) {
constructor(ownerUri: string, jobName: string) {
this.ownerUri = ownerUri;
this.jobName = jobName;
}

View File

@@ -22,7 +22,7 @@ export class ProxyData implements IAgentDialogData {
credentialId: number;
isEnabled: boolean;
constructor(ownerUri:string, proxyInfo: azdata.AgentProxyInfo) {
constructor(ownerUri: string, proxyInfo: azdata.AgentProxyInfo) {
this.ownerUri = ownerUri;
if (proxyInfo) {
@@ -48,7 +48,7 @@ export class ProxyData implements IAgentDialogData {
localize('proxyData.saveSucessMessage', "Proxy '{0}' updated successfully", proxyInfo.accountName));
} else {
vscode.window.showInformationMessage(
localize('proxyData.newJobSuccessMessage',"Proxy '{0}' created successfully", proxyInfo.accountName));
localize('proxyData.newJobSuccessMessage', "Proxy '{0}' created successfully", proxyInfo.accountName));
}
}

View File

@@ -14,7 +14,7 @@ export class ScheduleData implements IAgentDialogData {
public schedules: azdata.AgentJobScheduleInfo[];
public selectedSchedule: azdata.AgentJobScheduleInfo;
constructor(ownerUri:string) {
constructor(ownerUri: string) {
this.ownerUri = ownerUri;
}

View File

@@ -62,14 +62,14 @@ export class AlertDialog extends AgentDialog<AlertData> {
private static readonly AlertSeverity025Label: string = localize('alertDialog.Severity025', '025 - Fatal Error');
private static readonly AllDatabases: string = localize('alertDialog.AllDatabases', '<all databases>');
private static readonly AlertTypes: string[] = [
private static readonly AlertTypes: string[] = [
AlertData.AlertTypeSqlServerEventString,
// Disabled until next release
// AlertData.AlertTypePerformanceConditionString,
// AlertData.AlertTypeWmiEventString
];
private static readonly AlertSeverities: string[] = [
private static readonly AlertSeverities: string[] = [
AlertDialog.AlertSeverity001Label,
AlertDialog.AlertSeverity002Label,
AlertDialog.AlertSeverity003Label,
@@ -100,21 +100,21 @@ export class AlertDialog extends AgentDialog<AlertData> {
// Response tab strings
private static readonly ExecuteJobCheckBoxLabel: string = localize('alertDialog.ExecuteJob', 'Execute Job');
private static readonly ExecuteJobTextBoxLabel: string = localize('alertDialog.ExecuteJobName', 'Job Name');
private static readonly NotifyOperatorsTextBoxLabel: string = localize('alertDialog.NotifyOperators', 'Notify Operators');
private static readonly NewJobButtonLabel: string = localize('alertDialog.NewJob', 'New Job');
private static readonly OperatorListLabel: string = localize('alertDialog.OperatorList', 'Operator List');
private static readonly OperatorNameColumnLabel: string = localize('alertDialog.OperatorName', 'Operator');
private static readonly OperatorEmailColumnLabel: string = localize('alertDialog.OperatorEmail', 'E-mail');
private static readonly OperatorPagerColumnLabel: string = localize('alertDialog.OperatorPager', 'Pager');
private static readonly NewOperatorButtonLabel: string = localize('alertDialog.NewOperator', 'New Operator');
private static readonly NotifyOperatorsTextBoxLabel: string = localize('alertDialog.NotifyOperators', 'Notify Operators');
private static readonly NewJobButtonLabel: string = localize('alertDialog.NewJob', 'New Job');
private static readonly OperatorListLabel: string = localize('alertDialog.OperatorList', 'Operator List');
private static readonly OperatorNameColumnLabel: string = localize('alertDialog.OperatorName', 'Operator');
private static readonly OperatorEmailColumnLabel: string = localize('alertDialog.OperatorEmail', 'E-mail');
private static readonly OperatorPagerColumnLabel: string = localize('alertDialog.OperatorPager', 'Pager');
private static readonly NewOperatorButtonLabel: string = localize('alertDialog.NewOperator', 'New Operator');
// Options tab strings
private static readonly IncludeErrorInEmailCheckBoxLabel: string = localize('alertDialog.IncludeErrorInEmail', 'Include alert error text in e-mail');
private static readonly IncludeErrorInPagerCheckBoxLabel: string = localize('alertDialog.IncludeErrorInPager', 'Include alert error text in pager');
private static readonly AdditionalMessageTextBoxLabel: string = localize('alertDialog.AdditionalNotification', 'Additional notification message to send');
private static readonly DelayBetweenResponsesTextBoxLabel: string = localize('alertDialog.DelayBetweenResponse', 'Delay between responses');
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
private static readonly IncludeErrorInEmailCheckBoxLabel: string = localize('alertDialog.IncludeErrorInEmail', 'Include alert error text in e-mail');
private static readonly IncludeErrorInPagerCheckBoxLabel: string = localize('alertDialog.IncludeErrorInPager', 'Include alert error text in pager');
private static readonly AdditionalMessageTextBoxLabel: string = localize('alertDialog.AdditionalNotification', 'Additional notification message to send');
private static readonly DelayBetweenResponsesTextBoxLabel: string = localize('alertDialog.DelayBetweenResponse', 'Delay between responses');
private static readonly DelayMinutesTextBoxLabel: string = localize('alertDialog.DelayMinutes', 'Delay Minutes');
private static readonly DelaySecondsTextBoxLabel: string = localize('alertDialog.DelaySeconds', 'Delay Seconds');
// Event Name strings
private readonly NewAlertDialog = 'NewAlertDialogOpen';
@@ -315,7 +315,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}],
title: AlertDialog.EventAlertText
}
]).withLayout({ width: '100%' }).component();
]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
@@ -332,7 +332,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
if (this.model.severity > 0) {
this.severityRadioButton.checked = true;
this.severityDropDown.value = this.severityDropDown.values[this.model.severity-1];
this.severityDropDown.value = this.severityDropDown.values[this.model.severity - 1];
}
if (this.model.databaseName) {
@@ -356,9 +356,9 @@ export class AlertDialog extends AgentDialog<AlertData> {
.component();
this.executeJobTextBox.enabled = false;
this.newJobButton = view.modelBuilder.button().withProperties({
label: AlertDialog.NewJobButtonLabel,
width: 80
}).component();
label: AlertDialog.NewJobButtonLabel,
width: 80
}).component();
this.newJobButton.enabled = false;
this.newJobButton.onDidClick(() => {
let jobDialog = new JobDialog(this.ownerUri);
@@ -382,7 +382,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}, {
component: this.newJobButton,
title: AlertDialog.NewJobButtonLabel
}], { componentWidth: '100%'}).component();
}], { componentWidth: '100%' }).component();
let previewTag = view.modelBuilder.text()
.withProperties({
@@ -409,9 +409,9 @@ export class AlertDialog extends AgentDialog<AlertData> {
}).component();
this.newOperatorButton = view.modelBuilder.button().withProperties({
label: AlertDialog.NewOperatorButtonLabel,
width: 80
}).component();
label: AlertDialog.NewOperatorButtonLabel,
width: 80
}).component();
this.operatorsTable.enabled = false;
this.newOperatorButton.enabled = false;
@@ -438,7 +438,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
}, {
component: this.newOperatorButton,
title: ''
}], { componentWidth: '100%'}).component();
}], { componentWidth: '100%' }).component();
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
@@ -548,7 +548,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
} else {
this.model.eventDescriptionKeyword = '';
}
let minutes = this.delayMinutesTextBox.value ? +this.delayMinutesTextBox.value : 0;
let minutes = this.delayMinutesTextBox.value ? +this.delayMinutesTextBox.value : 0;
let seconds = this.delaySecondsTextBox.value ? +this.delaySecondsTextBox : 0;
this.model.delayBetweenResponses = minutes + seconds;

View File

@@ -70,7 +70,7 @@ export class JobDialog extends AgentDialog<JobData> {
// Event Name strings
private readonly NewJobDialogEvent: string = 'NewJobDialogOpened';
private readonly EditJobDialogEvent: string = 'EditJobDialogOpened';
private readonly EditJobDialogEvent: string = 'EditJobDialogOpened';
// UI Components
private generalTab: azdata.window.DialogTab;
@@ -259,9 +259,9 @@ export class JobDialog extends AgentDialog<JobData> {
width: 140
}).component();
this.newStepButton.onDidClick((e)=>{
this.newStepButton.onDidClick((e) => {
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, null, true);
let stepDialog = new JobStepDialog(this.model.ownerUri, '', this.model, null, true);
stepDialog.onSuccess((step) => {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
this.steps.push(stepInfo);
@@ -296,7 +296,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.deleteStepButton.enabled = false;
this.moveStepUpButton.onDidClick(() => {
let rowNumber = this.stepsTable.selectedRows[0];
let rowNumber = this.stepsTable.selectedRows[0];
let previousRow = rowNumber - 1;
let previousStep = this.steps[previousRow];
let previousStepId = this.steps[previousRow].id;
@@ -329,7 +329,7 @@ export class JobDialog extends AgentDialog<JobData> {
if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0];
let stepData = this.model.jobSteps[rowNumber];
let editStepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true);
let editStepDialog = new JobStepDialog(this.model.ownerUri, '', this.model, stepData, true);
editStepDialog.onSuccess((step) => {
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
for (let i = 0; i < this.steps.length; i++) {
@@ -349,7 +349,7 @@ export class JobDialog extends AgentDialog<JobData> {
}
});
this.deleteStepButton.onDidClick(async() => {
this.deleteStepButton.onDidClick(async () => {
if (this.stepsTable.selectedRows.length === 1) {
let rowNumber = this.stepsTable.selectedRows[0];
AgentUtils.getAgentService().then(async (agentService) => {
@@ -448,7 +448,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.alerts.push(alertInfo);
this.alertsTable.data = this.convertAlertsToData(this.alerts);
});
this.newAlertButton.onDidClick(()=>{
this.newAlertButton.onDidClick(() => {
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
alertDialog.jobId = this.model.jobId;
alertDialog.jobName = this.model.name ? this.model.name : this.nameTextBox.value;
@@ -491,7 +491,7 @@ export class JobDialog extends AgentDialog<JobData> {
label: 'Remove schedule',
width: 100
}).component();
this.pickScheduleButton.onDidClick(()=>{
this.pickScheduleButton.onDidClick(() => {
let pickScheduleDialog = new PickScheduleDialog(this.model.ownerUri, this.model.name);
pickScheduleDialog.onSuccess((dialogModel) => {
let selectedSchedule = dialogModel.selectedSchedule;
@@ -507,8 +507,8 @@ export class JobDialog extends AgentDialog<JobData> {
pickScheduleDialog.showDialog();
});
this.removeScheduleButton.onDidClick(() => {
if (this.schedulesTable.selectedRows.length === 1) {
let selectedRow = this.schedulesTable.selectedRows[0];
if (this.schedulesTable.selectedRows.length === 1) {
let selectedRow = this.schedulesTable.selectedRows[0];
let selectedScheduleName = this.schedulesTable.data[selectedRow][1];
for (let i = 0; i < this.schedules.length; i++) {
if (this.schedules[i].name === selectedScheduleName) {
@@ -595,22 +595,23 @@ export class JobDialog extends AgentDialog<JobData> {
let formModel = view.modelBuilder.formContainer().withFormItems([
{
components:
[{
component: emailContainer,
title: ''
},
{
component: pagerContainer,
title: ''
},
{
component: eventLogContainer,
title: ''
},
{
component: deleteJobContainer,
title: ''
}], title: this.NotificationsTabTopLabelString}]).withLayout({ width: '100%' }).component();
[{
component: emailContainer,
title: ''
},
{
component: pagerContainer,
title: ''
},
{
component: eventLogContainer,
title: ''
},
{
component: deleteJobContainer,
title: ''
}], title: this.NotificationsTabTopLabelString
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);
this.emailConditionDropdown.values = this.model.JobCompletionActionConditions;
@@ -694,7 +695,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.model.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown);
this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown);
this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown);
this.model.startStepId = this.startStepDropdown.enabled ? +this.getDropdownValue(this.startStepDropdown) : 1;
this.model.startStepId = this.startStepDropdown.enabled ? +this.getDropdownValue(this.startStepDropdown) : 1;
if (!this.model.jobSteps) {
this.model.jobSteps = [];
}

View File

@@ -28,7 +28,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
private readonly GeneralTabText: string = localize('jobStepDialog.general', 'General');
private readonly AdvancedTabText: string = localize('jobStepDialog.advanced', 'Advanced');
private readonly OpenCommandText: string = localize('jobStepDialog.open', 'Open...');
private readonly ParseCommandText: string = localize('jobStepDialog.parse','Parse');
private readonly ParseCommandText: string = localize('jobStepDialog.parse', 'Parse');
private readonly SuccessfulParseText: string = localize('jobStepDialog.successParse', 'The command was successfully parsed.');
private readonly FailureParseText: string = localize('jobStepDialog.failParse', 'The command failed.');
private readonly BlankStepNameErrorText: string = localize('jobStepDialog.blankStepName', 'The step name cannot be left blank');
@@ -124,15 +124,15 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
viaJobDialog: boolean = false
) {
super(ownerUri,
jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel, viaJobDialog),
jobStepInfo ? JobStepDialog.EditDialogTitle : JobStepDialog.NewDialogTitle);
jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel, viaJobDialog),
jobStepInfo ? JobStepDialog.EditDialogTitle : JobStepDialog.NewDialogTitle);
this.stepId = jobStepInfo ?
jobStepInfo.id : jobModel.jobSteps ?
jobModel.jobSteps.length + 1 : 1;
jobStepInfo.id : jobModel.jobSteps ?
jobModel.jobSteps.length + 1 : 1;
this.isEdit = jobStepInfo ? true : false;
this.model.dialogMode = this.isEdit ? AgentDialogMode.EDIT : AgentDialogMode.CREATE;
this.jobModel = jobModel;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
this.server = server;
this.dialogName = this.isEdit ? this.EditStepDialog : this.NewStepDialog;
}
@@ -164,7 +164,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
if (this.commandTextBox.value) {
queryProvider.parseSyntax(this.ownerUri, this.commandTextBox.value).then(result => {
if (result && result.parseable) {
this.dialog.message = { text: this.SuccessfulParseText, level: 2};
this.dialog.message = { text: this.SuccessfulParseText, level: 2 };
} else if (result && !result.parseable) {
this.dialog.message = { text: this.FailureParseText };
}
@@ -246,7 +246,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
}).component();
this.typeDropdown.onValueChanged((type) => {
switch (type.selected) {
case(this.TSQLScript):
case (this.TSQLScript):
this.runAsDropdown.value = '';
this.runAsDropdown.values = [''];
this.runAsDropdown.enabled = false;
@@ -256,7 +256,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.processExitCodeBox.value = '';
this.processExitCodeBox.enabled = false;
break;
case(this.Powershell):
case (this.Powershell):
this.runAsDropdown.value = this.AgentServiceAccount;
this.runAsDropdown.values = [this.runAsDropdown.value];
this.runAsDropdown.enabled = true;
@@ -266,7 +266,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
this.processExitCodeBox.value = '';
this.processExitCodeBox.enabled = false;
break;
case(this.CmdExec):
case (this.CmdExec):
this.databaseDropdown.enabled = false;
this.databaseDropdown.values = [''];
this.databaseDropdown.value = '';
@@ -397,13 +397,13 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
let retryAttemptsContainer = view.modelBuilder.formContainer()
.withFormItems(
[{
component: this.retryAttemptsBox,
title: this.RetryAttemptsLabel
}], {
horizontal: false,
componentWidth: '100%'
})
[{
component: this.retryAttemptsBox,
title: this.RetryAttemptsLabel
}], {
horizontal: false,
componentWidth: '100%'
})
.component();
let retryIntervalContainer = view.modelBuilder.formContainer()
@@ -411,7 +411,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
[{
component: this.retryIntervalBox,
title: this.RetryIntervalLabel
}], {
}], {
horizontal: false
})
.component();
@@ -427,13 +427,13 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
let fileBrowserTitle = this.FileBrowserDialogTitle + `${this.server}`;
this.fileBrowserDialog = azdata.window.createModelViewDialog(fileBrowserTitle);
let fileBrowserTab = azdata.window.createTab('File Browser');
this.fileBrowserDialog.content = [fileBrowserTab];
this.fileBrowserDialog.content = [fileBrowserTab];
fileBrowserTab.registerContent(async (view) => {
this.fileBrowserTree = view.modelBuilder.fileBrowserTree()
.withProperties({ ownerUri: this.ownerUri, width: 420, height: 700 })
.component();
this.selectedPathTextBox = view.modelBuilder.inputBox()
.withProperties({ inputType: 'text'})
.withProperties({ inputType: 'text' })
.component();
this.fileBrowserTree.onDidChange((args) => {
this.selectedPathTextBox.value = args.fullPath;
@@ -462,7 +462,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
component: this.fileBrowserNameBox,
title: this.FileNameLabelString
}
]).component();
]).component();
view.initializeModel(fileBrowserContainer);
});
this.fileBrowserDialog.okButton.onClick(() => {

View File

@@ -135,7 +135,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
this.pagerTuesdayCheckBox.onChanged(() => {
if (this.pagerTuesdayCheckBox .checked) {
if (this.pagerTuesdayCheckBox.checked) {
this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true;
} else {
@@ -153,7 +153,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}).component();
this.pagerWednesdayCheckBox.onChanged(() => {
if (this.pagerWednesdayCheckBox .checked) {
if (this.pagerWednesdayCheckBox.checked) {
this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true;
} else {
@@ -171,7 +171,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}).component();
this.pagerThursdayCheckBox.onChanged(() => {
if (this.pagerThursdayCheckBox .checked) {
if (this.pagerThursdayCheckBox.checked) {
this.weekdayPagerStartTimeInput.enabled = true;
this.weekdayPagerEndTimeInput.enabled = true;
} else {
@@ -362,7 +362,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
}, {
component: pagerSundayCheckboxContainer,
title: ''
}] ,
}],
title: OperatorDialog.PagerDutyScheduleLabel
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel);

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
'use strict';
import * as nls from 'vscode-nls';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
@@ -20,8 +20,8 @@ export class PickScheduleDialog {
private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel');
private readonly SchedulesLabelText: string = localize('pickSchedule.availableSchedules', 'Available Schedules:');
public static readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Name');
public static readonly SchedulesIDText: string = localize('pickSchedule.scheduleID','ID');
public static readonly ScheduleDescription: string = localize('pickSchedule.description','Description');
public static readonly SchedulesIDText: string = localize('pickSchedule.scheduleID', 'ID');
public static readonly ScheduleDescription: string = localize('pickSchedule.description', 'Description');
// UI Components
@@ -74,7 +74,7 @@ export class PickScheduleDialog {
let data: any[][] = [];
for (let i = 0; i < this.model.schedules.length; ++i) {
let schedule = this.model.schedules[i];
data[i] = [ schedule.id, schedule.name, schedule.description ];
data[i] = [schedule.id, schedule.name, schedule.description];
}
this.schedulesTable.data = data;
}

View File

@@ -84,7 +84,7 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
this.generalTab.registerContent(async view => {
this.proxyNameTextBox = view.modelBuilder.inputBox()
.withProperties({width: 420})
.withProperties({ width: 420 })
.component();
this.credentialNameDropDown = view.modelBuilder.dropDown()

View File

@@ -69,7 +69,7 @@ export class ScheduleDialog {
let data: any[][] = [];
for (let i = 0; i < this.model.schedules.length; ++i) {
let schedule = this.model.schedules[i];
data[i] = [ schedule.name ];
data[i] = [schedule.name];
}
this.schedulesTable.data = data;
}

View File

@@ -22,57 +22,57 @@ const localize = nls.loadMessageBundle();
* The main controller class that initializes the extension
*/
export class MainController {
protected _context: vscode.ExtensionContext;
protected _context: vscode.ExtensionContext;
// PUBLIC METHODS //////////////////////////////////////////////////////
public constructor(context: vscode.ExtensionContext) {
this._context = context;
}
// PUBLIC METHODS //////////////////////////////////////////////////////
public constructor(context: vscode.ExtensionContext) {
this._context = context;
}
public static showNotYetImplemented(): void {
vscode.window.showInformationMessage(
localize('mainController.notImplemented', "This feature is under development. Check-out the latest insiders build if you'd like to try out the most recent changes!"));
}
public static showNotYetImplemented(): void {
vscode.window.showInformationMessage(
localize('mainController.notImplemented', "This feature is under development. Check-out the latest insiders build if you'd like to try out the most recent changes!"));
}
/**
* Activates the extension
*/
public activate(): void {
vscode.commands.registerCommand('agent.openJobDialog', async (ownerUri: string, jobInfo: azdata.AgentJobInfo) => {
let dialog = new JobDialog(ownerUri, jobInfo);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: azdata.AgentJobInfo, jobStepInfo: azdata.AgentJobStepInfo) => {
AgentUtils.getAgentService().then(async(agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openPickScheduleDialog', async (ownerUri: string, jobName: string) => {
let dialog = new PickScheduleDialog(ownerUri, jobName);
await dialog.showDialog();
});
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, jobInfo: azdata.AgentJobInfo, alertInfo: azdata.AgentAlertInfo) => {
AgentUtils.getAgentService().then(async (agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openOperatorDialog', async (ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) => {
let dialog = new OperatorDialog(ownerUri, operatorInfo);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
vscode.commands.registerCommand('agent.openProxyDialog', async (ownerUri: string, proxyInfo: azdata.AgentProxyInfo, credentials: azdata.CredentialInfo[]) => {
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
}
/**
* Activates the extension
*/
public activate(): void {
vscode.commands.registerCommand('agent.openJobDialog', async (ownerUri: string, jobInfo: azdata.AgentJobInfo) => {
let dialog = new JobDialog(ownerUri, jobInfo);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: azdata.AgentJobInfo, jobStepInfo: azdata.AgentJobStepInfo) => {
AgentUtils.getAgentService().then(async (agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openPickScheduleDialog', async (ownerUri: string, jobName: string) => {
let dialog = new PickScheduleDialog(ownerUri, jobName);
await dialog.showDialog();
});
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, jobInfo: azdata.AgentJobInfo, alertInfo: azdata.AgentAlertInfo) => {
AgentUtils.getAgentService().then(async (agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openOperatorDialog', async (ownerUri: string, operatorInfo: azdata.AgentOperatorInfo) => {
let dialog = new OperatorDialog(ownerUri, operatorInfo);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
vscode.commands.registerCommand('agent.openProxyDialog', async (ownerUri: string, proxyInfo: azdata.AgentProxyInfo, credentials: azdata.CredentialInfo[]) => {
let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
dialog.dialogName ? await dialog.openDialog(dialog.dialogName) : await dialog.openDialog();
});
}
/**
* Deactivates the extension
*/
public deactivate(): void {
}
/**
* Deactivates the extension
*/
public deactivate(): void {
}
}

View File

@@ -1,19 +1,18 @@
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": true
},
"exclude": [
"node_modules"
]
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node"
},
"exclude": [
"node_modules"
]
}

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as adal from 'adal-node';
import * as azdata from 'azdata';
import * as request from 'request';
@@ -54,8 +52,8 @@ export class AzureAccountProvider implements azdata.AccountProvider {
/**
* Clears all tokens that belong to the given account from the token cache
* @param {"data".AccountKey} accountKey Key identifying the account to delete tokens for
* @returns {Thenable<void>} Promise to clear requested tokens from the token cache
* @param accountKey Key identifying the account to delete tokens for
* @returns Promise to clear requested tokens from the token cache
*/
public clear(accountKey: azdata.AccountKey): Thenable<void> {
return this.doIfInitialized(() => this.clearAccountTokens(accountKey));
@@ -63,7 +61,7 @@ export class AzureAccountProvider implements azdata.AccountProvider {
/**
* Clears the entire token cache. Invoked by command palette action.
* @returns {Thenable<void>} Promise to clear the token cache
* @returns Promise to clear the token cache
*/
public clearTokenCache(): Thenable<void> {
return this._tokenCache.clear();
@@ -92,13 +90,13 @@ export class AzureAccountProvider implements azdata.AccountProvider {
// NOTE: Based on ADAL implementation, getting tokens should use the refresh token if necessary
let task = this.getAccessTokens(account, azdata.AzureResource.ResourceManagement)
.then(
() => {
return account;
},
() => {
account.isStale = true;
return account;
}
() => {
return account;
},
() => {
account.isStale = true;
return account;
}
);
rehydrationTasks.push(task);
}
@@ -321,10 +319,10 @@ export class AzureAccountProvider implements azdata.AccountProvider {
* Retrieves a token for the given user ID for the specific tenant ID. If the token can, it
* will be retrieved from the cache as per the ADAL API. AFAIK, the ADAL API will also utilize
* the refresh token if there aren't any unexpired tokens to use.
* @param {string} userId ID of the user to get a token for
* @param {string} tenantId Tenant to get the token for
* @param {string} resourceId ID of the resource the token will be good for
* @returns {Thenable<TokenResponse>} Promise to return a token. Rejected if retrieving the token fails.
* @param userId ID of the user to get a token for
* @param tenantId Tenant to get the token for
* @param resourceId ID of the resource the token will be good for
* @returns Promise to return a token. Rejected if retrieving the token fails.
*/
private getToken(userId: string, tenantId: string, resourceId: string): Thenable<adal.TokenResponse> {
let self = this;
@@ -346,9 +344,9 @@ export class AzureAccountProvider implements azdata.AccountProvider {
/**
* Performs a web request using the provided bearer token
* @param {TokenResponse} accessToken Bearer token for accessing the provided URI
* @param {string} uri URI to access
* @returns {Thenable<any>} Promise to return the deserialized body of the request. Rejected if error occurred.
* @param accessToken Bearer token for accessing the provided URI
* @param uri URI to access
* @returns Promise to return the deserialized body of the request. Rejected if error occurred.
*/
private makeWebRequest(accessToken: adal.TokenResponse, uri: string): Thenable<any> {
return new Promise<any>((resolve, reject) => {

View File

@@ -77,14 +77,14 @@ export class AzureAccountProviderService implements vscode.Disposable {
return Promise.all(promises)
.then(
() => {
let message = localize('clearTokenCacheSuccess', 'Token cache successfully cleared');
vscode.window.showInformationMessage(`${constants.extensionName}: ${message}`);
},
err => {
let message = localize('clearTokenCacheFailure', 'Failed to clear token cache');
vscode.window.showErrorMessage(`${constants.extensionName}: ${message}: ${err}`);
});
() => {
let message = localize('clearTokenCacheSuccess', 'Token cache successfully cleared');
vscode.window.showInformationMessage(`${constants.extensionName}: ${message}`);
},
err => {
let message = localize('clearTokenCacheFailure', 'Failed to clear token cache');
vscode.window.showErrorMessage(`${constants.extensionName}: ${message}: ${err}`);
});
}
private onDidChangeConfiguration(): void {

View File

@@ -1,3 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as adal from 'adal-node';
import * as azdata from 'azdata';
import * as crypto from 'crypto';
@@ -34,8 +32,8 @@ export default class TokenCache implements adal.TokenCache {
.then(cache => self.addToCache(cache, entries))
.then(updatedCache => self.writeCache(updatedCache))
.then(
() => callback(null, false),
(err) => callback(err, true)
() => callback(null, false),
(err) => callback(err, true)
);
});
}
@@ -70,8 +68,8 @@ export default class TokenCache implements adal.TokenCache {
);
})
.then(
results => callback(null, results),
(err) => callback(err, null)
results => callback(null, results),
(err) => callback(err, null)
);
});
}
@@ -79,7 +77,7 @@ export default class TokenCache implements adal.TokenCache {
/**
* Wrapper to make callback-based find method into a thenable method
* @param query Partial object to use to look up tokens. Ideally should be partial of adal.TokenResponse
* @returns {Thenable<any[]>} Promise to return the matching adal.TokenResponse objects.
* @returns Promise to return the matching adal.TokenResponse objects.
* Rejected if an error was sent in the callback
*/
public findThenable(query: any): Thenable<any[]> {
@@ -104,16 +102,16 @@ export default class TokenCache implements adal.TokenCache {
.then(cache => self.removeFromCache(cache, entries))
.then(updatedCache => self.writeCache(updatedCache))
.then(
() => callback(null, null),
(err) => callback(err, null)
() => callback(null, null),
(err) => callback(err, null)
);
});
}
/**
* Wrapper to make callback-based remove method into a thenable method
* @param {TokenResponse[]} entries Array of entries to remove from the token cache
* @returns {Thenable<void>} Promise to remove the given tokens from the token cache
* @param entries Array of entries to remove from the token cache
* @returns Promise to remove the given tokens from the token cache
* Rejected if an error was sent in the callback
*/
public removeThenable(entries: adal.TokenResponse[]): Thenable<void> {
@@ -186,8 +184,8 @@ export default class TokenCache implements adal.TokenCache {
if (splitValues.length === 2 && splitValues[0] && splitValues[1]) {
try {
return <EncryptionParams>{
key: new Buffer(splitValues[0], 'hex'),
initializationVector: new Buffer(splitValues[1], 'hex')
key: Buffer.from(splitValues[0], 'hex'),
initializationVector: Buffer.from(splitValues[1], 'hex')
};
} catch (e) {
// Swallow the error and fall through to generate new params

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
@@ -15,7 +13,6 @@ import * as constants from './constants';
* this API from our code
*
* @export
* @class ApiWrapper
*/
export class ApiWrapper {
// Data APIs

View File

@@ -16,8 +16,7 @@ import { AzureResourceResourceTreeNode } from '../../resourceTreeNode';
export function registerAzureResourceDatabaseCommands(appContext: AppContext): void {
appContext.apiWrapper.registerCommand('azure.resource.connectsqldb', async (node?: TreeNode) => {
if (!node)
{
if (!node) {
return;
}

View File

@@ -16,8 +16,7 @@ import { AzureResourceResourceTreeNode } from '../../resourceTreeNode';
export function registerAzureResourceDatabaseServerCommands(appContext: AppContext): void {
appContext.apiWrapper.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode) => {
if (!node)
{
if (!node) {
return;
}

View File

@@ -21,9 +21,9 @@ export class AzureResourceDatabaseServerService implements IAzureResourceDatabas
svrs.forEach((svr) => databaseServers.push({
name: svr.name,
fullName: svr.fullyQualifiedDomainName,
loginName: svr.administratorLogin,
defaultDatabaseName: 'master'
fullName: svr.fullyQualifiedDomainName,
loginName: svr.administratorLogin,
defaultDatabaseName: 'master'
}));
return databaseServers;

View File

@@ -5,7 +5,7 @@
'use strict';
import { ServiceClientCredentials } from 'ms-rest';
import { ServiceClientCredentials } from 'ms-rest';
import { azureResource } from '../../azure-resource';
import { AzureResourceDatabaseServer } from './models';

View File

@@ -17,10 +17,10 @@ export class AzureResourceCacheService implements IAzureResourceCacheService {
}
public generateKey(id: string): string {
return `${AzureResourceCacheService.cacheKeyPrefix}.${id}`;
}
return `${AzureResourceCacheService.cacheKeyPrefix}.${id}`;
}
public get<T>(key: string): T | undefined {
public get<T>(key: string): T | undefined {
return this._context.workspaceState.get(key);
}

View File

@@ -12,7 +12,7 @@ import { azureResource } from '../azure-resource';
import { IAzureResourceSubscriptionFilterService, IAzureResourceCacheService } from '../interfaces';
interface AzureResourceSelectedSubscriptionsCache {
selectedSubscriptions: { [accountId: string]: azureResource.AzureResourceSubscription[]};
selectedSubscriptions: { [accountId: string]: azureResource.AzureResourceSubscription[] };
}
export class AzureResourceSubscriptionFilterService implements IAzureResourceSubscriptionFilterService {
@@ -36,7 +36,7 @@ export class AzureResourceSubscriptionFilterService implements IAzureResourceSub
}
public async saveSelectedSubscriptions(account: Account, selectedSubscriptions: azureResource.AzureResourceSubscription[]): Promise<void> {
let selectedSubscriptionsCache: { [accountId: string]: azureResource.AzureResourceSubscription[]} = {};
let selectedSubscriptionsCache: { [accountId: string]: azureResource.AzureResourceSubscription[] } = {};
const cache = this._cacheService.get<AzureResourceSelectedSubscriptionsCache>(this._cacheKey);
if (cache) {

View File

@@ -46,7 +46,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
if (this._isClearingCache) {
try {
const tokens = await this.appContext.apiWrapper.getSecurityToken(this.account, AzureResource.ResourceManagement);
const tokens = await this.appContext.apiWrapper.getSecurityToken(this.account, AzureResource.ResourceManagement);
for (const tenant of this.account.properties.tenants) {
const token = tokens[tenant.id].token;

View File

@@ -44,8 +44,8 @@ export abstract class AzureResourceContainerTreeNodeBase extends AzureResourceTr
}
protected setCacheKey(id: string): void {
this._cacheKey = this._cacheService.generateKey(id);
}
this._cacheKey = this._cacheService.generateKey(id);
}
protected updateCache<T>(cache: T): void {
this._cacheService.update<T>(this._cacheKey, cache);

View File

@@ -86,7 +86,7 @@ export class AzureResourceSubscriptionTreeNode extends AzureResourceContainerTre
}
public get nodePathValue(): string {
return this._id;
return this._id;
}
private _id: string = undefined;

View File

@@ -45,7 +45,7 @@ export abstract class TreeNode {
if (children) {
for (let child of children) {
if (filter && filter(child)) {
let childNode = await this.findNode(child, condition, filter, expandIfNeeded);
let childNode = await this.findNode(child, condition, filter, expandIfNeeded);
if (childNode) {
return childNode;
}

View File

@@ -9,7 +9,7 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export function getErrorMessage(error: Error | string): string {
return (error instanceof Error) ? error.message : error;
return (error instanceof Error) ? error.message : error;
}
export class AzureResourceErrorMessageUtil {
@@ -19,78 +19,78 @@ export class AzureResourceErrorMessageUtil {
}
export function generateGuid(): string {
let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
// c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
let oct: string = '';
let tmp: number;
/* tslint:disable:no-bitwise */
for (let a: number = 0; a < 4; a++) {
tmp = (4294967296 * Math.random()) | 0;
oct += hexValues[tmp & 0xF] +
hexValues[tmp >> 4 & 0xF] +
hexValues[tmp >> 8 & 0xF] +
hexValues[tmp >> 12 & 0xF] +
hexValues[tmp >> 16 & 0xF] +
hexValues[tmp >> 20 & 0xF] +
hexValues[tmp >> 24 & 0xF] +
hexValues[tmp >> 28 & 0xF];
}
let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
// c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
let oct: string = '';
let tmp: number;
/* tslint:disable:no-bitwise */
for (let a: number = 0; a < 4; a++) {
tmp = (4294967296 * Math.random()) | 0;
oct += hexValues[tmp & 0xF] +
hexValues[tmp >> 4 & 0xF] +
hexValues[tmp >> 8 & 0xF] +
hexValues[tmp >> 12 & 0xF] +
hexValues[tmp >> 16 & 0xF] +
hexValues[tmp >> 20 & 0xF] +
hexValues[tmp >> 24 & 0xF] +
hexValues[tmp >> 28 & 0xF];
}
// 'Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively'
let clockSequenceHi: string = hexValues[8 + (Math.random() * 4) | 0];
return oct.substr(0, 8) + '-' + oct.substr(9, 4) + '-4' + oct.substr(13, 3) + '-' + clockSequenceHi + oct.substr(16, 3) + '-' + oct.substr(19, 12);
/* tslint:enable:no-bitwise */
// 'Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively'
let clockSequenceHi: string = hexValues[8 + (Math.random() * 4) | 0];
return oct.substr(0, 8) + '-' + oct.substr(9, 4) + '-4' + oct.substr(13, 3) + '-' + clockSequenceHi + oct.substr(16, 3) + '-' + oct.substr(19, 12);
/* tslint:enable:no-bitwise */
}
export function equals(one: any, other: any): boolean {
if (one === other) {
return true;
}
if (one === null || one === undefined || other === null || other === undefined) {
return false;
}
if (typeof one !== typeof other) {
return false;
}
if (typeof one !== 'object') {
return false;
}
if ((Array.isArray(one)) !== (Array.isArray(other))) {
return false;
}
if (one === other) {
return true;
}
if (one === null || one === undefined || other === null || other === undefined) {
return false;
}
if (typeof one !== typeof other) {
return false;
}
if (typeof one !== 'object') {
return false;
}
if ((Array.isArray(one)) !== (Array.isArray(other))) {
return false;
}
let i: number;
let key: string;
let i: number;
let key: string;
if (Array.isArray(one)) {
if (one.length !== other.length) {
return false;
}
for (i = 0; i < one.length; i++) {
if (!equals(one[i], other[i])) {
return false;
}
}
} else {
const oneKeys: string[] = [];
if (Array.isArray(one)) {
if (one.length !== other.length) {
return false;
}
for (i = 0; i < one.length; i++) {
if (!equals(one[i], other[i])) {
return false;
}
}
} else {
const oneKeys: string[] = [];
for (key in one) {
oneKeys.push(key);
}
oneKeys.sort();
const otherKeys: string[] = [];
for (key in other) {
otherKeys.push(key);
}
otherKeys.sort();
if (!equals(oneKeys, otherKeys)) {
return false;
}
for (i = 0; i < oneKeys.length; i++) {
if (!equals(one[oneKeys[i]], other[oneKeys[i]])) {
return false;
}
}
}
return true;
for (key in one) {
oneKeys.push(key);
}
oneKeys.sort();
const otherKeys: string[] = [];
for (key in other) {
otherKeys.push(key);
}
otherKeys.sort();
if (!equals(oneKeys, otherKeys)) {
return false;
}
for (i = 0; i < oneKeys.length; i++) {
if (!equals(one[oneKeys[i]], other[oneKeys[i]])) {
return false;
}
}
}
return true;
}

View File

@@ -1,3 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vscode-nls';

View File

@@ -13,7 +13,8 @@ import {
IAzureResourceAccountService,
IAzureResourceSubscriptionService,
IAzureResourceSubscriptionFilterService,
IAzureResourceTenantService } from '../azureResource/interfaces';
IAzureResourceTenantService
} from '../azureResource/interfaces';
import { AzureResourceServiceNames } from '../azureResource/constants';
import { AzureResourceTreeProvider } from '../azureResource/tree/treeProvider';
import { registerAzureResourceCommands } from '../azureResource/commands';

View File

@@ -1,4 +1,7 @@
'use strict';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as fs from 'fs';
@@ -23,7 +26,7 @@ let controllers: ControllerBase[] = [];
// The function is a duplicate of \src\paths.js. IT would be better to import path.js but it doesn't
// work for now because the extension is running in different process.
export function getAppDataPath() {
var platform = process.platform;
let platform = process.platform;
switch (platform) {
case 'win32': return process.env['APPDATA'] || path.join(process.env['USERPROFILE'], 'AppData', 'Roaming');
case 'darwin': return path.join(os.homedir(), 'Library', 'Application Support');

View File

@@ -12,110 +12,110 @@ const KUBECONFIG_PATH_KEY = 'mssql-bdc.kubeconfig';
const KNOWN_KUBECONFIGS_KEY = 'mssql-bdc.knownKubeconfigs';
export async function addPathToConfig(configKey: string, value: string): Promise<void> {
await setConfigValue(configKey, value);
await setConfigValue(configKey, value);
}
async function setConfigValue(configKey: string, value: any): Promise<void> {
await atAllConfigScopes(addValueToConfigAtScope, configKey, value);
await atAllConfigScopes(addValueToConfigAtScope, configKey, value);
}
async function addValueToConfigAtScope(configKey: string, value: any, scope: vscode.ConfigurationTarget, valueAtScope: any, createIfNotExist: boolean): Promise<void> {
if (!createIfNotExist) {
if (!valueAtScope || !(valueAtScope[configKey])) {
return;
}
}
if (!createIfNotExist) {
if (!valueAtScope || !(valueAtScope[configKey])) {
return;
}
}
let newValue: any = {};
if (valueAtScope) {
newValue = Object.assign({}, valueAtScope);
}
newValue[configKey] = value;
await vscode.workspace.getConfiguration().update(EXTENSION_CONFIG_KEY, newValue, scope);
let newValue: any = {};
if (valueAtScope) {
newValue = Object.assign({}, valueAtScope);
}
newValue[configKey] = value;
await vscode.workspace.getConfiguration().update(EXTENSION_CONFIG_KEY, newValue, scope);
}
async function addValueToConfigArray(configKey: string, value: string): Promise<void> {
await atAllConfigScopes(addValueToConfigArrayAtScope, configKey, value);
await atAllConfigScopes(addValueToConfigArrayAtScope, configKey, value);
}
async function addValueToConfigArrayAtScope(configKey: string, value: string, scope: vscode.ConfigurationTarget, valueAtScope: any, createIfNotExist: boolean): Promise<void> {
if (!createIfNotExist) {
if (!valueAtScope || !(valueAtScope[configKey])) {
return;
}
}
if (!createIfNotExist) {
if (!valueAtScope || !(valueAtScope[configKey])) {
return;
}
}
let newValue: any = {};
if (valueAtScope) {
newValue = Object.assign({}, valueAtScope);
}
const arrayEntry: string[] = newValue[configKey] || [];
arrayEntry.push(value);
newValue[configKey] = arrayEntry;
await vscode.workspace.getConfiguration().update(EXTENSION_CONFIG_KEY, newValue, scope);
let newValue: any = {};
if (valueAtScope) {
newValue = Object.assign({}, valueAtScope);
}
const arrayEntry: string[] = newValue[configKey] || [];
arrayEntry.push(value);
newValue[configKey] = arrayEntry;
await vscode.workspace.getConfiguration().update(EXTENSION_CONFIG_KEY, newValue, scope);
}
type ConfigUpdater<T> = (configKey: string, value: T, scope: vscode.ConfigurationTarget, valueAtScope: any, createIfNotExist: boolean) => Promise<void>;
async function atAllConfigScopes<T>(fn: ConfigUpdater<T>, configKey: string, value: T): Promise<void> {
const config = vscode.workspace.getConfiguration().inspect(EXTENSION_CONFIG_KEY)!;
await fn(configKey, value, vscode.ConfigurationTarget.Global, config.globalValue, true);
await fn(configKey, value, vscode.ConfigurationTarget.Workspace, config.workspaceValue, false);
await fn(configKey, value, vscode.ConfigurationTarget.WorkspaceFolder, config.workspaceFolderValue, false);
const config = vscode.workspace.getConfiguration().inspect(EXTENSION_CONFIG_KEY)!;
await fn(configKey, value, vscode.ConfigurationTarget.Global, config.globalValue, true);
await fn(configKey, value, vscode.ConfigurationTarget.Workspace, config.workspaceValue, false);
await fn(configKey, value, vscode.ConfigurationTarget.WorkspaceFolder, config.workspaceFolderValue, false);
}
// Functions for working with the list of known kubeconfigs
export function getKnownKubeconfigs(): string[] {
const kkcConfig = vscode.workspace.getConfiguration(EXTENSION_CONFIG_KEY)[KNOWN_KUBECONFIGS_KEY];
if (!kkcConfig || !kkcConfig.length) {
return [];
}
return kkcConfig as string[];
const kkcConfig = vscode.workspace.getConfiguration(EXTENSION_CONFIG_KEY)[KNOWN_KUBECONFIGS_KEY];
if (!kkcConfig || !kkcConfig.length) {
return [];
}
return kkcConfig as string[];
}
export async function addKnownKubeconfig(kubeconfigPath: string) {
await addValueToConfigArray(KNOWN_KUBECONFIGS_KEY, kubeconfigPath);
await addValueToConfigArray(KNOWN_KUBECONFIGS_KEY, kubeconfigPath);
}
// Functions for working with the active kubeconfig setting
export async function setActiveKubeconfig(kubeconfig: string): Promise<void> {
await addPathToConfig(KUBECONFIG_PATH_KEY, kubeconfig);
await addPathToConfig(KUBECONFIG_PATH_KEY, kubeconfig);
}
export function getActiveKubeconfig(): string {
return vscode.workspace.getConfiguration(EXTENSION_CONFIG_KEY)[KUBECONFIG_PATH_KEY];
return vscode.workspace.getConfiguration(EXTENSION_CONFIG_KEY)[KUBECONFIG_PATH_KEY];
}
// Functions for working with tool paths
export function getToolPath(host: Host, shell: Shell, tool: string): string | undefined {
const baseKey = toolPathBaseKey(tool);
return getPathSetting(host, shell, baseKey);
const baseKey = toolPathBaseKey(tool);
return getPathSetting(host, shell, baseKey);
}
function getPathSetting(host: Host, shell: Shell, baseKey: string): string | undefined {
const os = shell.platform();
const osOverridePath = host.getConfiguration(EXTENSION_CONFIG_KEY)[osOverrideKey(os, baseKey)];
return osOverridePath || host.getConfiguration(EXTENSION_CONFIG_KEY)[baseKey];
const os = shell.platform();
const osOverridePath = host.getConfiguration(EXTENSION_CONFIG_KEY)[osOverrideKey(os, baseKey)];
return osOverridePath || host.getConfiguration(EXTENSION_CONFIG_KEY)[baseKey];
}
export function toolPathBaseKey(tool: string): string {
return `mssql-bdc.${tool}-path`;
return `mssql-bdc.${tool}-path`;
}
function osOverrideKey(os: Platform, baseKey: string): string {
const osKey = osKeyString(os);
return osKey ? `${baseKey}.${osKey}` : baseKey; // The 'else' clause should never happen so don't worry that this would result in double-checking a missing base key
const osKey = osKeyString(os);
return osKey ? `${baseKey}.${osKey}` : baseKey; // The 'else' clause should never happen so don't worry that this would result in double-checking a missing base key
}
function osKeyString(os: Platform): string | null {
switch (os) {
case Platform.Windows: return 'windows';
case Platform.MacOS: return 'mac';
case Platform.Linux: return 'linux';
default: return null;
}
switch (os) {
case Platform.Windows: return 'windows';
case Platform.MacOS: return 'mac';
case Platform.Linux: return 'linux';
default: return null;
}
}

View File

@@ -10,36 +10,36 @@ import * as tmp from 'tmp';
import { succeeded, Errorable } from '../interfaces';
type DownloadFunc =
(url: string, destination?: string, options?: any)
=> Promise<Buffer> & stream.Duplex; // Stream has additional events - see https://www.npmjs.com/package/download
(url: string, destination?: string, options?: any)
=> Promise<Buffer> & stream.Duplex; // Stream has additional events - see https://www.npmjs.com/package/download
let download: DownloadFunc;
function ensureDownloadFunc() {
if (!download) {
const home = process.env['HOME'];
download = require('download');
if (home) {
process.env['HOME'] = home;
}
}
if (!download) {
const home = process.env['HOME'];
download = require('download');
if (home) {
process.env['HOME'] = home;
}
}
}
export async function toTempFile(sourceUrl: string): Promise<Errorable<string>> {
const tempFileObj = tmp.fileSync({ prefix: 'mssql-bdc-autoinstall-' });
const downloadResult = await to(sourceUrl, tempFileObj.name);
if (succeeded(downloadResult)) {
return { succeeded: true, result: tempFileObj.name };
}
return { succeeded: false, error: downloadResult.error };
const tempFileObj = tmp.fileSync({ prefix: 'mssql-bdc-autoinstall-' });
const downloadResult = await to(sourceUrl, tempFileObj.name);
if (succeeded(downloadResult)) {
return { succeeded: true, result: tempFileObj.name };
}
return { succeeded: false, error: downloadResult.error };
}
export async function to(sourceUrl: string, destinationFile: string): Promise<Errorable<null>> {
ensureDownloadFunc();
try {
await download(sourceUrl, path.dirname(destinationFile), { filename: path.basename(destinationFile) });
return { succeeded: true, result: null };
} catch (e) {
return { succeeded: false, error: [e.message] };
}
ensureDownloadFunc();
try {
await download(sourceUrl, path.dirname(destinationFile), { filename: path.basename(destinationFile) });
return { succeeded: true, result: null };
} catch (e) {
return { succeeded: false, error: [e.message] };
}
}

View File

@@ -16,57 +16,57 @@ import { Errorable, failed } from '../interfaces';
import { addPathToConfig, toolPathBaseKey } from '../config/config';
export async function installKubectl(shell: Shell): Promise<Errorable<null>> {
const tool = 'kubectl';
const binFile = (shell.isUnix()) ? 'kubectl' : 'kubectl.exe';
const os = platformUrlString(shell.platform());
const tool = 'kubectl';
const binFile = (shell.isUnix()) ? 'kubectl' : 'kubectl.exe';
const os = platformUrlString(shell.platform());
const version = await getStableKubectlVersion();
if (failed(version)) {
return { succeeded: false, error: version.error };
}
const version = await getStableKubectlVersion();
if (failed(version)) {
return { succeeded: false, error: version.error };
}
const installFolder = getInstallFolder(shell, tool);
mkdirp.sync(installFolder);
const installFolder = getInstallFolder(shell, tool);
mkdirp.sync(installFolder);
const kubectlUrl = `https://storage.googleapis.com/kubernetes-release/release/${version.result.trim()}/bin/${os}/amd64/${binFile}`;
const downloadFile = path.join(installFolder, binFile);
const downloadResult = await download.to(kubectlUrl, downloadFile);
if (failed(downloadResult)) {
return { succeeded: false, error: [localize('downloadKubectlFailed', 'Failed to download kubectl: {0}', downloadResult.error[0])] };
}
const kubectlUrl = `https://storage.googleapis.com/kubernetes-release/release/${version.result.trim()}/bin/${os}/amd64/${binFile}`;
const downloadFile = path.join(installFolder, binFile);
const downloadResult = await download.to(kubectlUrl, downloadFile);
if (failed(downloadResult)) {
return { succeeded: false, error: [localize('downloadKubectlFailed', 'Failed to download kubectl: {0}', downloadResult.error[0])] };
}
if (shell.isUnix()) {
fs.chmodSync(downloadFile, '0777');
}
if (shell.isUnix()) {
fs.chmodSync(downloadFile, '0777');
}
await addPathToConfig(toolPathBaseKey(tool), downloadFile);
return { succeeded: true, result: null };
await addPathToConfig(toolPathBaseKey(tool), downloadFile);
return { succeeded: true, result: null };
}
async function getStableKubectlVersion(): Promise<Errorable<string>> {
const downloadResult = await download.toTempFile('https://storage.googleapis.com/kubernetes-release/release/stable.txt');
if (failed(downloadResult)) {
return { succeeded: false, error: [localize('kubectlVersionCheckFailed', 'Failed to establish kubectl stable version: {0}', downloadResult.error[0])] };
}
const version = fs.readFileSync(downloadResult.result, 'utf-8');
fs.unlinkSync(downloadResult.result);
return { succeeded: true, result: version };
const downloadResult = await download.toTempFile('https://storage.googleapis.com/kubernetes-release/release/stable.txt');
if (failed(downloadResult)) {
return { succeeded: false, error: [localize('kubectlVersionCheckFailed', 'Failed to establish kubectl stable version: {0}', downloadResult.error[0])] };
}
const version = fs.readFileSync(downloadResult.result, 'utf-8');
fs.unlinkSync(downloadResult.result);
return { succeeded: true, result: version };
}
export function getInstallFolder(shell: Shell, tool: string): string {
return path.join(shell.home(), `.mssql-bdc/tools/${tool}`);
return path.join(shell.home(), `.mssql-bdc/tools/${tool}`);
}
function platformUrlString(platform: Platform, supported?: Platform[]): string | null {
if (supported && supported.indexOf(platform) < 0) {
return null;
}
switch (platform) {
case Platform.Windows: return 'windows';
case Platform.MacOS: return 'darwin';
case Platform.Linux: return 'linux';
default: return null;
}
if (supported && supported.indexOf(platform) < 0) {
return null;
}
switch (platform) {
case Platform.Windows: return 'windows';
case Platform.MacOS: return 'darwin';
case Platform.Linux: return 'linux';
default: return null;
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vscode-nls';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { Shell } from '../utility/shell';
@@ -11,111 +11,111 @@ import { Host } from './host';
import { FS } from '../utility/fs';
export interface BinCheckContext {
readonly host: Host;
readonly fs: FS;
readonly shell: Shell;
readonly installDependenciesCallback: () => void;
binFound: boolean;
binPath: string;
readonly host: Host;
readonly fs: FS;
readonly shell: Shell;
readonly installDependenciesCallback: () => void;
binFound: boolean;
binPath: string;
}
interface FindBinaryResult {
err: number | null;
output: string;
err: number | null;
output: string;
}
async function findBinary(shell: Shell, binName: string): Promise<FindBinaryResult> {
let cmd = `which ${binName}`;
let cmd = `which ${binName}`;
if (shell.isWindows()) {
cmd = `where.exe ${binName}.exe`;
}
if (shell.isWindows()) {
cmd = `where.exe ${binName}.exe`;
}
const opts = {
async: true,
env: {
HOME: process.env.HOME,
PATH: process.env.PATH
}
};
const opts = {
async: true,
env: {
HOME: process.env.HOME,
PATH: process.env.PATH
}
};
const execResult = await shell.execCore(cmd, opts);
if (execResult.code) {
return { err: execResult.code, output: execResult.stderr };
}
const execResult = await shell.execCore(cmd, opts);
if (execResult.code) {
return { err: execResult.code, output: execResult.stderr };
}
return { err: null, output: execResult.stdout };
return { err: null, output: execResult.stdout };
}
export function execPath(shell: Shell, basePath: string): string {
let bin = basePath;
if (shell.isWindows() && bin && !(bin.endsWith('.exe'))) {
bin = bin + '.exe';
}
return bin;
let bin = basePath;
if (shell.isWindows() && bin && !(bin.endsWith('.exe'))) {
bin = bin + '.exe';
}
return bin;
}
type CheckPresentFailureReason = 'inferFailed' | 'configuredFileMissing';
const installDependenciesAction = localize('installDependenciesAction','Install dependencies');
const learnMoreAction = localize('learnMoreAction','Learn more');
const installDependenciesAction = localize('installDependenciesAction', 'Install dependencies');
const learnMoreAction = localize('learnMoreAction', 'Learn more');
function alertNoBin(host: Host, binName: string, failureReason: CheckPresentFailureReason, message: string, installDependencies: () => void): void {
switch (failureReason) {
case 'inferFailed':
host.showErrorMessage(message, installDependenciesAction, learnMoreAction).then(
(str) => {
switch (str) {
case learnMoreAction:
host.showInformationMessage(localize('moreInfoMsg', 'Add {0} directory to path, or set "mssql-bdc.{0}-path" config to {0} binary.', binName));
break;
case installDependenciesAction:
installDependencies();
break;
}
switch (failureReason) {
case 'inferFailed':
host.showErrorMessage(message, installDependenciesAction, learnMoreAction).then(
(str) => {
switch (str) {
case learnMoreAction:
host.showInformationMessage(localize('moreInfoMsg', 'Add {0} directory to path, or set "mssql-bdc.{0}-path" config to {0} binary.', binName));
break;
case installDependenciesAction:
installDependencies();
break;
}
}
);
break;
case 'configuredFileMissing':
host.showErrorMessage(message, installDependenciesAction).then(
(str) => {
if (str === installDependenciesAction) {
installDependencies();
}
}
);
break;
}
}
);
break;
case 'configuredFileMissing':
host.showErrorMessage(message, installDependenciesAction).then(
(str) => {
if (str === installDependenciesAction) {
installDependencies();
}
}
);
break;
}
}
export async function checkForBinary(context: BinCheckContext, bin: string | undefined, binName: string, inferFailedMessage: string, configuredFileMissingMessage: string, alertOnFail: boolean): Promise<boolean> {
if (!bin) {
const fb = await findBinary(context.shell, binName);
if (!bin) {
const fb = await findBinary(context.shell, binName);
if (fb.err || fb.output.length === 0) {
if (alertOnFail) {
alertNoBin(context.host, binName, 'inferFailed', inferFailedMessage, context.installDependenciesCallback);
}
return false;
}
if (fb.err || fb.output.length === 0) {
if (alertOnFail) {
alertNoBin(context.host, binName, 'inferFailed', inferFailedMessage, context.installDependenciesCallback);
}
return false;
}
context.binFound = true;
context.binFound = true;
return true;
}
return true;
}
if (context.shell.isWindows) {
context.binFound = context.fs.existsSync(bin);
} else {
const sr = await context.shell.exec(`ls ${bin}`);
context.binFound = (!!sr && sr.code === 0);
}
if (context.binFound) {
context.binPath = bin;
} else {
if (alertOnFail) {
alertNoBin(context.host, binName, 'configuredFileMissing', configuredFileMissingMessage, context.installDependenciesCallback);
}
}
if (context.shell.isWindows) {
context.binFound = context.fs.existsSync(bin);
} else {
const sr = await context.shell.exec(`ls ${bin}`);
context.binFound = (!!sr && sr.code === 0);
}
if (context.binFound) {
context.binPath = bin;
} else {
if (alertOnFail) {
alertNoBin(context.host, binName, 'configuredFileMissing', configuredFileMissingMessage, context.installDependenciesCallback);
}
}
return context.binFound;
return context.binFound;
}

View File

@@ -6,61 +6,61 @@
import { Errorable, failed } from '../interfaces';
interface CompatibilityGuaranteed {
readonly guaranteed: true;
readonly guaranteed: true;
}
interface CompatibilityNotGuaranteed {
readonly guaranteed: false;
readonly didCheck: boolean;
readonly clientVersion: string;
readonly serverVersion: string;
readonly guaranteed: false;
readonly didCheck: boolean;
readonly clientVersion: string;
readonly serverVersion: string;
}
export type Compatibility = CompatibilityGuaranteed | CompatibilityNotGuaranteed;
export function isGuaranteedCompatible(c: Compatibility): c is CompatibilityGuaranteed {
return c.guaranteed;
return c.guaranteed;
}
export interface Version {
readonly major: string;
readonly minor: string;
readonly gitVersion: string;
readonly major: string;
readonly minor: string;
readonly gitVersion: string;
}
export async function check(kubectlLoadJSON: (cmd: string) => Promise<Errorable<any>>): Promise<Compatibility> {
const version = await kubectlLoadJSON('version -o json');
if (failed(version)) {
return {
guaranteed: false,
didCheck: false,
clientVersion: '',
serverVersion: ''
};
}
const version = await kubectlLoadJSON('version -o json');
if (failed(version)) {
return {
guaranteed: false,
didCheck: false,
clientVersion: '',
serverVersion: ''
};
}
const clientVersion: Version = version.result.clientVersion;
const serverVersion: Version = version.result.serverVersion;
const clientVersion: Version = version.result.clientVersion;
const serverVersion: Version = version.result.serverVersion;
if (isCompatible(clientVersion, serverVersion)) {
return { guaranteed: true };
}
if (isCompatible(clientVersion, serverVersion)) {
return { guaranteed: true };
}
return {
guaranteed: false,
didCheck: true,
clientVersion: clientVersion.gitVersion,
serverVersion: serverVersion.gitVersion
};
return {
guaranteed: false,
didCheck: true,
clientVersion: clientVersion.gitVersion,
serverVersion: serverVersion.gitVersion
};
}
function isCompatible(clientVersion: Version, serverVersion: Version): boolean {
if (clientVersion.major === serverVersion.major) {
const clientMinor = Number.parseInt(clientVersion.minor);
const serverMinor = Number.parseInt(serverVersion.minor);
if (Number.isInteger(clientMinor) && Number.isInteger(serverMinor) && Math.abs(clientMinor - serverMinor) <= 1) {
return true;
}
}
return false;
if (clientVersion.major === serverVersion.major) {
const clientMinor = Number.parseInt(clientVersion.minor);
const serverMinor = Number.parseInt(serverVersion.minor);
if (Number.isInteger(clientMinor) && Number.isInteger(serverMinor) && Math.abs(clientMinor - serverMinor) <= 1) {
return true;
}
}
return false;
}

View File

@@ -6,37 +6,37 @@
import * as vscode from 'vscode';
export interface Host {
showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined>;
showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined>;
showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined>;
getConfiguration(key: string): any;
onDidChangeConfiguration(listener: (ch: vscode.ConfigurationChangeEvent) => any): vscode.Disposable;
showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined>;
showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined>;
showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined>;
getConfiguration(key: string): any;
onDidChangeConfiguration(listener: (ch: vscode.ConfigurationChangeEvent) => any): vscode.Disposable;
}
export const host: Host = {
showErrorMessage : showErrorMessage,
showWarningMessage : showWarningMessage,
showInformationMessage : showInformationMessage,
getConfiguration : getConfiguration,
onDidChangeConfiguration : onDidChangeConfiguration,
showErrorMessage: showErrorMessage,
showWarningMessage: showWarningMessage,
showInformationMessage: showInformationMessage,
getConfiguration: getConfiguration,
onDidChangeConfiguration: onDidChangeConfiguration,
};
function showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items);
return vscode.window.showErrorMessage(message, ...items);
}
function showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showWarningMessage(message, ...items);
return vscode.window.showWarningMessage(message, ...items);
}
function showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showInformationMessage(message, ...items);
return vscode.window.showInformationMessage(message, ...items);
}
function getConfiguration(key: string): any {
return vscode.workspace.getConfiguration(key);
return vscode.workspace.getConfiguration(key);
}
function onDidChangeConfiguration(listener: (e: vscode.ConfigurationChangeEvent) => any): vscode.Disposable {
return vscode.workspace.onDidChangeConfiguration(listener);
return vscode.workspace.onDidChangeConfiguration(listener);
}

View File

@@ -15,128 +15,128 @@ import * as compatibility from './compatibility';
import { getToolPath } from '../config/config';
export interface Kubectl {
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean>;
asJson<T>(command: string): Promise<Errorable<T>>;
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined>;
getContext(): Context;
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean>;
asJson<T>(command: string): Promise<Errorable<T>>;
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined>;
getContext(): Context;
}
interface Context {
readonly host: Host;
readonly fs: FS;
readonly shell: Shell;
readonly installDependenciesCallback: () => void;
binFound: boolean;
binPath: string;
readonly host: Host;
readonly fs: FS;
readonly shell: Shell;
readonly installDependenciesCallback: () => void;
binFound: boolean;
binPath: string;
}
class KubectlImpl implements Kubectl {
constructor(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void, kubectlFound: boolean) {
this.context = { host : host, fs : fs, shell : shell, installDependenciesCallback : installDependenciesCallback, binFound : kubectlFound, binPath : 'kubectl' };
}
constructor(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void, kubectlFound: boolean) {
this.context = { host: host, fs: fs, shell: shell, installDependenciesCallback: installDependenciesCallback, binFound: kubectlFound, binPath: 'kubectl' };
}
readonly context: Context;
readonly context: Context;
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
return checkPresent(this.context, errorMessageMode);
}
asJson<T>(command: string): Promise<Errorable<T>> {
return asJson(this.context, command);
}
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined> {
return invokeAsync(this.context, command, stdin);
}
checkPresent(errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
return checkPresent(this.context, errorMessageMode);
}
asJson<T>(command: string): Promise<Errorable<T>> {
return asJson(this.context, command);
}
invokeAsync(command: string, stdin?: string): Promise<ShellResult | undefined> {
return invokeAsync(this.context, command, stdin);
}
getContext(): Context {
return this.context;
}
getContext(): Context {
return this.context;
}
}
export function create(host: Host, fs: FS, shell: Shell, installDependenciesCallback: () => void): Kubectl {
return new KubectlImpl(host, fs, shell, installDependenciesCallback, false);
return new KubectlImpl(host, fs, shell, installDependenciesCallback, false);
}
export enum CheckPresentMessageMode {
Command,
Activation,
Silent,
Command,
Activation,
Silent,
}
async function checkPresent(context: Context, errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
if (context.binFound) {
return true;
}
if (context.binFound) {
return true;
}
return await checkForKubectlInternal(context, errorMessageMode);
return await checkForKubectlInternal(context, errorMessageMode);
}
async function checkForKubectlInternal(context: Context, errorMessageMode: CheckPresentMessageMode): Promise<boolean> {
const binName = 'kubectl';
const bin = getToolPath(context.host, context.shell, binName);
const binName = 'kubectl';
const bin = getToolPath(context.host, context.shell, binName);
const contextMessage = getCheckKubectlContextMessage(errorMessageMode);
const inferFailedMessage = localize('binaryNotFound', 'Could not find {0} binary. {1}', binName, contextMessage);
const configuredFileMissingMessage = localize('binaryNotInstalled', '{0} is not installed. {1}', bin, contextMessage);
const contextMessage = getCheckKubectlContextMessage(errorMessageMode);
const inferFailedMessage = localize('binaryNotFound', 'Could not find {0} binary. {1}', binName, contextMessage);
const configuredFileMissingMessage = localize('binaryNotInstalled', '{0} is not installed. {1}', bin, contextMessage);
return await binutil.checkForBinary(context, bin, binName, inferFailedMessage, configuredFileMissingMessage, errorMessageMode !== CheckPresentMessageMode.Silent);
return await binutil.checkForBinary(context, bin, binName, inferFailedMessage, configuredFileMissingMessage, errorMessageMode !== CheckPresentMessageMode.Silent);
}
function getCheckKubectlContextMessage(errorMessageMode: CheckPresentMessageMode): string {
if (errorMessageMode === CheckPresentMessageMode.Activation) {
return localize('kubernetesRequired',' SQL Server Big data cluster requires kubernetes.');
} else if (errorMessageMode === CheckPresentMessageMode.Command) {
return localize('cannotExecuteCmd', ' Cannot execute command.');
}
return '';
if (errorMessageMode === CheckPresentMessageMode.Activation) {
return localize('kubernetesRequired', ' SQL Server Big data cluster requires kubernetes.');
} else if (errorMessageMode === CheckPresentMessageMode.Command) {
return localize('cannotExecuteCmd', ' Cannot execute command.');
}
return '';
}
async function invokeAsync(context: Context, command: string, stdin?: string): Promise<ShellResult | undefined> {
if (await checkPresent(context, CheckPresentMessageMode.Command)) {
const bin = baseKubectlPath(context);
const cmd = `${bin} ${command}`;
const sr = await context.shell.exec(cmd, stdin);
if (sr && sr.code !== 0) {
checkPossibleIncompatibility(context);
}
return sr;
} else {
return { code: -1, stdout: '', stderr: '' };
}
if (await checkPresent(context, CheckPresentMessageMode.Command)) {
const bin = baseKubectlPath(context);
const cmd = `${bin} ${command}`;
const sr = await context.shell.exec(cmd, stdin);
if (sr && sr.code !== 0) {
checkPossibleIncompatibility(context);
}
return sr;
} else {
return { code: -1, stdout: '', stderr: '' };
}
}
// TODO: invalidate this when the context changes or if we know kubectl has changed (e.g. config)
let checkedCompatibility = false; // We don't want to spam the user (or CPU!) repeatedly running the version check
async function checkPossibleIncompatibility(context: Context): Promise<void> {
if (checkedCompatibility) {
return;
}
checkedCompatibility = true;
const compat = await compatibility.check((cmd) => asJson<compatibility.Version>(context, cmd));
if (!compatibility.isGuaranteedCompatible(compat) && compat.didCheck) {
const versionAlert = localize('kubectlVersionIncompatible', 'kubectl version ${0} may be incompatible with cluster Kubernetes version {1}', compat.clientVersion, compat.serverVersion);
context.host.showWarningMessage(versionAlert);
}
if (checkedCompatibility) {
return;
}
checkedCompatibility = true;
const compat = await compatibility.check((cmd) => asJson<compatibility.Version>(context, cmd));
if (!compatibility.isGuaranteedCompatible(compat) && compat.didCheck) {
const versionAlert = localize('kubectlVersionIncompatible', 'kubectl version ${0} may be incompatible with cluster Kubernetes version {1}', compat.clientVersion, compat.serverVersion);
context.host.showWarningMessage(versionAlert);
}
}
export function baseKubectlPath(context: Context): string {
let bin = getToolPath(context.host, context.shell, 'kubectl');
if (!bin) {
bin = 'kubectl';
}
return bin;
let bin = getToolPath(context.host, context.shell, 'kubectl');
if (!bin) {
bin = 'kubectl';
}
return bin;
}
async function asJson<T>(context: Context, command: string): Promise<Errorable<T>> {
const shellResult = await invokeAsync(context, command);
if (!shellResult) {
return { succeeded: false, error: [localize('cannotRunCommand', 'Unable to run command ({0})', command)] };
}
const shellResult = await invokeAsync(context, command);
if (!shellResult) {
return { succeeded: false, error: [localize('cannotRunCommand', 'Unable to run command ({0})', command)] };
}
if (shellResult.code === 0) {
return { succeeded: true, result: JSON.parse(shellResult.stdout.trim()) as T };
if (shellResult.code === 0) {
return { succeeded: true, result: JSON.parse(shellResult.stdout.trim()) as T };
}
return { succeeded: false, error: [ shellResult.stderr ] };
}
return { succeeded: false, error: [shellResult.stderr] };
}

View File

@@ -11,126 +11,126 @@ import { Kubectl } from './kubectl';
import { failed, ClusterType } from '../interfaces';
export interface KubectlContext {
readonly clusterName: string;
readonly contextName: string;
readonly userName: string;
readonly active: boolean;
readonly clusterName: string;
readonly contextName: string;
readonly userName: string;
readonly active: boolean;
}
interface Kubeconfig {
readonly apiVersion: string;
readonly 'current-context': string;
readonly clusters: {
readonly name: string;
readonly cluster: {
readonly server: string;
readonly 'certificate-authority'?: string;
readonly 'certificate-authority-data'?: string;
};
}[] | undefined;
readonly contexts: {
readonly name: string;
readonly context: {
readonly cluster: string;
readonly user: string;
readonly namespace?: string;
};
}[] | undefined;
readonly users: {
readonly name: string;
readonly user: {};
}[] | undefined;
readonly apiVersion: string;
readonly 'current-context': string;
readonly clusters: {
readonly name: string;
readonly cluster: {
readonly server: string;
readonly 'certificate-authority'?: string;
readonly 'certificate-authority-data'?: string;
};
}[] | undefined;
readonly contexts: {
readonly name: string;
readonly context: {
readonly cluster: string;
readonly user: string;
readonly namespace?: string;
};
}[] | undefined;
readonly users: {
readonly name: string;
readonly user: {};
}[] | undefined;
}
export interface ClusterConfig {
readonly server: string;
readonly certificateAuthority: string | undefined;
readonly server: string;
readonly certificateAuthority: string | undefined;
}
async function getKubeconfig(kubectl: Kubectl): Promise<Kubeconfig | null> {
const shellResult = await kubectl.asJson<any>('config view -o json');
if (failed(shellResult)) {
vscode.window.showErrorMessage(shellResult.error[0]);
return null;
}
return shellResult.result;
const shellResult = await kubectl.asJson<any>('config view -o json');
if (failed(shellResult)) {
vscode.window.showErrorMessage(shellResult.error[0]);
return null;
}
return shellResult.result;
}
export async function getCurrentClusterConfig(kubectl: Kubectl): Promise<ClusterConfig | undefined> {
const kubeConfig = await getKubeconfig(kubectl);
if (!kubeConfig || !kubeConfig.clusters || !kubeConfig.contexts) {
return undefined;
}
const contextConfig = kubeConfig.contexts.find((context) => context.name === kubeConfig['current-context'])!;
const clusterConfig = kubeConfig.clusters.find((cluster) => cluster.name === contextConfig.context.cluster)!;
return {
server: clusterConfig.cluster.server,
certificateAuthority: clusterConfig.cluster['certificate-authority']
};
const kubeConfig = await getKubeconfig(kubectl);
if (!kubeConfig || !kubeConfig.clusters || !kubeConfig.contexts) {
return undefined;
}
const contextConfig = kubeConfig.contexts.find((context) => context.name === kubeConfig['current-context'])!;
const clusterConfig = kubeConfig.clusters.find((cluster) => cluster.name === contextConfig.context.cluster)!;
return {
server: clusterConfig.cluster.server,
certificateAuthority: clusterConfig.cluster['certificate-authority']
};
}
export async function getContexts(kubectl: Kubectl): Promise<KubectlContext[]> {
const kubectlConfig = await getKubeconfig(kubectl);
if (!kubectlConfig) {
return [];
}
const currentContext = kubectlConfig['current-context'];
const contexts = kubectlConfig.contexts || [];
return contexts.map((c) => {
return {
clusterName: c.context.cluster,
contextName: c.name,
userName: c.context.user,
active: c.name === currentContext
};
});
const kubectlConfig = await getKubeconfig(kubectl);
if (!kubectlConfig) {
return [];
}
const currentContext = kubectlConfig['current-context'];
const contexts = kubectlConfig.contexts || [];
return contexts.map((c) => {
return {
clusterName: c.context.cluster,
contextName: c.name,
userName: c.context.user,
active: c.name === currentContext
};
});
}
export async function setContext(kubectl: Kubectl, targetContext: string): Promise<void> {
const shellResult = await kubectl.invokeAsync(`config use-context ${targetContext}`);
if (!shellResult || shellResult.code !== 0) {
// TODO: Update error handling for now.
let errMsg = shellResult ? shellResult.stderr : localize('runKubectlFailed', 'Unable to run kubectl');
vscode.window.showErrorMessage(localize('setClusterFailed', 'Failed to set \'{0}\' as current cluster: {1}', targetContext, errMsg));
}
const shellResult = await kubectl.invokeAsync(`config use-context ${targetContext}`);
if (!shellResult || shellResult.code !== 0) {
// TODO: Update error handling for now.
let errMsg = shellResult ? shellResult.stderr : localize('runKubectlFailed', 'Unable to run kubectl');
vscode.window.showErrorMessage(localize('setClusterFailed', 'Failed to set \'{0}\' as current cluster: {1}', targetContext, errMsg));
}
}
export async function inferCurrentClusterType(kubectl: Kubectl): Promise<ClusterType> {
let latestContextName = '';
let latestContextName = '';
const ctxsr = await kubectl.invokeAsync('config current-context');
if (ctxsr && ctxsr.code === 0) {
latestContextName = ctxsr.stdout.trim();
} else {
return ClusterType.Other;
}
const ctxsr = await kubectl.invokeAsync('config current-context');
if (ctxsr && ctxsr.code === 0) {
latestContextName = ctxsr.stdout.trim();
} else {
return ClusterType.Other;
}
const cisr = await kubectl.invokeAsync('cluster-info');
if (!cisr || cisr.code !== 0) {
return ClusterType.Unknown;
}
const masterInfos = cisr.stdout.split('\n')
.filter((s) => s.indexOf('master is running at') >= 0);
const cisr = await kubectl.invokeAsync('cluster-info');
if (!cisr || cisr.code !== 0) {
return ClusterType.Unknown;
}
const masterInfos = cisr.stdout.split('\n')
.filter((s) => s.indexOf('master is running at') >= 0);
if (masterInfos.length === 0) {
return ClusterType.Other;
}
if (masterInfos.length === 0) {
return ClusterType.Other;
}
const masterInfo = masterInfos[0];
if (masterInfo.indexOf('azmk8s.io') >= 0 || masterInfo.indexOf('azure.com') >= 0) {
return ClusterType.AKS;
}
const masterInfo = masterInfos[0];
if (masterInfo.indexOf('azmk8s.io') >= 0 || masterInfo.indexOf('azure.com') >= 0) {
return ClusterType.AKS;
}
if (latestContextName) {
const gcsr = await kubectl.invokeAsync(`config get-contexts ${latestContextName}`);
if (gcsr && gcsr.code === 0) {
if (gcsr.stdout.indexOf('minikube') >= 0) {
return ClusterType.Minikube;
}
}
}
if (latestContextName) {
const gcsr = await kubectl.invokeAsync(`config get-contexts ${latestContextName}`);
if (gcsr && gcsr.code === 0) {
if (gcsr.stdout.indexOf('minikube') >= 0) {
return ClusterType.Minikube;
}
}
}
return ClusterType.Other;
return ClusterType.Other;
}

View File

@@ -8,22 +8,22 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export interface ISqlServerBigDataClusterChannel {
showOutput(message: any, title?: string): void;
showOutput(message: any, title?: string): void;
}
const outputChannelName = localize('bigDataClusterOutputChannel', 'SQL Server big data cluster');
class SqlServerBigDataCluster implements ISqlServerBigDataClusterChannel {
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel(outputChannelName);
private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel(outputChannelName);
showOutput(message: any, title?: string): void {
if (title) {
const simplifiedTime = (new Date()).toISOString().replace(/z|t/gi, ' ').trim(); // YYYY-MM-DD HH:mm:ss.sss
const hightlightingTitle = `[${title} ${simplifiedTime}]`;
this.channel.appendLine(hightlightingTitle);
}
this.channel.appendLine(message);
this.channel.show();
}
showOutput(message: any, title?: string): void {
if (title) {
const simplifiedTime = (new Date()).toISOString().replace(/z|t/gi, ' ').trim(); // YYYY-MM-DD HH:mm:ss.sss
const hightlightingTitle = `[${title} ${simplifiedTime}]`;
this.channel.appendLine(hightlightingTitle);
}
this.channel.appendLine(message);
this.channel.show();
}
}
export const sqlserverbigdataclusterchannel: ISqlServerBigDataClusterChannel = new SqlServerBigDataCluster();

View File

@@ -35,26 +35,26 @@ export function deactivate(): void {
}
export async function installDependencies() {
const gotKubectl = await kubectl.checkPresent(CheckPresentMessageMode.Silent);
const gotKubectl = await kubectl.checkPresent(CheckPresentMessageMode.Silent);
const installPromises = [
installDependency('kubectl', gotKubectl, installKubectl)
];
const installPromises = [
installDependency('kubectl', gotKubectl, installKubectl)
];
await Promise.all(installPromises);
await Promise.all(installPromises);
sqlserverbigdataclusterchannel.showOutput(localize('done', 'Done'));
sqlserverbigdataclusterchannel.showOutput(localize('done', 'Done'));
}
async function installDependency(name: string, alreadyGot: boolean, installFunc: (shell: Shell) => Promise<Errorable<null>>): Promise<void> {
if (alreadyGot) {
sqlserverbigdataclusterchannel.showOutput(localize('dependencyInstalled', '{0} already installed...', name));
} else {
sqlserverbigdataclusterchannel.showOutput(localize('installingDependency', 'Installing {0}...', name));
const result = await installFunc(shell);
if (failed(result)) {
sqlserverbigdataclusterchannel.showOutput(localize('installingDependencyFailed', 'Unable to install {0}: {1}', name, result.error[0]));
}
}
if (alreadyGot) {
sqlserverbigdataclusterchannel.showOutput(localize('dependencyInstalled', '{0} already installed...', name));
} else {
sqlserverbigdataclusterchannel.showOutput(localize('installingDependency', 'Installing {0}...', name));
const result = await installFunc(shell);
if (failed(result)) {
sqlserverbigdataclusterchannel.showOutput(localize('installingDependencyFailed', 'Unable to install {0}: {1}', name, result.error[0]));
}
}
}

View File

@@ -12,7 +12,7 @@ import { Kubectl } from './kubectl/kubectl';
*/
export class MainController {
protected _context: vscode.ExtensionContext;
protected _kubectl : Kubectl;
protected _kubectl: Kubectl;
public constructor(context: vscode.ExtensionContext, kubectl: Kubectl) {
this._context = context;

View File

@@ -11,16 +11,16 @@ import mkdirp = require('mkdirp');
import { Kubectl, baseKubectlPath } from '../kubectl/kubectl';
import { KubectlContext } from '../kubectl/kubectlUtils';
export interface Scriptable {
getScriptProperties(): Promise<ScriptingDictionary<string>>;
getTargetKubectlContext() : KubectlContext;
}
export interface Scriptable {
getScriptProperties(): Promise<ScriptingDictionary<string>>;
getTargetKubectlContext(): KubectlContext;
}
export interface ScriptingDictionary<V> {
export interface ScriptingDictionary<V> {
[name: string]: V;
}
const deployFilePrefix : string = 'mssql-bdc-deploy';
const deployFilePrefix: string = 'mssql-bdc-deploy';
export class ScriptGenerator {
private _shell: Shell;
@@ -33,7 +33,7 @@ export class ScriptGenerator {
this._kubectlPath = baseKubectlPath(this._kubectl.getContext());
}
public async generateDeploymentScript(scriptable: Scriptable) : Promise<void> {
public async generateDeploymentScript(scriptable: Scriptable): Promise<void> {
let targetClusterName = scriptable.getTargetKubectlContext().clusterName;
let targetContextName = scriptable.getTargetKubectlContext().contextName;
@@ -67,7 +67,7 @@ export class ScriptGenerator {
}
const handleError = (err: NodeJS.ErrnoException) => {
if (err) {
vscode.window.showErrorMessage(err.message);
}
if (err) {
vscode.window.showErrorMessage(err.message);
}
};

View File

@@ -5,61 +5,61 @@
import * as sysfs from 'fs';
export interface FS {
existsSync(path: string): boolean;
readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void;
readFileSync(filename: string, encoding: string): string;
readFileToBufferSync(filename: string): Buffer;
writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
writeFileSync(filename: string, data: any): void;
dirSync(path: string): string[];
unlinkAsync(path: string): Promise<void>;
existsAsync(path: string): Promise<boolean>;
openAsync(path: string, flags: string): Promise<void>;
statSync(path: string): sysfs.Stats;
existsSync(path: string): boolean;
readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void;
readFileSync(filename: string, encoding: string): string;
readFileToBufferSync(filename: string): Buffer;
writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
writeFileSync(filename: string, data: any): void;
dirSync(path: string): string[];
unlinkAsync(path: string): Promise<void>;
existsAsync(path: string): Promise<boolean>;
openAsync(path: string, flags: string): Promise<void>;
statSync(path: string): sysfs.Stats;
}
export const fs: FS = {
existsSync: (path) => sysfs.existsSync(path),
readFile: (filename, encoding, callback) => sysfs.readFile(filename, encoding, callback),
readFileSync: (filename, encoding) => sysfs.readFileSync(filename, encoding),
readFileToBufferSync: (filename) => sysfs.readFileSync(filename),
writeFile: (filename, data, callback) => sysfs.writeFile(filename, data, callback),
writeFileSync: (filename, data) => sysfs.writeFileSync(filename, data),
dirSync: (path) => sysfs.readdirSync(path),
existsSync: (path) => sysfs.existsSync(path),
readFile: (filename, encoding, callback) => sysfs.readFile(filename, encoding, callback),
readFileSync: (filename, encoding) => sysfs.readFileSync(filename, encoding),
readFileToBufferSync: (filename) => sysfs.readFileSync(filename),
writeFile: (filename, data, callback) => sysfs.writeFile(filename, data, callback),
writeFileSync: (filename, data) => sysfs.writeFileSync(filename, data),
dirSync: (path) => sysfs.readdirSync(path),
unlinkAsync: (path) => {
return new Promise((resolve, reject) => {
sysfs.unlink(path, (error) => {
if (error) {
reject();
return;
}
unlinkAsync: (path) => {
return new Promise((resolve, reject) => {
sysfs.unlink(path, (error) => {
if (error) {
reject();
return;
}
resolve();
});
});
},
resolve();
});
});
},
existsAsync: (path) => {
return new Promise((resolve) => {
sysfs.exists(path, (exists) => {
resolve(exists);
});
});
},
existsAsync: (path) => {
return new Promise((resolve) => {
sysfs.exists(path, (exists) => {
resolve(exists);
});
});
},
openAsync: (path, flags) => {
return new Promise((resolve, reject) => {
sysfs.open(path, flags, (error, _fd) => {
if (error) {
reject();
return;
}
openAsync: (path, flags) => {
return new Promise((resolve, reject) => {
sysfs.open(path, flags, (error, _fd) => {
if (error) {
reject();
return;
}
resolve();
});
});
},
resolve();
});
});
},
statSync: (path) => sysfs.statSync(path)
statSync: (path) => sysfs.statSync(path)
};

View File

@@ -12,193 +12,193 @@ import { getActiveKubeconfig, getToolPath } from '../config/config';
import { host } from '../kubectl/host';
export enum Platform {
Windows,
MacOS,
Linux,
Unsupported,
Windows,
MacOS,
Linux,
Unsupported,
}
export interface ExecCallback extends shelljs.ExecCallback {}
export interface ExecCallback extends shelljs.ExecCallback { }
export interface Shell {
isWindows(): boolean;
isUnix(): boolean;
platform(): Platform;
home(): string;
combinePath(basePath: string, relativePath: string): string;
fileUri(filePath: string): vscode.Uri;
execOpts(): any;
exec(cmd: string, stdin?: string): Promise<ShellResult | undefined>;
execCore(cmd: string, opts: any, stdin?: string): Promise<ShellResult>;
unquotedPath(path: string): string;
which(bin: string): string | null;
cat(path: string): string;
ls(path: string): string[];
isWindows(): boolean;
isUnix(): boolean;
platform(): Platform;
home(): string;
combinePath(basePath: string, relativePath: string): string;
fileUri(filePath: string): vscode.Uri;
execOpts(): any;
exec(cmd: string, stdin?: string): Promise<ShellResult | undefined>;
execCore(cmd: string, opts: any, stdin?: string): Promise<ShellResult>;
unquotedPath(path: string): string;
which(bin: string): string | null;
cat(path: string): string;
ls(path: string): string[];
}
export const shell: Shell = {
isWindows : isWindows,
isUnix : isUnix,
platform : platform,
home : home,
combinePath : combinePath,
fileUri : fileUri,
execOpts : execOpts,
exec : exec,
execCore : execCore,
unquotedPath : unquotedPath,
which: which,
cat: cat,
ls: ls,
isWindows: isWindows,
isUnix: isUnix,
platform: platform,
home: home,
combinePath: combinePath,
fileUri: fileUri,
execOpts: execOpts,
exec: exec,
execCore: execCore,
unquotedPath: unquotedPath,
which: which,
cat: cat,
ls: ls,
};
const WINDOWS: string = 'win32';
export interface ShellResult {
readonly code: number;
readonly stdout: string;
readonly stderr: string;
readonly code: number;
readonly stdout: string;
readonly stderr: string;
}
export type ShellHandler = (code: number, stdout: string, stderr: string) => void;
function isWindows(): boolean {
return (process.platform === WINDOWS);
return (process.platform === WINDOWS);
}
function isUnix(): boolean {
return !isWindows();
return !isWindows();
}
function platform(): Platform {
switch (process.platform) {
case 'win32': return Platform.Windows;
case 'darwin': return Platform.MacOS;
case 'linux': return Platform.Linux;
default: return Platform.Unsupported;
}
switch (process.platform) {
case 'win32': return Platform.Windows;
case 'darwin': return Platform.MacOS;
case 'linux': return Platform.Linux;
default: return Platform.Unsupported;
}
}
function concatIfBoth(s1: string | undefined, s2: string | undefined): string | undefined {
return s1 && s2 ? s1.concat(s2) : undefined;
return s1 && s2 ? s1.concat(s2) : undefined;
}
function home(): string {
return process.env['HOME'] ||
concatIfBoth(process.env['HOMEDRIVE'], process.env['HOMEPATH']) ||
process.env['USERPROFILE'] ||
'';
return process.env['HOME'] ||
concatIfBoth(process.env['HOMEDRIVE'], process.env['HOMEPATH']) ||
process.env['USERPROFILE'] ||
'';
}
function combinePath(basePath: string, relativePath: string) {
let separator = '/';
if (isWindows()) {
relativePath = relativePath.replace(/\//g, '\\');
separator = '\\';
}
return basePath + separator + relativePath;
let separator = '/';
if (isWindows()) {
relativePath = relativePath.replace(/\//g, '\\');
separator = '\\';
}
return basePath + separator + relativePath;
}
function isWindowsFilePath(filePath: string) {
return filePath[1] === ':' && filePath[2] === '\\';
return filePath[1] === ':' && filePath[2] === '\\';
}
function fileUri(filePath: string): vscode.Uri {
if (isWindowsFilePath(filePath)) {
return vscode.Uri.parse('file:///' + filePath.replace(/\\/g, '/'));
}
return vscode.Uri.parse('file://' + filePath);
if (isWindowsFilePath(filePath)) {
return vscode.Uri.parse('file:///' + filePath.replace(/\\/g, '/'));
}
return vscode.Uri.parse('file://' + filePath);
}
function execOpts(): any {
let env = process.env;
if (isWindows()) {
env = Object.assign({ }, env, { HOME: home() });
}
env = shellEnvironment(env);
const opts = {
cwd: vscode.workspace.rootPath,
env: env,
async: true
};
return opts;
let env = process.env;
if (isWindows()) {
env = Object.assign({}, env, { HOME: home() });
}
env = shellEnvironment(env);
const opts = {
cwd: vscode.workspace.rootPath,
env: env,
async: true
};
return opts;
}
async function exec(cmd: string, stdin?: string): Promise<ShellResult | undefined> {
try {
return await execCore(cmd, execOpts(), stdin);
} catch (ex) {
vscode.window.showErrorMessage(ex);
return undefined;
}
try {
return await execCore(cmd, execOpts(), stdin);
} catch (ex) {
vscode.window.showErrorMessage(ex);
return undefined;
}
}
function execCore(cmd: string, opts: any, stdin?: string): Promise<ShellResult> {
return new Promise<ShellResult>((resolve) => {
const proc = shelljs.exec(cmd, opts, (code, stdout, stderr) => resolve({code : code, stdout : stdout, stderr : stderr}));
if (stdin) {
proc.stdin.end(stdin);
}
});
return new Promise<ShellResult>((resolve) => {
const proc = shelljs.exec(cmd, opts, (code, stdout, stderr) => resolve({ code: code, stdout: stdout, stderr: stderr }));
if (stdin) {
proc.stdin.end(stdin);
}
});
}
function unquotedPath(path: string): string {
if (isWindows() && path && path.length > 1 && path.startsWith('"') && path.endsWith('"')) {
return path.substring(1, path.length - 1);
}
return path;
if (isWindows() && path && path.length > 1 && path.startsWith('"') && path.endsWith('"')) {
return path.substring(1, path.length - 1);
}
return path;
}
export function shellEnvironment(baseEnvironment: any): any {
const env = Object.assign({}, baseEnvironment);
const pathVariable = pathVariableName(env);
for (const tool of ['kubectl']) {
const toolPath = getToolPath(host, shell, tool);
if (toolPath) {
const toolDirectory = path.dirname(toolPath);
const currentPath = env[pathVariable];
env[pathVariable] = toolDirectory + (currentPath ? `${pathEntrySeparator()}${currentPath}` : '');
}
}
const env = Object.assign({}, baseEnvironment);
const pathVariable = pathVariableName(env);
for (const tool of ['kubectl']) {
const toolPath = getToolPath(host, shell, tool);
if (toolPath) {
const toolDirectory = path.dirname(toolPath);
const currentPath = env[pathVariable];
env[pathVariable] = toolDirectory + (currentPath ? `${pathEntrySeparator()}${currentPath}` : '');
}
}
const kubeconfig = getActiveKubeconfig();
if (kubeconfig) {
env['KUBECONFIG'] = kubeconfig;
}
const kubeconfig = getActiveKubeconfig();
if (kubeconfig) {
env['KUBECONFIG'] = kubeconfig;
}
return env;
return env;
}
function pathVariableName(env: any): string {
if (isWindows()) {
for (const v of Object.keys(env)) {
if (v.toLowerCase() === 'path') {
return v;
}
}
}
return 'PATH';
if (isWindows()) {
for (const v of Object.keys(env)) {
if (v.toLowerCase() === 'path') {
return v;
}
}
}
return 'PATH';
}
function pathEntrySeparator() {
return isWindows() ? ';' : ':';
return isWindows() ? ';' : ':';
}
function which(bin: string): string | null {
return shelljs.which(bin);
return shelljs.which(bin);
}
function cat(path: string): string {
return shelljs.cat(path);
return shelljs.cat(path);
}
function ls(path: string): string[] {
return shelljs.ls(path);
return shelljs.ls(path);
}
export function shellMessage(sr: ShellResult | undefined, invocationFailureMessage: string): string {
if (!sr) {
return invocationFailureMessage;
}
return sr.code === 0 ? sr.stdout : sr.stderr;
if (!sr) {
return invocationFailureMessage;
}
return sr.code === 0 ? sr.stdout : sr.stderr;
}

View File

@@ -2,10 +2,8 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { WizardPageBase } from '../../wizardPageBase';
import { CreateClusterWizard } from '../createClusterWizard';
import * as nls from 'vscode-nls';
@@ -347,7 +345,7 @@ export class ClusterProfilePage extends WizardPageBase<CreateClusterWizard> {
case ClusterPoolType.Spark:
return localize('bdc-create.SparkPoolDisplayName', 'Spark pool');
default:
throw 'unknown pool type';
throw new Error('unknown pool type');
}
}
@@ -364,7 +362,7 @@ export class ClusterProfilePage extends WizardPageBase<CreateClusterWizard> {
case ClusterPoolType.Spark:
return localize('bdc-create.SparkPoolDescription', 'TODO: Add description');
default:
throw 'unknown pool type';
throw new Error('unknown pool type');
}
}

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import { WizardPageBase } from '../../wizardPageBase';

View File

@@ -1,4 +1,3 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import { DacFxDataModel } from './models';
@@ -15,19 +14,16 @@ export abstract class BasePage {
/**
* This method constructs all the elements of the page.
* @returns {Promise<boolean>}
*/
public async abstract start(): Promise<boolean>;
/**
* This method is called when the user is entering the page.
* @returns {Promise<boolean>}
*/
public async abstract onPageEnter(): Promise<boolean>;
/**
* This method is called when the user is leaving the page.
* @returns {Promise<boolean>}
*/
async onPageLeave(): Promise<boolean> {
return true;
@@ -35,7 +31,6 @@ export abstract class BasePage {
/**
* Override this method to cleanup what you don't need cached in the page.
* @returns {Promise<boolean>}
*/
public async cleanup(): Promise<boolean> {
return true;
@@ -136,4 +131,3 @@ export abstract class BasePage {
return;
}
}

View File

@@ -1,4 +1,3 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.

View File

@@ -2,13 +2,9 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { RequestType, NotificationType } from 'vscode-languageclient';
/**
* @interface IMessage
*/
export interface IMessage {
jsonrpc: string;
}

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as path from 'path';
import * as crypto from 'crypto';
@@ -97,7 +96,7 @@ export function generateGuid(): string {
}
export function verifyPlatform(): Thenable<boolean> {
if (os.platform() === 'darwin' && parseFloat(os.release()) < 16.0) {
if (os.platform() === 'darwin' && parseFloat(os.release()) < 16) {
return Promise.resolve(false);
} else {
return Promise.resolve(true);

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { ErrorAction, CloseAction } from 'vscode-languageclient';
import TelemetryReporter from 'vscode-extension-telemetry';
import { PlatformInformation } from 'service-downloader/out/platform';
@@ -20,22 +18,21 @@ import { IMessage, ITelemetryEventProperties, ITelemetryEventMeasures } from './
/**
* Handle Language Service client errors
* @class LanguageClientErrorHandler
*/
export class LanguageClientErrorHandler {
/**
* Creates an instance of LanguageClientErrorHandler.
* @memberOf LanguageClientErrorHandler
*/
/**
* Creates an instance of LanguageClientErrorHandler.
* @memberOf LanguageClientErrorHandler
*/
constructor() {
}
/**
* Show an error message prompt with a link to known issues wiki page
* @memberOf LanguageClientErrorHandler
*/
/**
* Show an error message prompt with a link to known issues wiki page
* @memberOf LanguageClientErrorHandler
*/
showOnErrorPrompt(): void {
// TODO add telemetry
// Telemetry.sendTelemetryEvent('SqlToolsServiceCrash');
@@ -50,16 +47,11 @@ export class LanguageClientErrorHandler {
});
}
/**
* Callback for language service client error
*
* @param {Error} error
* @param {Message} message
* @param {number} count
* @returns {ErrorAction}
*
* @memberOf LanguageClientErrorHandler
*/
/**
* Callback for language service client error
*
* @memberOf LanguageClientErrorHandler
*/
error(error: Error, message: IMessage, count: number): ErrorAction {
this.showOnErrorPrompt();
@@ -68,13 +60,11 @@ export class LanguageClientErrorHandler {
return ErrorAction.Shutdown;
}
/**
* Callback for language service client closed
*
* @returns {CloseAction}
*
* @memberOf LanguageClientErrorHandler
*/
/**
* Callback for language service client closed
*
* @memberOf LanguageClientErrorHandler
*/
closed(): CloseAction {
this.showOnErrorPrompt();
@@ -134,16 +124,16 @@ export class Telemetry {
}
}
/**
* Disable telemetry reporting
*/
/**
* Disable telemetry reporting
*/
public static disable(): void {
this.disabled = true;
}
/**
* Initialize the telemetry reporter for use.
*/
/**
* Initialize the telemetry reporter for use.
*/
public static initialize(): void {
if (typeof this.reporter === 'undefined') {
// Check if the user has opted out of telemetry
@@ -156,9 +146,9 @@ export class Telemetry {
}
}
/**
* Send a telemetry event for an exception
*/
/**
* Send a telemetry event for an exception
*/
public static sendTelemetryEventForException(
err: any, methodName: string, extensionConfigName: string): void {
try {
@@ -181,9 +171,9 @@ export class Telemetry {
}
}
/**
* Send a telemetry event using application insights
*/
/**
* Send a telemetry event using application insights
*/
public static sendTelemetryEvent(
eventName: string,
properties?: ITelemetryEventProperties,

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import { ImportDataModel } from './models';
@@ -15,19 +14,16 @@ export abstract class BasePage {
/**
* This method constructs all the elements of the page.
* @returns {Promise<boolean>}
*/
public async abstract start(): Promise<boolean>;
/**
* This method is called when the user is entering the page.
* @returns {Promise<boolean>}
*/
public async abstract onPageEnter(): Promise<boolean>;
/**
* This method is called when the user is leaving the page.
* @returns {Promise<boolean>}
*/
async onPageLeave(): Promise<boolean> {
return true;
@@ -35,7 +31,6 @@ export abstract class BasePage {
/**
* Override this method to cleanup what you don't need cached in the page.
* @returns {Promise<boolean>}
*/
public async cleanup(): Promise<boolean> {
return true;
@@ -136,4 +131,3 @@ export abstract class BasePage {
return;
}
}

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import * as nls from 'vscode-nls';
@@ -133,7 +131,6 @@ export class SummaryPage extends ImportPage {
/**
* Gets the connection string to send to the middleware
* @returns {Promise<string>}
*/
private async getConnectionString(): Promise<string> {
let options = this.model.server.options;

View File

@@ -1,19 +1,19 @@
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "./out",
"lib": [
"es6", "es2015.promise"
],
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": false
},
"exclude": [
"node_modules"
]
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"declaration": false
},
"exclude": [
"node_modules"
]
}

View File

@@ -1,3 +1,7 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
const os = require('os');
const fs = require('fs');

View File

@@ -2,7 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import { normalize, join } from 'path';
@@ -12,10 +12,10 @@ const TEST_SETUP_COMPLETED_TEXT: string = 'Test Setup Completed';
const EXTENSION_LOADED_TEXT: string = 'Test Extension Loaded';
const ALL_EXTENSION_LOADED_TEXT: string = 'All Extensions Loaded';
var statusBarItemTimer: NodeJS.Timer;
let statusBarItemTimer: NodeJS.Timer;
export function activate(context: vscode.ExtensionContext) {
var statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
let statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
vscode.commands.registerCommand('test.setupIntegrationTest', async () => {
let extensionInstallersFolder = normalize(join(__dirname, '../extensionInstallers'));
let installers = fs.readdirSync(extensionInstallersFolder);

View File

@@ -41,8 +41,8 @@ export enum EngineType {
BigDataCluster
}
var connectionProviderMapping = {};
var authenticationTypeMapping = {};
let connectionProviderMapping = {};
let authenticationTypeMapping = {};
connectionProviderMapping[ConnectionProvider.SQLServer] = { name: 'MSSQL', displayName: 'Microsoft SQL Server' };
authenticationTypeMapping[AuthenticationType.SqlLogin] = { name: 'SqlLogin', displayName: 'SQL Login' };
@@ -80,7 +80,7 @@ export class TestServerProfile {
public get engineType(): EngineType { return this._profile.engineType; }
}
var TestingServers: TestServerProfile[] = [
let TestingServers: TestServerProfile[] = [
new TestServerProfile(
{
serverName: getConfigValue(EnvironmentVariable_STANDALONE_SERVER),
@@ -121,7 +121,7 @@ function getEnumMappingEntry(mapping: any, enumValue: any): INameDisplayNamePair
if (entry) {
return entry;
} else {
throw `Unknown enum type: ${enumValue.toString()}`;
throw new Error(`Unknown enum type: ${enumValue.toString()}`);
}
}
@@ -146,4 +146,4 @@ export async function getTestingServers(): Promise<TestServerProfile[]> {
});
await promise;
return promise;
}
}

View File

@@ -3,6 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export var context = {
export let context = {
RunTest: true
};
};

View File

@@ -18,14 +18,14 @@
"tab.bigDataClusterDescription": "Tasks and information about your SQL Server Big Data Cluster",
"title.bigDataCluster": "SQL Server Big Data Cluster",
"title.submitSparkJob": "Submit Spark Job",
"title.newSparkJob": "New Spark Job",
"title.openSparkHistory": "View Spark History",
"title.openYarnHistory": "View Yarn History",
"title.tasks": "Tasks",
"title.installPackages": "Install Packages",
"title.submitSparkJob": "Submit Spark Job",
"title.newSparkJob": "New Spark Job",
"title.openSparkHistory": "View Spark History",
"title.openYarnHistory": "View Yarn History",
"title.tasks": "Tasks",
"title.installPackages": "Install Packages",
"title.configurePython": "Configure Python for Notebooks",
"title.searchServers": "Search: Servers",
"title.clearSearchServerResult": "Search: Clear Search Server Results"
}
}

View File

@@ -10,24 +10,17 @@ import * as vscode from 'vscode';
/**
* The APIs provided by Mssql extension
*
* @export
* @interface MssqlExtensionApi
*/
export interface MssqlExtensionApi {
/**
* Gets the object explorer API that supports querying over the connections supported by this extension
*
* @returns {IMssqlObjectExplorerBrowser}
* @memberof IMssqlExtensionApi
*/
getMssqlObjectExplorerBrowser(): MssqlObjectExplorerBrowser;
/**
* Get the Cms Service APIs to communicate with CMS connections supported by this extension
*
* @returns {Promise<CmsService>}
* @memberof IMssqlExtensionApi
*/
getCmsServiceProvider(): Promise<CmsService>;
}
@@ -35,25 +28,16 @@ export interface MssqlExtensionApi {
/**
* A browser supporting actions over the object explorer connections provided by this extension.
* Currently this is the
*
* @export
* @interface MssqlObjectExplorerBrowser
*/
export interface MssqlObjectExplorerBrowser {
/**
* Gets the matching node given a context object, e.g. one from a right-click on a node in Object Explorer
*
* @param {azdata.ObjectExplorerContext} objectExplorerContext
* @returns {Promise<T>}
*/
getNode<T extends ITreeNode>(objectExplorerContext: azdata.ObjectExplorerContext): Promise<T>;
}
/**
* A tree node in the object explorer tree
*
* @export
* @interface ITreeNode
*/
export interface ITreeNode {
getNodeInfo(): azdata.NodeInfo;
@@ -63,10 +47,6 @@ export interface ITreeNode {
/**
* A HDFS file node. This is a leaf node in the object explorer tree, and its contents
* can be queried
*
* @export
* @interface IFileNode
* @extends {ITreeNode}
*/
export interface IFileNode extends ITreeNode {
getFileContentsAsString(maxBytes?: number): Promise<string>;
@@ -79,64 +59,31 @@ export interface IFileNode extends ITreeNode {
export interface CmsService {
/**
* Connects to or creates a Central management Server
*
* @param {string} name
* @param {string} description
* @param {azdata.ConnectionInfo} connectiondetails
* @param {string} ownerUri
* @returns {Thenable<azdata.ListRegisteredServersResult>}
*/
createCmsServer(name: string, description:string, connectiondetails: azdata.ConnectionInfo, ownerUri: string): Thenable<ListRegisteredServersResult>;
/**
* gets all Registered Servers inside a CMS on a particular level
*
* @param {string} ownerUri
* @param {string} relativePath
* @returns {Thenable<azdata.ListRegisteredServersResult>}
*/
getRegisteredServers(ownerUri: string, relativePath: string): Thenable<ListRegisteredServersResult>;
/**
* Adds a Registered Server inside a CMS on a particular level
*
* @param {string} ownerUri
* @param {string} relativePath
* @param {string} registeredServerName
* @param {string} registeredServerDescription
* @param {azdata.ConnectionInfo} connectiondetails
* @returns {Thenable<boolean>>}
*/
addRegisteredServer (ownerUri: string, relativePath: string, registeredServerName: string, registeredServerDescription:string, connectionDetails:azdata.ConnectionInfo): Thenable<boolean>;
/**
* Removes a Registered Server inside a CMS on a particular level
*
* @param {string} ownerUri
* @param {string} relativePath
* @param {string} registeredServerName
* @returns {Thenable<boolean>}
*/
removeRegisteredServer (ownerUri: string, relativePath: string, registeredServerName: string): Thenable<boolean>;
/**
* Adds a Server Group inside a CMS on a particular level
*
* @param {string} ownerUri
* @param {string} relativePath
* @param {string} groupName
* @param {string} groupDescription
* @param {azdata.ConnectionInfo} connectiondetails
*/
addServerGroup (ownerUri: string, relativePath: string, groupName: string, groupDescription:string): Thenable<boolean>;
/**
* Removes a Server Group inside a CMS on a particular level
*
* @param {string} ownerUri
* @param {string} relativePath
* @param {string} groupName
* @param {string} groupDescription
*/
removeServerGroup (ownerUri: string, relativePath: string, groupName: string): Thenable<boolean>;
}
@@ -162,4 +109,3 @@ export interface ListRegisteredServersResult {
registeredServersList: Array<RegisteredServerResult>;
registeredServerGroups: Array<RegisteredServerGroup>;
}

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
@@ -13,7 +11,6 @@ import * as azdata from 'azdata';
* this API from our code
*
* @export
* @class ApiWrapper
*/
export class ApiWrapper {
// Data APIs

View File

@@ -20,9 +20,9 @@ export class CmsService {
this.appContext.registerService<CmsService>(constants.CmsService, this);
}
createCmsServer(name: string, description:string, connectiondetails: azdata.ConnectionInfo, ownerUri: string): Thenable<ListRegisteredServersResult> {
createCmsServer(name: string, description: string, connectiondetails: azdata.ConnectionInfo, ownerUri: string): Thenable<ListRegisteredServersResult> {
let connectparams: ConnectParams = { ownerUri: ownerUri, connection: connectiondetails };
let cmsparams: contracts.CreateCentralManagementServerParams = { registeredServerName: name, registeredServerDescription: description, connectParams: connectparams};
let cmsparams: contracts.CreateCentralManagementServerParams = { registeredServerName: name, registeredServerDescription: description, connectParams: connectparams };
return this.client.sendRequest(contracts.CreateCentralManagementServerRequest.type, cmsparams).then(
r => {
@@ -35,7 +35,7 @@ export class CmsService {
);
}
getRegisteredServers(ownerUri: string, relativePath: string): Thenable<ListRegisteredServersResult> {
getRegisteredServers(ownerUri: string, relativePath: string): Thenable<ListRegisteredServersResult> {
let params: contracts.ListRegisteredServersParams = { parentOwnerUri: ownerUri, relativePath: relativePath };
return this.client.sendRequest(contracts.ListRegisteredServersRequest.type, params).then(
r => {
@@ -48,7 +48,7 @@ export class CmsService {
);
}
addRegisteredServer (ownerUri: string, relativePath: string, registeredServerName: string, registeredServerDescription:string, connectionDetails:azdata.ConnectionInfo): Thenable<boolean> {
addRegisteredServer(ownerUri: string, relativePath: string, registeredServerName: string, registeredServerDescription: string, connectionDetails: azdata.ConnectionInfo): Thenable<boolean> {
let params: contracts.AddRegisteredServerParams = { parentOwnerUri: ownerUri, relativePath: relativePath, registeredServerName: registeredServerName, registeredServerDescription: registeredServerDescription, registeredServerConnectionDetails: connectionDetails };
return this.client.sendRequest(contracts.AddRegisteredServerRequest.type, params).then(
r => {
@@ -61,7 +61,7 @@ export class CmsService {
);
}
removeRegisteredServer (ownerUri: string, relativePath: string, registeredServerName: string): Thenable<boolean> {
removeRegisteredServer(ownerUri: string, relativePath: string, registeredServerName: string): Thenable<boolean> {
let params: contracts.RemoveRegisteredServerParams = { parentOwnerUri: ownerUri, relativePath: relativePath, registeredServerName: registeredServerName };
return this.client.sendRequest(contracts.RemoveRegisteredServerRequest.type, params).then(
r => {
@@ -74,7 +74,7 @@ export class CmsService {
);
}
addServerGroup (ownerUri: string, relativePath: string, groupName: string, groupDescription:string): Thenable<boolean> {
addServerGroup(ownerUri: string, relativePath: string, groupName: string, groupDescription: string): Thenable<boolean> {
let params: contracts.AddServerGroupParams = { parentOwnerUri: ownerUri, relativePath: relativePath, groupName: groupName, groupDescription: groupDescription };
return this.client.sendRequest(contracts.AddServerGroupRequest.type, params).then(
r => {
@@ -87,7 +87,7 @@ export class CmsService {
);
}
removeServerGroup (ownerUri: string, relativePath: string, groupName: string): Thenable<boolean> {
removeServerGroup(ownerUri: string, relativePath: string, groupName: string): Thenable<boolean> {
let params: contracts.RemoveServerGroupParams = { parentOwnerUri: ownerUri, relativePath: relativePath, groupName: groupName };
return this.client.sendRequest(contracts.RemoveServerGroupRequest.type, params).then(
r => {

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { NotificationType, RequestType } from 'vscode-languageclient';
import { ITelemetryEventProperties, ITelemetryEventMeasures } from './telemetry';
@@ -377,37 +376,37 @@ export namespace GenerateDeployPlanRequest {
export interface CreateCentralManagementServerParams {
registeredServerName: string;
registeredServerDescription : string;
connectParams: ConnectParams;
registeredServerName: string;
registeredServerDescription: string;
connectParams: ConnectParams;
}
export interface ListRegisteredServersParams extends RegisteredServerParamsBase {
// same as base
// same as base
}
export interface AddRegisteredServerParams extends RegisteredServerParamsBase {
registeredServerName: string;
registeredServerDescription : string;
registeredServerConnectionDetails: azdata.ConnectionInfo;
registeredServerName: string;
registeredServerDescription: string;
registeredServerConnectionDetails: azdata.ConnectionInfo;
}
export interface RemoveRegisteredServerParams extends RegisteredServerParamsBase {
registeredServerName: string;
registeredServerName: string;
}
export interface AddServerGroupParams extends RegisteredServerParamsBase {
groupName: string;
groupName: string;
groupDescription: string;
}
export interface RemoveServerGroupParams extends RegisteredServerParamsBase {
groupName: string;
groupName: string;
}
export interface RegisteredServerParamsBase {
parentOwnerUri: string;
relativePath: string;
parentOwnerUri: string;
relativePath: string;
}
export namespace CreateCentralManagementServerRequest {
@@ -442,7 +441,7 @@ export interface SchemaCompareParams {
taskExecutionMode: TaskExecutionMode;
}
export interface SchemaCompareGenerateScriptParams {
export interface SchemaCompareGenerateScriptParams {
operationId: string;
targetDatabaseName: string;
scriptFilePath: string;
@@ -453,7 +452,7 @@ export namespace SchemaCompareRequest {
export const type = new RequestType<SchemaCompareParams, azdata.SchemaCompareResult, void, void>('schemaCompare/compare');
}
export namespace SchemaCompareGenerateScriptRequest {
export namespace SchemaCompareGenerateScriptRequest {
export const type = new RequestType<SchemaCompareGenerateScriptParams, azdata.ResultStatus, void, void>('schemaCompare/generateScript');
}
// ------------------------------- <Schema Compare> -----------------------------

View File

@@ -1,3 +1,7 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export default require('error-ex')('EscapeException');

View File

@@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { SqlOpsDataClient, SqlOpsFeature } from 'dataprotocol-client';
import { ClientCapabilities, StaticFeature, RPCMessageType, ServerCapabilities } from 'vscode-languageclient';
@@ -12,7 +11,6 @@ import * as contracts from './contracts';
import * as azdata from 'azdata';
import * as Utils from './utils';
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
import { ConnectParams } from 'dataprotocol-client/lib/protocol';
export class TelemetryFeature implements StaticFeature {
@@ -170,7 +168,7 @@ export class SchemaCompareServicesFeature extends SqlOpsFeature<undefined> {
let self = this;
let schemaCompare = (sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.SchemaCompareResult> => {
let params: contracts.SchemaCompareParams = {sourceEndpointInfo: sourceEndpointInfo, targetEndpointInfo: targetEndpointInfo, taskExecutionMode: taskExecutionMode};
let params: contracts.SchemaCompareParams = { sourceEndpointInfo: sourceEndpointInfo, targetEndpointInfo: targetEndpointInfo, taskExecutionMode: taskExecutionMode };
return client.sendRequest(contracts.SchemaCompareRequest.type, params).then(
r => {
return r;
@@ -182,8 +180,8 @@ export class SchemaCompareServicesFeature extends SqlOpsFeature<undefined> {
);
};
let schemaCompareGenerateScript = (operationId: string, targetDatabaseName: string, scriptFilePath: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.DacFxResult> => {
let params: contracts.SchemaCompareGenerateScriptParams = {operationId: operationId, targetDatabaseName: targetDatabaseName, scriptFilePath: scriptFilePath, taskExecutionMode: taskExecutionMode};
let schemaCompareGenerateScript = (operationId: string, targetDatabaseName: string, scriptFilePath: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.DacFxResult> => {
let params: contracts.SchemaCompareGenerateScriptParams = { operationId: operationId, targetDatabaseName: targetDatabaseName, scriptFilePath: scriptFilePath, taskExecutionMode: taskExecutionMode };
return client.sendRequest(contracts.SchemaCompareGenerateScriptRequest.type, params).then(
r => {
return r;

View File

@@ -24,4 +24,4 @@ export function sparkJobSubmissionYarnUIMessage(yarnUIURL: string): string { ret
export function sparkJobSubmissionSparkHistoryLinkMessage(sparkHistoryLink: string): string { return localize('sparkJobSubmission_SparkHistoryLinkMessage', 'Spark History Url: {0} ', sparkHistoryLink); }
export function sparkJobSubmissionGetApplicationIdFailed(err: string): string { return localize('sparkJobSubmission_GetApplicationIdFailed', 'Get Application Id Failed. {0}', err); }
export function sparkJobSubmissionLocalFileNotExisted(path: string): string { return localize('sparkJobSubmission_LocalFileNotExisted', 'Local file {0} does not existed. ', path); }
export const sparkJobSubmissionNoSqlBigDataClusterFound = localize('sparkJobSubmission_NoSqlBigDataClusterFound','No Sql Server Big Data Cluster found.');
export const sparkJobSubmissionNoSqlBigDataClusterFound = localize('sparkJobSubmission_NoSqlBigDataClusterFound', 'No Sql Server Big Data Cluster found.');

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as nls from 'vscode-nls';
@@ -74,7 +73,9 @@ export abstract class Command extends vscode.Disposable {
}
dispose(): void {
this.disposable && this.disposable.dispose();
if (this.disposable) {
this.disposable.dispose();
}
}
protected get apiWrapper(): ApiWrapper {

View File

@@ -69,8 +69,8 @@ export class SqlClusterConnection {
return FileSourceFactory.instance.createHdfsFileSource(options);
}
public updatePassword(password : string): void{
if(password){
public updatePassword(password: string): void {
if (password) {
this._password = password;
}
}

View File

@@ -153,7 +153,7 @@ export class HdfsFileSource implements IFileSource {
reject(error);
} else {
let hdfsFiles: IFile[] = files.map(file => {
let hdfsFile = <IHdfsFileStatus> file;
let hdfsFile = <IHdfsFileStatus>file;
return new File(File.createPath(path, hdfsFile.pathSuffix), hdfsFile.type === 'DIRECTORY');
});
resolve(hdfsFiles);
@@ -195,9 +195,9 @@ export class HdfsFileSource implements IFileSource {
error = <HdfsError>err;
if (error.message.includes('Stream exceeded specified max')) {
// We have data > maxbytes, show we're truncating
let previewNote: string = '#################################################################################################################### \r\n'+
'########################### '+ localize('maxSizeNotice', "NOTICE: This file has been truncated at {0} for preview. ", bytes(maxBytes)) + '############################### \r\n' +
'#################################################################################################################### \r\n';
let previewNote: string = '#################################################################################################################### \r\n' +
'########################### ' + localize('maxSizeNotice', "NOTICE: This file has been truncated at {0} for preview. ", bytes(maxBytes)) + '############################### \r\n' +
'#################################################################################################################### \r\n';
data.splice(0, 0, Buffer.from(previewNote, 'utf-8'));
vscode.window.showWarningMessage(localize('maxSizeReached', "The file has been truncated at {0} for preview.", bytes(maxBytes)));
resolve(Buffer.concat(data));
@@ -236,15 +236,15 @@ export class HdfsFileSource implements IFileSource {
lineReader.close();
}
})
.on('error', (err) => {
error = <HdfsError>err;
reject(error);
})
.on('close', () => {
if (!error) {
resolve(Buffer.from(lineData.join(os.EOL)));
}
});
.on('error', (err) => {
error = <HdfsError>err;
reject(error);
})
.on('close', () => {
if (!error) {
resolve(Buffer.from(lineData.join(os.EOL)));
}
});
});
}

View File

@@ -345,7 +345,7 @@ export class ErrorNode extends TreeNode {
public static create(message: string, parent: TreeNode, errorCode?: number): ErrorNode {
let node = new ErrorNode(message);
node.parent = parent;
if(errorCode){
if (errorCode) {
node.errorStatusCode = errorCode;
}
return node;

View File

@@ -97,7 +97,7 @@ export class MssqlObjectExplorerNodeProvider extends ProviderBase implements azd
}
private hasExpansionError(children: TreeNode[]): boolean {
if(children.find(c => c.errorStatusCode > 0)){
if (children.find(c => c.errorStatusCode > 0)) {
return true;
}
return false;

View File

@@ -1,5 +1,3 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.

View File

@@ -68,7 +68,7 @@ export abstract class TreeNode implements ITreeNode {
if (children) {
for (let child of children) {
if (filter && filter(child)) {
let childNode = await this.findNode(child, condition, filter, expandIfNeeded);
let childNode = await this.findNode(child, condition, filter, expandIfNeeded);
if (childNode) {
return childNode;
}
@@ -78,7 +78,7 @@ export abstract class TreeNode implements ITreeNode {
return undefined;
}
public updateFileSource(connection: SqlClusterConnection): void{
public updateFileSource(connection: SqlClusterConnection): void {
this.fileSource = connection.createHdfsFileSource();
}
/**

View File

@@ -10,7 +10,6 @@ import * as azdata from 'azdata';
* A tree node in the object explorer tree
*
* @export
* @interface ITreeNode
*/
export interface ITreeNode {
getNodeInfo(): azdata.NodeInfo;
@@ -22,9 +21,8 @@ export interface ITreeNode {
* can be queried
*
* @export
* @interface IFileNode
* @extends {ITreeNode}
*/
export interface IFileNode extends ITreeNode {
getFileContentsAsString(maxBytes?: number): Promise<string>;
}
}

View File

@@ -1,8 +1,6 @@
// This code is originally from https://github.com/harrisiirak/webhdfs
// License: https://github.com/harrisiirak/webhdfs/blob/master/LICENSE
'use strict';
import * as url from 'url';
import * as fs from 'fs';
import * as querystring from 'querystring';
@@ -53,10 +51,8 @@ export class WebHDFS {
/**
* Generate WebHDFS REST API endpoint URL for given operation
*
* @param {string} operation WebHDFS operation name
* @param {string} path
* @param {object} params
* @returns {string} WebHDFS REST API endpoint URL
* @param operation WebHDFS operation name
* @returns WebHDFS REST API endpoint URL
*/
private getOperationEndpoint(operation: string, path: string, params?: object): string {
let endpoint = this._url;
@@ -73,8 +69,8 @@ export class WebHDFS {
/**
* Gets localized status message for given status code
*
* @param {number} statusCode Http status code
* @returns {string} status message
* @param statusCode Http status code
* @returns status message
*/
private toStatusMessage(statusCode: number): string {
let statusMessage: string = undefined;
@@ -93,9 +89,9 @@ export class WebHDFS {
/**
* Gets status message from response
*
* @param {request.Response} response response object
* @param {boolean} strict If set true then RemoteException must be present in the body
* @returns {string} Error message interpreted by status code
* @param response response object
* @param strict If set true then RemoteException must be present in the body
* @returns Error message interpreted by status code
*/
private getStatusMessage(response: request.Response): string {
if (!response) { return undefined; }
@@ -107,8 +103,8 @@ export class WebHDFS {
/**
* Gets remote exception message from response body
*
* @param {any} responseBody response body
* @returns {string} Error message interpreted by status code
* @param responseBody response body
* @returns Error message interpreted by status code
*/
private getRemoteExceptionMessage(responseBody: any): string {
if (!responseBody) { return undefined; }
@@ -128,10 +124,10 @@ export class WebHDFS {
/**
* Generates error message descriptive as much as possible
*
* @param {string} statusMessage status message
* @param {string} [remoteExceptionMessage] remote exception message
* @param {any} [error] error
* @returns {string} error message
* @param statusMessage status message
* @param [remoteExceptionMessage] remote exception message
* @param [error] error
* @returns error message
*/
private getErrorMessage(statusMessage: string, remoteExceptionMessage?: string, error?: any): string {
statusMessage = statusMessage === '' ? undefined : statusMessage;
@@ -140,16 +136,16 @@ export class WebHDFS {
return statusMessage && remoteExceptionMessage ?
`${statusMessage} (${remoteExceptionMessage})` :
statusMessage || remoteExceptionMessage || messageFromError ||
localize('webhdfs.unknownError', 'Unknown Error');
localize('webhdfs.unknownError', 'Unknown Error');
}
/**
* Parse error state from response and return valid Error object
*
* @param {request.Response} response response object
* @param {any} [responseBody] response body
* @param {any} [error] error
* @returns {HdfsError} HdfsError object
* @param response response object
* @param [responseBody] response body
* @param [error] error
* @returns HdfsError object
*/
private parseError(response: request.Response, responseBody?: any, error?: any): HdfsError {
let statusMessage: string = this.getStatusMessage(response);
@@ -165,8 +161,8 @@ export class WebHDFS {
/**
* Check if response is redirect
*
* @param {request.Response} response response object
* @returns {boolean} if response is redirect
* @param response response object
* @returns if response is redirect
*/
private isRedirect(response: request.Response): boolean {
return [301, 307].indexOf(response.statusCode) !== -1 &&
@@ -176,8 +172,8 @@ export class WebHDFS {
/**
* Check if response is successful
*
* @param {request.Response} response response object
* @returns {boolean} if response is successful
* @param response response object
* @returns if response is successful
*/
private isSuccess(response: request.Response): boolean {
return [200, 201].indexOf(response.statusCode) !== -1;
@@ -186,8 +182,8 @@ export class WebHDFS {
/**
* Check if response is error
*
* @param {request.Response} response response object
* @returns {boolean} if response is error
* @param response response object
* @returns if response is error
*/
private isError(response: request.Response): boolean {
return [400, 401, 402, 403, 404, 500].indexOf(response.statusCode) !== -1;
@@ -196,10 +192,8 @@ export class WebHDFS {
/**
* Send a request to WebHDFS REST API
*
* @param {string} method HTTP method
* @param {string} url
* @param {object} opts Options for request
* @param {(error: HdfsError, response: request.Response) => void} callback
* @param method HTTP method
* @param opts Options for request
* @returns void
*/
private sendRequest(method: string, url: string, opts: object,
@@ -234,10 +228,6 @@ export class WebHDFS {
/**
* Change file permissions
*
* @param {string} path
* @param {string} mode
* @param {(error: HdfsError) => void} callback
* @returns void
*/
public chmod(path: string, mode: string, callback: (error: HdfsError) => void): void {
@@ -253,10 +243,8 @@ export class WebHDFS {
/**
* Change file owner
*
* @param {string} path
* @param {string} userId User name
* @param {string} groupId Group name
* @param {(error: HdfsError) => void} callback
* @param userId User name
* @param groupId Group name
* @returns void
*/
public chown(path: string, userId: string, groupId: string, callback: (error: HdfsError) => void): void {
@@ -279,8 +267,6 @@ export class WebHDFS {
/**
* Read directory contents
*
* @param {string} path
* @param {(error: HdfsError, files: any[]) => void)} callback
* @returns void
*/
public readdir(path: string, callback: (error: HdfsError, files: any[]) => void): void {
@@ -305,10 +291,6 @@ export class WebHDFS {
/**
* Make new directory
*
* @param {string} path
* @param {string} [permission=0755]
* @param {(error: HdfsError) => void} callback
* @returns void
*/
public mkdir(path: string, permission: string = '0755', callback: (error: HdfsError) => void): void {
@@ -327,10 +309,6 @@ export class WebHDFS {
/**
* Rename path
*
* @param {string} path
* @param {string} destination
* @param {(error: HdfsError) => void} callback
* @returns void
*/
public rename(path: string, destination: string, callback: (error: HdfsError) => void): void {
@@ -350,9 +328,6 @@ export class WebHDFS {
/**
* Get file status for given path
*
* @param {string} path
* @param {(error: HdfsError, fileStatus: any) => void} callback
* @returns void
*/
public stat(path: string, callback: (error: HdfsError, fileStatus: any) => void): void {
@@ -376,8 +351,6 @@ export class WebHDFS {
* Wraps stat method
*
* @see WebHDFS.stat
* @param {string} path
* @param {(error: HdfsError, exists: boolean) => void} callback
* @returns void
*/
public exists(path: string, callback: (error: HdfsError, exists: boolean) => void): void {
@@ -392,12 +365,7 @@ export class WebHDFS {
/**
* Write data to the file
*
* @param {string} path
* @param {string | Buffer} data
* @param {boolean} append If set to true then append data to the file
* @param {object} opts
* @param {(error: HdfsError) => void} callback
* @returns {fs.WriteStream}
* @param append If set to true then append data to the file
*/
public writeFile(path: string, data: string | Buffer, append: boolean, opts: object,
callback: (error: HdfsError) => void): fs.WriteStream {
@@ -427,11 +395,6 @@ export class WebHDFS {
* Append data to the file
*
* @see writeFile
* @param {string} path
* @param {string | Buffer} data
* @param {object} opts
* @param {(error: HdfsError) => void} callback
* @returns {fs.WriteStream}
*/
public appendFile(path: string, data: string | Buffer, opts: object, callback: (error: HdfsError) => void): fs.WriteStream {
return this.writeFile(path, data, true, opts, callback);
@@ -442,8 +405,6 @@ export class WebHDFS {
*
* @fires Request#data
* @fires WebHDFS#finish
* @param {path} path
* @param {(error: HdfsError, buffer: Buffer) => void} callback
* @returns void
*/
public readFile(path: string, callback: (error: HdfsError, buffer: Buffer) => void): void {
@@ -475,10 +436,7 @@ export class WebHDFS {
* Create writable stream for given path
*
* @fires WebHDFS#finish
* @param {string} path
* @param {boolean} [append] If set to true then append data to the file
* @param {object} [opts]
* @returns {fs.WriteStream}
* @param [append] If set to true then append data to the file
*
* @example
* let hdfs = WebHDFS.createClient();
@@ -593,9 +551,6 @@ export class WebHDFS {
*
* @fires Request#data
* @fires WebHDFS#finish
* @param {string} path
* @param {object} [opts]
* @returns {fs.ReadStream}
*
* @example
* let hdfs = WebHDFS.createClient();
@@ -677,10 +632,6 @@ export class WebHDFS {
/**
* Create symbolic link to the destination path
*
* @param {string} src
* @param {string} destination
* @param {boolean} [createParent=false]
* @param {(error: HdfsError) => void} callback
* @returns void
*/
public symlink(src: string, destination: string, createParent: boolean = false, callback: (error: HdfsError) => void): void {
@@ -702,9 +653,6 @@ export class WebHDFS {
/**
* Unlink path
*
* @param {string} path
* @param {boolean} [recursive=false]
* @param {(error: any) => void} callback
* @returns void
*/
public unlink(path: string, recursive: boolean = false, callback: (error: HdfsError) => void): void {
@@ -720,9 +668,6 @@ export class WebHDFS {
/**
* @alias WebHDFS.unlink
* @param {string} path
* @param {boolean} [recursive=false]
* @param {(error: any) => void} callback
* @returns void
*/
public rmdir(path: string, recursive: boolean = false, callback: (error: HdfsError) => void): void {

View File

@@ -11,7 +11,7 @@ export default class ProgressIndicator {
constructor() {
this._statusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
}
}
private _tasks: string[] = [];
public beginTask(task: string): void {

Some files were not shown because too many files have changed in this diff Show More