Skip to content

Commit

Permalink
extension service: compatible version first steps
Browse files Browse the repository at this point in the history
  • Loading branch information
joaomoreno committed Feb 19, 2016
1 parent 302701c commit c06d578
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 41 deletions.
15 changes: 11 additions & 4 deletions src/vs/workbench/parts/extensions/common/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,29 @@ export interface IExtensionManifest {
name: string;
publisher: string;
version: string;
engines: { vscode: string };
displayName?: string;
description?: string;
}

export interface IGalleryInformation {
export interface IGalleryVersion {
version: string;
date: string;
manifestUrl: string;
downloadUrl: string;
}

export interface IGalleryMetadata {
galleryApiUrl: string;
id: string;
downloadUrl: string;
publisherId: string;
publisherDisplayName: string;
installCount: number;
date: string;
versions: IGalleryVersion[];
}

export interface IExtension extends IExtensionManifest {
galleryInformation?: IGalleryInformation;
galleryInformation?: IGalleryMetadata;
path?: string;
}

Expand Down
75 changes: 55 additions & 20 deletions src/vs/workbench/parts/extensions/node/extensionsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ import { assign } from 'vs/base/common/objects';
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 { IExtensionsService, IExtension, IExtensionManifest, IGalleryInformation } from 'vs/workbench/parts/extensions/common/extensions';
import { download } from 'vs/base/node/request';
import { IExtensionsService, IExtension, IExtensionManifest, IGalleryMetadata, IGalleryVersion } from 'vs/workbench/parts/extensions/common/extensions';
import { download, json, IRequestOptions } from 'vs/base/node/request';
import { getProxyAgent } from 'vs/base/node/proxy';
import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService';
import { Limiter } from 'vs/base/common/async';
import Event, { Emitter } from 'vs/base/common/event';
import { UserSettings } from 'vs/workbench/node/userSettings';
import * as semver from 'semver';
import {groupBy, values} from 'vs/base/common/collections';
import { groupBy, values } from 'vs/base/common/collections';
import { isValidExtensionVersion } from 'vs/platform/plugins/node/pluginVersionValidator';

function parseManifest(raw: string): TPromise<IExtensionManifest> {
return new Promise((c, e) => {
Expand Down Expand Up @@ -57,12 +58,13 @@ function validate(zipPath: string, extension?: IExtension): TPromise<IExtension>
});
}

function createExtension(manifest: IExtensionManifest, galleryInformation?: IGalleryInformation, path?: string): IExtension {
function createExtension(manifest: IExtensionManifest, galleryInformation?: IGalleryMetadata, path?: string): IExtension {
const extension: IExtension = {
name: manifest.name,
displayName: manifest.displayName || manifest.name,
publisher: manifest.publisher,
version: manifest.version,
engines: { vscode: manifest.engines.vscode },
description: manifest.description || ''
};

Expand All @@ -77,7 +79,7 @@ function createExtension(manifest: IExtensionManifest, galleryInformation?: IGal
return extension;
}

function getExtensionId(extension: IExtension): string {
function getExtensionId(extension: IExtensionManifest, version = extension.version): string {
return `${ extension.publisher }.${ extension.name }-${ extension.version }`;
}

Expand Down Expand Up @@ -127,22 +129,14 @@ export class ExtensionsService implements IExtensionsService {
return TPromise.wrapError(new Error(nls.localize('missingGalleryInformation', "Gallery information is missing")));
}

const url = galleryInformation.downloadUrl;
const zipPath = path.join(tmpdir(), galleryInformation.id);
const extensionPath = path.join(this.extensionsPath, getExtensionId(extension));
const manifestPath = path.join(extensionPath, 'package.json');
return this.getLastValidExtensionVersion(extension, extension.galleryInformation.versions).then(version => {
const zipPath = path.join(tmpdir(), galleryInformation.id);
const extensionPath = path.join(this.extensionsPath, getExtensionId(extension, version.version));
const manifestPath = path.join(extensionPath, 'package.json');
const url = version.downloadUrl;

const settings = TPromise.join([
UserSettings.getValue(this.contextService, 'http.proxy'),
UserSettings.getValue(this.contextService, 'http.proxyStrictSSL')
]);

return settings.then(settings => {
const proxyUrl: string = settings[0];
const strictSSL: boolean = settings[1];
const agent = getProxyAgent(url, { proxyUrl, strictSSL });

return download(zipPath, { url, agent, strictSSL })
return this.request(url)
.then(opts => download(zipPath, opts))
.then(() => validate(zipPath, extension))
.then(manifest => { this._onInstallExtension.fire(manifest); return manifest; })
.then(manifest => extract(zipPath, extensionPath, { sourcePath: 'extension', overwrite: true }).then(() => manifest))
Expand All @@ -154,6 +148,29 @@ export class ExtensionsService implements IExtensionsService {
});
}

private getLastValidExtensionVersion(extension: IExtension, versions: IGalleryVersion[]): TPromise<IGalleryVersion> {
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)));
}

const version = versions[0];
return this.request(version.manifestUrl)
.then(opts => json<IExtensionManifest>(opts))
.then(manifest => {
const codeVersion = this.contextService.getConfiguration().env.version;
const desc = {
isBuiltin: false,
engines: { vscode: manifest.engines.vscode }
};

if (!isValidExtensionVersion(codeVersion, desc, [])) {
return this.getLastValidExtensionVersion(extension, versions.slice(1));
}

return version;
});
}

private installFromZip(zipPath: string): TPromise<IExtension> {
return validate(zipPath).then(manifest => {
const extensionPath = path.join(this.extensionsPath, getExtensionId(manifest));
Expand Down Expand Up @@ -267,4 +284,22 @@ export class ExtensionsService implements IExtensionsService {
.then(() => result);
});
}

// Helper for proxy business... shameful.
// This should be pushed down and not rely on the context service
private request(url: string): TPromise<IRequestOptions> {
const settings = TPromise.join([
UserSettings.getValue(this.contextService, 'http.proxy'),
UserSettings.getValue(this.contextService, '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 };
});
}
}
43 changes: 26 additions & 17 deletions src/vs/workbench/parts/extensions/node/vsoGalleryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { TPromise } from 'vs/base/common/winjs.base';
import { IGalleryService, IExtension } from 'vs/workbench/parts/extensions/common/extensions';
import { IGalleryService, IExtension, IGalleryVersion } from 'vs/workbench/parts/extensions/common/extensions';
import { IXHRResponse } from 'vs/base/common/http';
import { IRequestService } from 'vs/platform/request/common/request';
import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService';
Expand Down Expand Up @@ -99,22 +99,31 @@ export class GalleryService implements IGalleryService {
return cache
.then<IGalleryExtension[]>(r => JSON.parse(r.responseText).results[0].extensions || [])
.then<IExtension[]>(extensions => {
return extensions.map(extension => ({
name: extension.extensionName,
displayName: extension.displayName || extension.extensionName,
publisher: extension.publisher.publisherName,
version: extension.versions[0].version,
description: extension.shortDescription || '',
galleryInformation: {
galleryApiUrl: this.extensionsGalleryUrl,
id: extension.extensionId,
downloadUrl: `${ extension.versions[0].assetUri }/Microsoft.VisualStudio.Services.VSIXPackage?install=true`,
publisherId: extension.publisher.publisherId,
publisherDisplayName: extension.publisher.displayName,
installCount: getInstallCount(extension.statistics),
date: extension.versions[0].lastUpdated,
}
}));
return extensions.map(e => {
const versions = e.versions.map<IGalleryVersion>(v => ({
version: v.version,
date: v.lastUpdated,
downloadUrl: `${ v.assetUri }/Microsoft.VisualStudio.Services.VSIXPackage?install=true`,
manifestUrl: `${ v.assetUri }/Microsoft.VisualStudio.Code.Manifest`
}));

return {
name: e.extensionName,
displayName: e.displayName || e.extensionName,
publisher: e.publisher.publisherName,
version: versions[0].version,
engines: { vscode: void 0 }, // TODO: ugly
description: e.shortDescription || '',
galleryInformation: {
galleryApiUrl: this.extensionsGalleryUrl,
id: e.extensionId,
publisherId: e.publisher.publisherId,
publisherDisplayName: e.publisher.displayName,
installCount: getInstallCount(e.statistics),
versions
}
};
});
});
}

Expand Down

0 comments on commit c06d578

Please sign in to comment.