From c8caac361f8237c324fa13ef0f5a5a565e8ea59e Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 16 Aug 2016 16:23:20 +0200 Subject: [PATCH] contain gallery code inside GalleryService related to #10180 --- src/vs/code/node/cliProcessMain.ts | 5 +- src/vs/code/node/sharedProcessMain.ts | 7 +- .../common/extensionManagement.ts | 27 +-- .../common/extensionManagementIpc.ts | 16 +- .../node/extensionGalleryService.ts | 159 ++++++++++++------ .../node/extensionManagementService.ts | 137 ++++----------- .../node/extensionManagementUtil.ts | 2 +- .../extensionsWorkbenchService.ts | 24 +-- 8 files changed, 185 insertions(+), 192 deletions(-) diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 358c72759d555..8f3649fd0444d 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -113,9 +113,8 @@ class Main { console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id)); console.log(localize('installing', "Installing...")); - return this.extensionManagementService.install(extension).then(() => { - console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.versions[0].version)); - }); + return this.extensionManagementService.installFromGallery(extension) + .then(() => console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.version))); }); }); }); diff --git a/src/vs/code/node/sharedProcessMain.ts b/src/vs/code/node/sharedProcessMain.ts index 03e38e8e2cbc3..4155fcc209975 100644 --- a/src/vs/code/node/sharedProcessMain.ts +++ b/src/vs/code/node/sharedProcessMain.ts @@ -17,8 +17,9 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ import { IEventService } from 'vs/platform/event/common/event'; import { EventService } from 'vs/platform/event/common/eventService'; import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; -import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { NodeConfigurationService } from 'vs/platform/configuration/node/nodeConfigurationService'; import { ITelemetryService, combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -55,7 +56,6 @@ function main(server: Server): void { services.set(IEventService, new SyncDescriptor(EventService)); services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IConfigurationService, new SyncDescriptor(NodeConfigurationService)); const instantiationService = new InstantiationService(services); @@ -93,6 +93,9 @@ function main(server: Server): void { services.set(ITelemetryService, NullTelemetryService); } + services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); + const instantiationService2 = instantiationService.createChild(services); instantiationService2.invokeFunction(accessor => { diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index d5b93c042117b..fea9dd07dca8f 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -22,25 +22,24 @@ export interface IExtensionManifest { icon?: string; } -export interface IGalleryVersion { - version: string; - date: string; - manifestUrl: string; - readmeUrl: string; - downloadUrl: string; - iconUrl: string; - licenseUrl: string; - downloadHeaders: { [key: string]: string; }; -} - export interface IExtensionIdentity { name: string; publisher: string; } +export interface IGalleryExtensionAssets { + manifest: string; + readme: string; + download: string; + icon: string; + license: string; +} + export interface IGalleryExtension { id: string; name: string; + version: string; + date: string; displayName: string; publisherId: string; publisher: string; @@ -49,7 +48,8 @@ export interface IGalleryExtension { installCount: number; rating: number; ratingCount: number; - versions: IGalleryVersion[]; + assets: IGalleryExtensionAssets; + downloadHeaders: { [key: string]: string; }; } export interface IGalleryMetadata { @@ -98,6 +98,7 @@ export interface IExtensionGalleryService { _serviceBrand: any; isEnabled(): boolean; query(options?: IQueryOptions): TPromise>; + download(extension: IGalleryExtension): TPromise; } export type InstallExtensionEvent = { id: string; gallery?: IGalleryExtension; }; @@ -111,8 +112,8 @@ export interface IExtensionManagementService { onUninstallExtension: Event; onDidUninstallExtension: Event; - install(extension: IGalleryExtension): TPromise; install(zipPath: string): TPromise; + installFromGallery(extension: IGalleryExtension): TPromise; uninstall(extension: ILocalExtension): TPromise; getInstalled(): TPromise; } diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index 38dcc18931089..03118cf831c4c 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent } from './extensionManagement'; +import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension } from './extensionManagement'; import Event from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -15,7 +15,8 @@ export interface IExtensionManagementChannel extends IChannel { call(command: 'event:onDidInstallExtension'): TPromise; call(command: 'event:onUninstallExtension'): TPromise; call(command: 'event:onDidUninstallExtension'): TPromise; - call(command: 'install', extensionOrPath: ILocalExtension | string): TPromise; + call(command: 'install', path: string): TPromise; + call(command: 'installFromGallery', extension: IGalleryExtension): TPromise; call(command: 'uninstall', extension: ILocalExtension): TPromise; call(command: 'getInstalled'): TPromise; call(command: string, arg: any): TPromise; @@ -32,6 +33,7 @@ export class ExtensionManagementChannel implements IExtensionManagementChannel { case 'event:onUninstallExtension': return eventToCall(this.service.onUninstallExtension); case 'event:onDidUninstallExtension': return eventToCall(this.service.onDidUninstallExtension); case 'install': return this.service.install(arg); + case 'installFromGallery': return this.service.installFromGallery(arg); case 'uninstall': return this.service.uninstall(arg); case 'getInstalled': return this.service.getInstalled(); } @@ -56,10 +58,12 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer private _onDidUninstallExtension = eventFromCall(this.channel, 'event:onDidUninstallExtension'); get onDidUninstallExtension(): Event { return this._onDidUninstallExtension; } - install(extension: IGalleryExtension): TPromise; - install(zipPath: string): TPromise; - install(arg: any): TPromise { - return this.channel.call('install', arg); + install(zipPath: string): TPromise { + return this.channel.call('install', zipPath); + } + + installFromGallery(extension: IGalleryExtension): TPromise { + return this.channel.call('installFromGallery', extension); } uninstall(extension: ILocalExtension): TPromise { diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index d5c8e5e90120b..d40ab7e0ba758 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -3,15 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { localize } from 'vs/nls'; +import { tmpdir } from 'os'; +import * as path from 'path'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IGalleryExtension, IExtensionGalleryService, IGalleryVersion, IQueryOptions, SortBy, SortOrder } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IGalleryExtension, IExtensionGalleryService, IQueryOptions, SortBy, SortOrder, IExtensionManifest } from 'vs/platform/extensionManagement/common/extensionManagement'; import { isUndefined } from 'vs/base/common/types'; import { assign, getOrDefault } from 'vs/base/common/objects'; import { IRequestService } from 'vs/platform/request/common/request'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IPager } from 'vs/base/common/paging'; +import { download, json, IRequestOptions } from 'vs/base/node/request'; +import { getProxyAgent } from 'vs/base/node/proxy'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import pkg from 'vs/platform/package'; import product from 'vs/platform/product'; +import { isValidExtensionVersion } from 'vs/platform/extensions/node/extensionValidator'; interface IRawGalleryExtensionFile { assetType: string; @@ -158,21 +165,21 @@ function getAssetSource(files: IRawGalleryExtensionFile[], type: string): string return result && result.source; } -function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUrl: string, downloadHeaders: any): IGalleryExtension { - const versions = galleryExtension.versions.map(v => ({ - version: v.version, - date: v.lastUpdated, - downloadHeaders, - downloadUrl: `${ v.assetUri }/${ AssetType.VSIX }?install=true`, - manifestUrl: `${ v.assetUri }/${ AssetType.Manifest }`, - readmeUrl: `${ v.assetUri }/${ AssetType.Details }`, - iconUrl: getAssetSource(v.files, AssetType.Icon) || require.toUrl('./media/defaultIcon.png'), - licenseUrl: getAssetSource(v.files, AssetType.License) - })); +function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUrl: string, downloadHeaders: { [key: string]: string; }): IGalleryExtension { + const [version] = galleryExtension.versions; + const assets = { + manifest: getAssetSource(version.files, AssetType.Manifest), + readme: getAssetSource(version.files, AssetType.Details), + download: `${ getAssetSource(version.files, AssetType.VSIX) }?install=true`, + icon: getAssetSource(version.files, AssetType.Icon) || require.toUrl('./media/defaultIcon.png'), + license: getAssetSource(version.files, AssetType.License) + }; return { id: galleryExtension.extensionId, name: galleryExtension.extensionName, + version: version.version, + date: version.lastUpdated, displayName: galleryExtension.displayName, publisherId: galleryExtension.publisher.publisherId, publisher: galleryExtension.publisher.publisherName, @@ -181,7 +188,8 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr installCount: getStatistic(galleryExtension.statistics, 'install'), rating: getStatistic(galleryExtension.statistics, 'averagerating'), ratingCount: getStatistic(galleryExtension.statistics, 'ratingcount'), - versions + assets, + downloadHeaders }; } @@ -190,15 +198,29 @@ export class ExtensionGalleryService implements IExtensionGalleryService { _serviceBrand: any; private extensionsGalleryUrl: string; - private machineId: TPromise; + + private getCommonHeaders(): TPromise<{ [key: string]: string; }> { + return this.telemetryService.getTelemetryInfo().then(({ machineId }) => { + const result: { [key: string]: string; } = { + 'X-Market-Client-Id': `VSCode ${ pkg.version }`, + 'User-Agent': `VSCode ${ pkg.version }` + }; + + if (machineId) { + result['X-Market-User-Id'] = machineId; + } + + return result; + }); + } constructor( @IRequestService private requestService: IRequestService, - @ITelemetryService private telemetryService: ITelemetryService + @ITelemetryService private telemetryService: ITelemetryService, + @IConfigurationService private configurationService: IConfigurationService ) { const config = product.extensionsGallery; this.extensionsGalleryUrl = config && config.serviceUrl; - this.machineId = telemetryService.getTelemetryInfo().then(({ machineId }) => machineId); } private api(path = ''): string { @@ -221,10 +243,10 @@ export class ExtensionGalleryService implements IExtensionGalleryService { this.telemetryService.publicLog('galleryService:query', { type, text }); let query = new Query() - .withFlags(Flags.IncludeVersions, Flags.IncludeCategoryAndTags, Flags.IncludeAssetUri, Flags.IncludeStatistics, Flags.IncludeFiles) + .withFlags(Flags.IncludeLatestVersionOnly, Flags.IncludeAssetUri, Flags.IncludeStatistics, Flags.IncludeFiles) .withPage(1, pageSize) .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code') - .withAssetTypes(AssetType.Icon, AssetType.License); + .withAssetTypes(AssetType.Icon, AssetType.License, AssetType.Details, AssetType.Manifest, AssetType.VSIX); if (text) { query = query.withFilter(FilterType.SearchText, text).withSortBy(SortBy.NoneOrRelevance); @@ -245,7 +267,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } return this.queryGallery(query).then(({ galleryExtensions, total }) => { - return this.getRequestHeaders().then(downloadHeaders => { + return this.getCommonHeaders().then(downloadHeaders => { const extensions = galleryExtensions.map(e => toExtension(e, this.extensionsGalleryUrl, downloadHeaders)); const pageSize = query.pageSize; const getPage = pageIndex => this.queryGallery(query.withPage(pageIndex + 1)) @@ -258,27 +280,19 @@ export class ExtensionGalleryService implements IExtensionGalleryService { private queryGallery(query: Query): TPromise<{ galleryExtensions: IRawGalleryExtension[], total: number; }> { const data = JSON.stringify(query.raw); - - return this.getRequestHeaders() - .then(headers => { - headers = assign(headers, { - 'Content-Type': 'application/json', - 'Accept': 'application/json;api-version=3.0-preview.1', - 'Accept-Encoding': 'gzip', - 'Content-Length': data.length - }); - - const request = { - type: 'POST', - url: this.api('/extensionquery'), - data, - headers - }; - - return this.requestService.makeRequest(request); - }) - .then(r => JSON.parse(r.responseText).results[0]) - .then(r => { + const request = this.request(this.api('/extensionquery')); + + return this.getCommonHeaders() + .then(headers => assign(headers, { + 'Content-Type': 'application/json', + 'Accept': 'application/json;api-version=3.0-preview.1', + 'Accept-Encoding': 'gzip', + 'Content-Length': data.length + })) + .then(headers => assign(request, { type: 'POST', data, headers })) + .then(() => json(request)) + .then(result => { + const r = result.results[0]; const galleryExtensions = r.extensions; const resultCount = r.resultMetadata && r.resultMetadata.filter(m => m.metadataType === 'ResultCount')[0]; const total = resultCount && resultCount.metadataItems.filter(i => i.name === 'TotalCount')[0].count || 0; @@ -287,18 +301,67 @@ export class ExtensionGalleryService implements IExtensionGalleryService { }); } - private getRequestHeaders(): TPromise { - return this.machineId.then(machineId => { - const result = { - 'X-Market-Client-Id': `VSCode ${ pkg.version }`, - 'User-Agent': `VSCode ${ pkg.version }` + download(extension: IGalleryExtension): TPromise { + const query = new Query() + .withFlags(Flags.IncludeVersions, Flags.IncludeFiles) + .withPage(1, 1) + .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code') + .withAssetTypes(AssetType.Manifest, AssetType.VSIX) + .withFilter(FilterType.ExtensionId, extension.id); + + return this.queryGallery(query).then(({ galleryExtensions }) => { + const [rawExtension] = galleryExtensions; + + if (!rawExtension) { + return TPromise.wrapError(new Error(localize('notFound', "Extension not found"))); + } + + return this.getLastValidExtensionVersion(rawExtension, rawExtension.versions).then(rawVersion => { + const url = `${ getAssetSource(rawVersion.files, AssetType.VSIX) }?install=true`; + const zipPath = path.join(tmpdir(), extension.id); + const request = this.request(url); + + return this.getCommonHeaders() + .then(headers => assign(request, { headers })) + .then(() => download(zipPath, request)) + .then(() => zipPath); + }); + }); + } + + private getLastValidExtensionVersion(extension: IRawGalleryExtension, versions: IRawGalleryExtensionVersion[]): TPromise { + if (!versions.length) { + return TPromise.wrapError(new Error(localize('noCompatible', "Couldn't find a compatible version of {0} with this version of Code.", extension.displayName || extension.extensionName))); + } + + const version = versions[0]; + const url = getAssetSource(version.files, AssetType.Manifest); + let request = this.request(url); + request = assign(request, { headers: { 'accept-encoding': 'gzip' } }); + + return json(request).then(manifest => { + const desc = { + isBuiltin: false, + engines: { vscode: manifest.engines.vscode }, + main: manifest.main }; - if (machineId) { - result['X-Market-User-Id'] = machineId; + if (!isValidExtensionVersion(pkg.version, desc, [])) { + return this.getLastValidExtensionVersion(extension, versions.slice(1)); } - return result; + return version; }); } + + // Helper for proxy business... shameful. + // This should be pushed down and not rely on the context service + private request(url: string): IRequestOptions { + const httpConfig = this.configurationService.getConfiguration('http') || {}; + const proxyUrl = httpConfig.proxy as string; + const strictSSL = httpConfig.proxyStrictSSL as boolean; + const agent = getProxyAgent(url, { proxyUrl, strictSSL }); + + return { url, agent, strictSSL }; + } } \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 6a2054cecd86a..e52a58d8daa10 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -6,26 +6,19 @@ 'use strict'; import nls = require('vs/nls'); -import { tmpdir } from 'os'; import * as path from 'path'; -import types = require('vs/base/common/types'); import * as pfs from 'vs/base/node/pfs'; import { assign } from 'vs/base/common/objects'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { flatten } from 'vs/base/common/arrays'; import { extract, buffer } from 'vs/base/node/zip'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionIdentity, IExtensionManifest, IGalleryVersion, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { download, json, IRequestOptions } from 'vs/base/node/request'; -import { getProxyAgent } from 'vs/base/node/proxy'; +import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IExtensionIdentity, IExtensionManifest, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Limiter } from 'vs/base/common/async'; import Event, { Emitter } from 'vs/base/common/event'; -import { UserSettings } from 'vs/base/node/userSettings'; import * as semver from 'semver'; import { groupBy, values } from 'vs/base/common/collections'; -import { isValidExtensionVersion } from 'vs/platform/extensions/node/extensionValidator'; -import pkg from 'vs/platform/package'; function parseManifest(raw: string): TPromise<{ manifest: IExtensionManifest; metadata: IGalleryMetadata; }> { return new Promise((c, e) => { @@ -88,100 +81,60 @@ export class ExtensionManagementService implements IExtensionManagementService { onDidUninstallExtension: Event = this._onDidUninstallExtension.event; constructor( - @IEnvironmentService private environmentService: IEnvironmentService + @IEnvironmentService private environmentService: IEnvironmentService, + @IExtensionGalleryService private galleryService: IExtensionGalleryService ) { this.extensionsPath = environmentService.extensionsPath; this.obsoletePath = path.join(this.extensionsPath, '.obsolete'); this.obsoleteFileLimiter = new Limiter(1); } - install(extension: IGalleryExtension): TPromise; - install(zipPath: string): TPromise; - install(arg: any): TPromise { - let id: string; - let result: TPromise; + install(zipPath: string): TPromise { + return validate(zipPath).then(manifest => { + const id = getExtensionId(manifest, manifest.version); - if (types.isString(arg)) { - const zipPath = arg as string; + return this.isObsolete(id).then(isObsolete => { + if (isObsolete) { + return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", manifest.displayName || manifest.name))); + } - result = validate(zipPath).then(manifest => { - id = getExtensionId(manifest, manifest.version); this._onInstallExtension.fire({ id }); - return this.installValidExtension(zipPath, id); - }); - } else { - const extension = arg as IGalleryExtension; - id = getExtensionId(extension, extension.versions[0].version); - this._onInstallExtension.fire({ id, gallery: extension }); - - result = this.isObsolete(id).then(obsolete => { - if (obsolete) { - return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.displayName || extension.name))); - } - - return this.installFromGallery(arg); + return this.installExtension(zipPath, id) + .then( + local => this._onDidInstallExtension.fire({ id, local }), + error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); } + ); }); - } - - return result.then( - local => this._onDidInstallExtension.fire({ id, local }), - error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); } - ); - } - - private installFromGallery(extension: IGalleryExtension): TPromise { - return this.getLastValidExtensionVersion(extension).then(versionInfo => { - const version = versionInfo.version; - const url = versionInfo.downloadUrl; - const headers = versionInfo.downloadHeaders; - const zipPath = path.join(tmpdir(), extension.id); - const id = getExtensionId(extension, version); - const metadata = { - id: extension.id, - publisherId: extension.publisherId, - publisherDisplayName: extension.publisherDisplayName - }; - - return this.request(url) - .then(opts => assign(opts, { headers })) - .then(opts => download(zipPath, opts)) - .then(() => validate(zipPath, extension, version)) - .then(() => this.installValidExtension(zipPath, id, metadata)); }); } - private getLastValidExtensionVersion(extension: IGalleryExtension): TPromise { - return this._getLastValidExtensionVersion(extension, extension.versions); - } + installFromGallery(extension: IGalleryExtension): TPromise { + const id = getExtensionId(extension, extension.version); - private _getLastValidExtensionVersion(extension: IGalleryExtension, versions: IGalleryVersion[]): TPromise { - if (!versions.length) { - return TPromise.wrapError(new Error(nls.localize('noCompatible', "Couldn't find a compatible version of {0} with this version of Code.", extension.displayName || extension.name))); - } + return this.isObsolete(id).then(isObsolete => { + if (isObsolete) { + return TPromise.wrapError(new Error(nls.localize('restartCode', "Please restart Code before reinstalling {0}.", extension.displayName || extension.name))); + } - const headers = { 'accept-encoding': 'gzip' }; - const version = versions[0]; - - return this.request(version.manifestUrl) - .then(opts => assign(opts, { headers })) - .then(opts => json(opts)) - .then(manifest => { - const desc = { - isBuiltin: false, - engines: { vscode: manifest.engines.vscode }, - main: manifest.main - }; - - if (!isValidExtensionVersion(pkg.version, desc, [])) { - return this._getLastValidExtensionVersion(extension, versions.slice(1)); - } + this._onInstallExtension.fire({ id, gallery: extension }); - return version; - }); + const metadata = { + id: extension.id, + publisherId: extension.publisherId, + publisherDisplayName: extension.publisherDisplayName + }; + + return this.galleryService.download(extension) + .then(zipPath => this.installExtension(zipPath, id, metadata)) + .then( + local => this._onDidInstallExtension.fire({ id, local }), + error => { this._onDidInstallExtension.fire({ id, error }); return TPromise.wrapError(error); } + ); + }); } - private installValidExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { + private installExtension(zipPath: string, id: string, metadata: IGalleryMetadata = null): TPromise { const extensionPath = path.join(this.extensionsPath, id); const manifestPath = path.join(extensionPath, 'package.json'); @@ -314,24 +267,6 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - // Helper for proxy business... shameful. - // This should be pushed down and not rely on the context service - private request(url: string): TPromise { - const settings = TPromise.join([ - // TODO@Joao we need a nice configuration service here! - UserSettings.getValue(this.environmentService.userDataPath, 'http.proxy'), - UserSettings.getValue(this.environmentService.userDataPath, 'http.proxyStrictSSL') - ]); - - return settings.then(settings => { - const proxyUrl: string = settings[0]; - const strictSSL: boolean = settings[1]; - const agent = getProxyAgent(url, { proxyUrl, strictSSL }); - - return { url, agent, strictSSL }; - }); - } - dispose() { this.disposables = dispose(this.disposables); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts index 06984461a1b30..1c423341b652f 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementUtil.ts @@ -55,7 +55,7 @@ export function getOutdatedExtensions(extensionsService: IExtensionManagementSer return available.map(extension => { const local = installed.filter(local => extensionEquals(local.manifest, extension))[0]; - if (local && semver.lt(local.manifest.version, extension.versions[0].version)) { + if (local && semver.lt(local.manifest.version, extension.version)) { return local; } else { return null; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index 32e32d6aa333c..e1c6e620c5df8 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -63,11 +63,11 @@ class Extension implements IExtension { } get version(): string { - return this.local ? this.local.manifest.version : this.gallery.versions[0].version; + return this.local ? this.local.manifest.version : this.gallery.version; } get latestVersion(): string { - return this.gallery ? this.gallery.versions[0].version : this.local.manifest.version; + return this.gallery ? this.gallery.version : this.local.manifest.version; } get description(): string { @@ -79,11 +79,7 @@ class Extension implements IExtension { return this.local.readmeUrl; } - if (this.gallery && this.gallery.versions[0].readmeUrl) { - return this.gallery.versions[0].readmeUrl; - } - - return null; + return this.gallery && this.gallery.assets.readme; } get iconUrl(): string { @@ -91,19 +87,11 @@ class Extension implements IExtension { return URI.file(path.join(this.local.path, this.local.manifest.icon)).toString(); } - if (this.gallery) { - return this.gallery.versions[0].iconUrl; - } - - return require.toUrl('./media/defaultIcon.png'); + return this.gallery ? this.gallery.assets.icon : require.toUrl('./media/defaultIcon.png'); } get licenseUrl(): string { - if (this.gallery) { - return this.gallery.versions[0].licenseUrl; - } - - return null; + return this.gallery && this.gallery.assets.license; } get state(): ExtensionState { @@ -283,7 +271,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return TPromise.wrapError(new Error('Missing gallery')); } - return this.extensionService.install(gallery); + return this.extensionService.installFromGallery(gallery); } uninstall(extension: IExtension): TPromise {