From 5c63f7bdb5e9f3ca01d0ff6e877e7c6b60f363ca Mon Sep 17 00:00:00 2001 From: Kevin Cunnane Date: Fri, 19 Jul 2019 16:11:57 -0700 Subject: [PATCH] Support installing SQL Server Notebook extension (#6432) This adds SQL Server Notebook as a built-in extension by pulling it from blob storage. It also adds support in mssql extension for reading the contribution points from other extensions. This will contribute troubleshooting and other books as widgets. In this commit: - Bundle the extension in the build - Bundle in sql.sh / sql.bat so it appears in local testing - Avoid installing in Stable. Should only appear in Dev/Insiders builds - Extensions with `notebook.books` contribution point will be discovered & their books available in MSSQL Coming later: - Integrate this with Maddy's work to show a Notebooks widget in the SQL Server big data cluster UI - When clause isn't supported yet for filtering. Will be done as we refactor towards more books for different server types --- build/builtInExtensions-insiders.json | 7 + build/lib/builtInExtensions.js | 4 +- build/lib/extensions.js | 8 +- build/lib/extensions.ts | 12 +- .../mssql/src/dashboard/bookExtensions.ts | 124 ++++++++++++++ .../mssql/src/dashboard/serviceEndpoints.ts | 104 ++++++++++++ extensions/mssql/src/main.ts | 152 +++++------------- extensions/mssql/src/util/arrays.ts | 22 +++ extensions/mssql/src/util/dispose.ts | 42 +++++ scripts/sql.bat | 3 + scripts/sql.sh | 3 + .../node/extensionManagementService.ts | 4 +- .../cachedExtensionScanner.ts | 5 +- 13 files changed, 365 insertions(+), 125 deletions(-) create mode 100644 build/builtInExtensions-insiders.json create mode 100644 extensions/mssql/src/dashboard/bookExtensions.ts create mode 100644 extensions/mssql/src/dashboard/serviceEndpoints.ts create mode 100644 extensions/mssql/src/util/arrays.ts create mode 100644 extensions/mssql/src/util/dispose.ts diff --git a/build/builtInExtensions-insiders.json b/build/builtInExtensions-insiders.json new file mode 100644 index 0000000000..fc6bc1f24c --- /dev/null +++ b/build/builtInExtensions-insiders.json @@ -0,0 +1,7 @@ +[ + { + "name": "Microsoft.sqlservernotebook", + "version": "0.1.0", + "repo": "https://github.com/Microsoft/azuredatastudio" + } +] diff --git a/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js index 72fa076f81..ae8fa2735d 100644 --- a/build/lib/builtInExtensions.js +++ b/build/lib/builtInExtensions.js @@ -18,7 +18,9 @@ const fancyLog = require('fancy-log'); const ansiColors = require('ansi-colors'); const root = path.dirname(path.dirname(__dirname)); -const builtInExtensions = require('../builtInExtensions.json'); +// {{SQL CARBON EDIT}} +const builtInExtensions = require('../builtInExtensions-insiders.json'); +// {{SQL CARBON EDIT}} - END const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json'); function getExtensionPath(extension) { diff --git a/build/lib/extensions.js b/build/lib/extensions.js index a97c65b0b4..dd09148894 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -151,8 +151,9 @@ const baseHeaders = { 'X-Market-User-Id': '291C1CD0-051A-4123-9B4B-30D60EF52EE2', }; function fromMarketplace(extensionName, version, metadata) { - const [publisher, name] = extensionName.split('.'); - const url = `https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher}/vsextensions/${name}/${version}/vspackage`; + // {{SQL CARBON EDIT}} + const [, name] = extensionName.split('.'); + const url = `https://sqlopsextensions.blob.core.windows.net/extensions/${name}/${name}-${version}.vsix`; fancyLog('Downloading extension:', ansiColors.yellow(`${extensionName}@${version}`), '...'); const options = { base: url, @@ -199,7 +200,8 @@ const sqlBuiltInExtensions = [ if (process.env['VSCODE_QUALITY'] === 'stable') { sqlBuiltInExtensions.push('resource-deployment'); } -const builtInExtensions = require('../builtInExtensions.json'); +const builtInExtensions = process.env['VSCODE_QUALITY'] === 'stable' ? require('../builtInExtensions.json') : require('../builtInExtensions-insiders.json'); +// {{SQL CARBON EDIT}} - End function packageLocalExtensionsStream() { const localExtensionDescriptions = glob.sync('extensions/*/package.json') .map(manifestPath => { diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index e1c4c77dac..8314839266 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -179,8 +179,9 @@ const baseHeaders = { }; export function fromMarketplace(extensionName: string, version: string, metadata: any): Stream { - const [publisher, name] = extensionName.split('.'); - const url = `https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher}/vsextensions/${name}/${version}/vspackage`; + // {{SQL CARBON EDIT}} + const [, name] = extensionName.split('.'); + const url = `https://sqlopsextensions.blob.core.windows.net/extensions/${name}/${name}-${version}.vsix`; fancyLog('Downloading extension:', ansiColors.yellow(`${extensionName}@${version}`), '...'); @@ -235,8 +236,6 @@ if (process.env['VSCODE_QUALITY'] === 'stable') { } -// {{SQL CARBON EDIT}} - End - interface IBuiltInExtension { name: string; version: string; @@ -244,7 +243,10 @@ interface IBuiltInExtension { metadata: any; } -const builtInExtensions: IBuiltInExtension[] = require('../builtInExtensions.json'); +const builtInExtensions: IBuiltInExtension[] = process.env['VSCODE_QUALITY'] === 'stable' ? require('../builtInExtensions.json') : require('../builtInExtensions-insiders.json'); + +// {{SQL CARBON EDIT}} - End + export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream { const localExtensionDescriptions = (glob.sync('extensions/*/package.json')) diff --git a/extensions/mssql/src/dashboard/bookExtensions.ts b/extensions/mssql/src/dashboard/bookExtensions.ts new file mode 100644 index 0000000000..1926e584f7 --- /dev/null +++ b/extensions/mssql/src/dashboard/bookExtensions.ts @@ -0,0 +1,124 @@ +/*--------------------------------------------------------------------------------------------- + * 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 path from 'path'; +import * as arrays from '../util/arrays'; +import { Disposable } from '../util/dispose'; + +const resolveExtensionResource = (extension: vscode.Extension, resourcePath: string): vscode.Uri => { + return vscode.Uri.file(path.join(extension.extensionPath, resourcePath)); +}; + +const resolveBookResources = (extension: vscode.Extension, books: BookContribution | BookContribution[]): BookContribution[] => { + if (!books) { + return []; + } + if (!Array.isArray(books)) { + books = [books]; + } + let result = books.map(book => { + try { + book.path = resolveExtensionResource(extension, book.path).fsPath; + } catch (e) { + // noop + } + return book; + }); + return result; +}; + +export interface BookContribution { + name: string; + path: string; + when?: string; +} + +export namespace BookContributions { + + export function merge(a: BookContribution[], b: BookContribution[]): BookContribution[] { + if (!a) { + return b; + } else if (!b) { + return a; + } + return a.concat(b); + } + + export function equal(a: BookContribution, b: BookContribution): boolean { + return (a.name === b.name) + && (a.path === b.path) + && (a.when === b.when); + } + + export function fromExtension( + extension: vscode.Extension + ): BookContribution[] { + const contributions = extension.packageJSON && extension.packageJSON.contributes; + if (!contributions) { + return []; + } + + return getContributedBooks(contributions, extension); + } + + + function getContributedBooks( + contributes: any, + extension: vscode.Extension + ): BookContribution[] { + if (contributes['notebook.books']) { + return resolveBookResources(extension, contributes['notebook.books']); + } + return []; + } +} + +export interface BookContributionProvider { + readonly extensionPath: string; + readonly contributions: BookContribution[]; + readonly onContributionsChanged: vscode.Event; + + dispose(): void; +} + +class AzdataExtensionBookContributionProvider extends Disposable implements BookContributionProvider { + private _contributions?: BookContribution[]; + + public constructor( + public readonly extensionPath: string, + ) { + super(); + + vscode.extensions.onDidChange(() => { + const currentContributions = this.getCurrentContributions(); + const existingContributions = this._contributions || undefined; + if (!arrays.equals(existingContributions, currentContributions, BookContributions.equal)) { + this._contributions = currentContributions; + this._onContributionsChanged.fire(this); + } + }, undefined, this._disposables); + } + + private readonly _onContributionsChanged = this._register(new vscode.EventEmitter()); + public readonly onContributionsChanged = this._onContributionsChanged.event; + + public get contributions(): BookContribution[] { + if (!this._contributions) { + this._contributions = this.getCurrentContributions(); + } + return this._contributions; + } + + private getCurrentContributions(): BookContribution[] { + return vscode.extensions.all + .map(BookContributions.fromExtension) + .reduce(BookContributions.merge, []); + } +} + +export function getBookExtensionContributions(context: vscode.ExtensionContext): BookContributionProvider { + return new AzdataExtensionBookContributionProvider(context.extensionPath); +} \ No newline at end of file diff --git a/extensions/mssql/src/dashboard/serviceEndpoints.ts b/extensions/mssql/src/dashboard/serviceEndpoints.ts new file mode 100644 index 0000000000..eebf0f5c60 --- /dev/null +++ b/extensions/mssql/src/dashboard/serviceEndpoints.ts @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * 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 azdata from 'azdata'; +import * as nls from 'vscode-nls'; +const localize = nls.loadMessageBundle(); + +import * as Utils from '../utils'; + +export function registerServiceEndpoints(context: vscode.ExtensionContext): void { + azdata.ui.registerModelViewProvider('bdc-endpoints', async (view) => { + + const endpointsArray: Array = Object.assign([], view.serverInfo.options['clusterEndpoints']); + endpointsArray.forEach(endpointInfo => { + endpointInfo.isHyperlink = true; + endpointInfo.hyperlink = 'https://' + endpointInfo.ipAddress + ':' + endpointInfo.port; + + }); + if (endpointsArray.length > 0) { + const managementProxyEp = endpointsArray.find(e => e.serviceName === 'management-proxy' || e.serviceName === 'mgmtproxy'); + if (managementProxyEp) { + endpointsArray.push(getCustomEndpoint(managementProxyEp, localize("grafana", "Metrics Dashboard"), '/grafana/d/wZx3OUdmz')); + endpointsArray.push(getCustomEndpoint(managementProxyEp, localize("kibana", "Log Search Dashboard"), '/kibana/app/kibana#/discover')); + } + + const gatewayEp = endpointsArray.find(e => e.serviceName === 'gateway'); + if (gatewayEp) { + endpointsArray.push(getCustomEndpoint(gatewayEp, localize("sparkHostory", "Spark Job Monitoring"), '/gateway/default/sparkhistory')); + endpointsArray.push(getCustomEndpoint(gatewayEp, localize("yarnHistory", "Spark Resource Management"), '/gateway/default/yarn')); + } + + const container = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%', alignItems: 'left' }).component(); + endpointsArray.forEach(endpointInfo => { + const endPointRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component(); + const nameCell = view.modelBuilder.text().withProperties({ value: getFriendlyEndpointNames(endpointInfo.serviceName) }).component(); + endPointRow.addItem(nameCell, { CSSStyles: { 'width': '35%', 'font-weight': '600', 'user-select': 'text' } }); + if (endpointInfo.isHyperlink) { + const linkCell = view.modelBuilder.hyperlink().withProperties({ label: endpointInfo.hyperlink, url: endpointInfo.hyperlink }).component(); + endPointRow.addItem(linkCell, { CSSStyles: { 'width': '62%', 'color': '#0078d4', 'text-decoration': 'underline', 'padding-top': '10px' } }); + } + else { + const endpointCell = view.modelBuilder.text().withProperties({ value: endpointInfo.ipAddress + ':' + endpointInfo.port }).component(); + endPointRow.addItem(endpointCell, { CSSStyles: { 'width': '62%', 'user-select': 'text' } }); + } + const copyValueCell = view.modelBuilder.button().component(); + copyValueCell.iconPath = { light: context.asAbsolutePath('resources/light/copy.png'), dark: context.asAbsolutePath('resources/dark/copy_inverse.png') }; + copyValueCell.onDidClick(() => { + vscode.env.clipboard.writeText(endpointInfo.hyperlink); + }); + copyValueCell.title = localize("copyText", "Copy"); + copyValueCell.iconHeight = '14px'; + copyValueCell.iconWidth = '14px'; + endPointRow.addItem(copyValueCell, { CSSStyles: { 'width': '3%', 'padding-top': '10px' } }); + + container.addItem(endPointRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } }); + }); + const endpointsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '540px', height: '100%', alignItems: 'left', position: 'absolute' }).component(); + endpointsContainer.addItem(container, { CSSStyles: { 'padding-top': '25px', 'padding-left': '5px' } }); + + await view.initializeModel(endpointsContainer); + } + }); +} + +function getCustomEndpoint(parentEndpoint: Utils.IEndpoint, serviceName: string, serviceUrl?: string): Utils.IEndpoint { + if (parentEndpoint) { + let endpoint: Utils.IEndpoint = { + serviceName: serviceName, + ipAddress: parentEndpoint.ipAddress, + port: parentEndpoint.port, + isHyperlink: serviceUrl ? true : false, + hyperlink: 'https://' + parentEndpoint.ipAddress + ':' + parentEndpoint.port + serviceUrl + }; + return endpoint; + } + return null; +} + +function getFriendlyEndpointNames(name: string): string { + let friendlyName: string = name; + switch (name) { + case 'app-proxy': + friendlyName = localize("appproxy", "Application Proxy"); + break; + case 'controller': + friendlyName = localize("controller", "Cluster Management Service"); + break; + case 'gateway': + friendlyName = localize("gateway", "HDFS and Spark"); + break; + case 'management-proxy': + friendlyName = localize("managementproxy", "Management Proxy"); + break; + case 'mgmtproxy': + friendlyName = localize("mgmtproxy", "Management Proxy"); + break; + default: + break; + } + return friendlyName; +} \ No newline at end of file diff --git a/extensions/mssql/src/main.ts b/extensions/mssql/src/main.ts index 548fb2aedd..6761fb3545 100644 --- a/extensions/mssql/src/main.ts +++ b/extensions/mssql/src/main.ts @@ -33,6 +33,8 @@ import { MssqlObjectExplorerNodeProvider, mssqlOutputChannel } from './objectExp import { CmsService } from './cms/cmsService'; import { registerSearchServerCommand } from './objectExplorerNodeProvider/command'; import { MssqlIconProvider } from './iconProvider'; +import { registerServiceEndpoints } from './dashboard/serviceEndpoints'; +import { getBookExtensionContributions } from './dashboard/bookExtensions'; const baseConfig = require('./config.json'); const outputChannel = vscode.window.createOutputChannel(Constants.serviceName); @@ -63,23 +65,7 @@ export async function activate(context: vscode.ExtensionContext): Promise languageClient.stop() }); - azdata.ui.registerModelViewProvider('bdc-endpoints', async (view) => { - - const endpointsArray: Array = Object.assign([], view.serverInfo.options['clusterEndpoints']); - endpointsArray.forEach(endpointInfo => { - endpointInfo.isHyperlink = true; - endpointInfo.hyperlink = 'https://' + endpointInfo.ipAddress + ':' + endpointInfo.port; - - }); - if (endpointsArray.length > 0) { - const managementProxyEp = endpointsArray.find(e => e.serviceName === 'management-proxy' || e.serviceName === 'mgmtproxy'); - if (managementProxyEp) { - endpointsArray.push(getCustomEndpoint(managementProxyEp, localize("grafana", "Metrics Dashboard"), '/grafana/d/wZx3OUdmz')); - endpointsArray.push(getCustomEndpoint(managementProxyEp, localize("kibana", "Log Search Dashboard"), '/kibana/app/kibana#/discover')); - } - - const gatewayEp = endpointsArray.find(e => e.serviceName === 'gateway'); - if (gatewayEp) { - endpointsArray.push(getCustomEndpoint(gatewayEp, localize("sparkHostory", "Spark Job Monitoring"), '/gateway/default/sparkhistory')); - endpointsArray.push(getCustomEndpoint(gatewayEp, localize("yarnHistory", "Spark Resource Management"), '/gateway/default/yarn')); - } - - const container = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%', alignItems: 'left' }).component(); - endpointsArray.forEach(endpointInfo => { - const endPointRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component(); - const nameCell = view.modelBuilder.text().withProperties({ value: getFriendlyEndpointNames(endpointInfo.serviceName) }).component(); - endPointRow.addItem(nameCell, { CSSStyles: { 'width': '35%', 'font-weight': '600', 'user-select': 'text' } }); - if (endpointInfo.isHyperlink) { - const linkCell = view.modelBuilder.hyperlink().withProperties({ label: endpointInfo.hyperlink, url: endpointInfo.hyperlink }).component(); - endPointRow.addItem(linkCell, { CSSStyles: { 'width': '62%', 'color': '#0078d4', 'text-decoration': 'underline', 'padding-top': '10px' } }); - } - else { - const endpointCell = view.modelBuilder.text().withProperties({ value: endpointInfo.ipAddress + ':' + endpointInfo.port }).component(); - endPointRow.addItem(endpointCell, { CSSStyles: { 'width': '62%', 'user-select': 'text' } }); - } - const copyValueCell = view.modelBuilder.button().component(); - copyValueCell.iconPath = { light: context.asAbsolutePath('resources/light/copy.png'), dark: context.asAbsolutePath('resources/dark/copy_inverse.png') }; - copyValueCell.onDidClick(() => { - vscode.env.clipboard.writeText(endpointInfo.hyperlink); - }); - copyValueCell.title = localize("copyText", "Copy"); - copyValueCell.iconHeight = '14px'; - copyValueCell.iconWidth = '14px'; - endPointRow.addItem(copyValueCell, { CSSStyles: { 'width': '3%', 'padding-top': '10px' } }); - - container.addItem(endPointRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } }); - }); - const endpointsContainer = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '540px', height: '100%', alignItems: 'left', position: 'absolute' }).component(); - endpointsContainer.addItem(container, { CSSStyles: { 'padding-top': '25px', 'padding-left': '5px' } }); - - await view.initializeModel(endpointsContainer); - } - - }); - - function getCustomEndpoint(parentEndpoint: Utils.IEndpoint, serviceName: string, serviceUrl?: string): Utils.IEndpoint { - if (parentEndpoint) { - let endpoint: Utils.IEndpoint = { - serviceName: serviceName, - ipAddress: parentEndpoint.ipAddress, - port: parentEndpoint.port, - isHyperlink: serviceUrl ? true : false, - hyperlink: 'https://' + parentEndpoint.ipAddress + ':' + parentEndpoint.port + serviceUrl - }; - return endpoint; - } - return null; - } - - function getFriendlyEndpointNames(name: string): string { - let friendlyName: string = name; - switch (name) { - case 'app-proxy': - friendlyName = localize("appproxy", "Application Proxy"); - break; - case 'controller': - friendlyName = localize("controller", "Cluster Management Service"); - break; - case 'gateway': - friendlyName = localize("gateway", "HDFS and Spark"); - break; - case 'management-proxy': - friendlyName = localize("managementproxy", "Management Proxy"); - break; - case 'mgmtproxy': - friendlyName = localize("mgmtproxy", "Management Proxy"); - break; - default: - break; - } - return friendlyName; - } + registerServiceEndpoints(context); + // Get book contributions - in the future this will be integrated with the Books/Notebook widget to show as a dashboard widget + const bookContributionProvider = getBookExtensionContributions(context); + context.subscriptions.push(bookContributionProvider); let api: MssqlExtensionApi = { getMssqlObjectExplorerBrowser(): MssqlObjectExplorerBrowser { @@ -242,6 +137,35 @@ export async function activate(context: vscode.ExtensionContext): Promise(one: ReadonlyArray, other: ReadonlyArray, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean { + if (one.length !== other.length) { + return false; + } + + for (let i = 0, len = one.length; i < len; i++) { + if (!itemEquals(one[i], other[i])) { + return false; + } + } + + return true; +} + +export function flatten(arr: ReadonlyArray[]): T[] { + return ([] as T[]).concat.apply([], arr); +} \ No newline at end of file diff --git a/extensions/mssql/src/util/dispose.ts b/extensions/mssql/src/util/dispose.ts new file mode 100644 index 0000000000..83ac3bf543 --- /dev/null +++ b/extensions/mssql/src/util/dispose.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * 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'; + +export function disposeAll(disposables: vscode.Disposable[]) { + while (disposables.length) { + const item = disposables.pop(); + if (item) { + item.dispose(); + } + } +} + +export abstract class Disposable { + private _isDisposed = false; + + protected _disposables: vscode.Disposable[] = []; + + public dispose(): any { + if (this._isDisposed) { + return; + } + this._isDisposed = true; + disposeAll(this._disposables); + } + + protected _register(value: T): T { + if (this._isDisposed) { + value.dispose(); + } else { + this._disposables.push(value); + } + return value; + } + + protected get isDisposed() { + return this._isDisposed; + } +} \ No newline at end of file diff --git a/scripts/sql.bat b/scripts/sql.bat index efce9a2888..5cffe2323d 100644 --- a/scripts/sql.bat +++ b/scripts/sql.bat @@ -17,6 +17,9 @@ set CODE=".build\electron\%NAMESHORT%" node build\lib\electron.js if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron +:: Sync built-in extensions +node build\lib\builtInExtensions.js + :: Build if not exist out node .\node_modules\gulp\bin\gulp.js compile diff --git a/scripts/sql.sh b/scripts/sql.sh index fe3d014c63..fcade57786 100755 --- a/scripts/sql.sh +++ b/scripts/sql.sh @@ -27,6 +27,9 @@ function code() { # Get electron (test -f "$CODE" && [ $INTENDED_VERSION == $INSTALLED_VERSION ]) || ./node_modules/.bin/gulp electron + # Sync built-in extensions + node build/lib/builtInExtensions.js + # Build test -d out || ./node_modules/.bin/gulp compile diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index e71e2ded79..bbebf60281 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -951,7 +951,9 @@ export class ExtensionManagementService extends Disposable implements IExtension private _devSystemExtensionsFilePath: string | null = null; private get devSystemExtensionsFilePath(): string { if (!this._devSystemExtensionsFilePath) { - this._devSystemExtensionsFilePath = path.normalize(path.join(getPathFromAmdModule(require, ''), '..', 'build', 'builtInExtensions.json')); + // {{SQL CARBON EDIT} + let builtInPath = product.quality === 'stable' ? 'builtInExtensions' : 'builtInExtensions-insiders'; + this._devSystemExtensionsFilePath = path.normalize(path.join(getPathFromAmdModule(require, ''), '..', 'build', `${builtInPath}.json`)); } return this._devSystemExtensionsFilePath; } diff --git a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts index 2a16c37dfd..da42951505 100644 --- a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts +++ b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts @@ -264,7 +264,10 @@ export class CachedExtensionScanner { let finalBuiltinExtensions: Promise = builtinExtensions; if (devMode) { - const builtInExtensionsFilePath = path.normalize(path.join(getPathFromAmdModule(require, ''), '..', 'build', 'builtInExtensions.json')); + // {{SQL CARBON EDIT}} + let builtInFilename = product.quality === 'stable' ? 'builtInExtensions.json' : 'builtInExtensions-insiders.json'; + const builtInExtensionsFilePath = path.normalize(path.join(getPathFromAmdModule(require, ''), '..', 'build', builtInFilename)); + // {{SQL CARBON EDIT}} - END const builtInExtensions = pfs.readFile(builtInExtensionsFilePath, 'utf8') .then(raw => JSON.parse(raw));