Skip to content

Commit

Permalink
Skip extension resolution if already installed
Browse files Browse the repository at this point in the history
  • Loading branch information
msujew committed Jan 12, 2022
1 parent dd900be commit 74db1db
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 2 deletions.
3 changes: 2 additions & 1 deletion packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,9 +822,10 @@ export interface PluginDeployerHandler {
deployFrontendPlugins(frontendPlugins: PluginDeployerEntry[]): Promise<void>;
deployBackendPlugins(backendPlugins: PluginDeployerEntry[]): Promise<void>;

getDeployedPlugin(pluginId: string): DeployedPlugin | undefined;
undeployPlugin(pluginId: string): Promise<boolean>;

getPluginDependencies(pluginToBeInstalled: PluginDeployerEntry): Promise<PluginDependencies | undefined>
getPluginDependencies(pluginToBeInstalled: PluginDeployerEntry): Promise<PluginDependencies | undefined>;
}

export interface GetDeployedPluginsParams {
Expand Down
69 changes: 69 additions & 0 deletions packages/vsx-registry/src/common/vsx-version.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/********************************************************************************
* Copyright (C) 2022 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { expect } from 'chai';
import { compareVersion, parseVersion } from './vsx-version';

describe('parseVersion', () => {

it('should succesfully parse 2', () => {
expect(parseVersion('2')).to.be.deep.equal([2]);
});

it('should succesfully parse 2.4.3', () => {
expect(parseVersion('2.4.3')).to.be.deep.equal([2, 4, 3]);
});

it('should fail parsing when non-numeric version is given', () => {
expect(parseVersion('2.3-preview4')).to.be.equal(undefined);
});
});

describe('compareVersion', () => {

it('should correctly identify version equality', () => {
const a = parseVersion('2.4.3')!;
const b = parseVersion('2.4.3')!;
expect(compareVersion(a, b)).to.be.equals(0);
});

it('should correctly identify larger version', () => {
const larger = parseVersion('1.42.0')!;
const smaller = parseVersion('1.14.4')!;
expect(compareVersion(larger, smaller)).to.be.equals(1);
expect(compareVersion(smaller, larger)).to.be.equals(-1);
});

it('should correctly identify larger version with less specificity', () => {
const larger = parseVersion('1.42')!;
const smaller = parseVersion('1.14.4')!;
expect(compareVersion(larger, smaller)).to.be.equals(1);
expect(compareVersion(smaller, larger)).to.be.equals(-1);
});

it('should correctly identify larger version with more specificity', () => {
const larger = parseVersion('1.42.1')!;
const smaller = parseVersion('1.42')!;
expect(compareVersion(larger, smaller)).to.be.equals(1);
expect(compareVersion(smaller, larger)).to.be.equals(-1);
});

it('should correctly identify version equality with more specificity', () => {
const a = parseVersion('1.42.0')!;
const b = parseVersion('1.42')!;
expect(compareVersion(a, b)).to.be.equals(0);
});
});
41 changes: 41 additions & 0 deletions packages/vsx-registry/src/common/vsx-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/********************************************************************************
* Copyright (C) 2022 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

export type VSXExtensionVersion = number[];

export function parseVersion(versionString: string): VSXExtensionVersion | undefined {
const array = versionString.split('.').map(e => Number(e));
return array.some(isNaN) ? undefined : array;
}

export function compareVersion(a: VSXExtensionVersion, b: VSXExtensionVersion): (-1 | 0 | 1) {
const length = Math.max(a.length, b.length);
if (length > b.length) {
b = b.concat(new Array(length - b.length).fill(0));
} else if (length > a.length) {
a = a.concat(new Array(length - a.length).fill(0));
}
for (let i = 0; i < length; i++) {
const aPart = a[i];
const bPart = b[i];
if (aPart > bPart) {
return 1;
} else if (aPart < bPart) {
return -1;
}
}
return 0;
}
26 changes: 25 additions & 1 deletion packages/vsx-registry/src/node/vsx-extension-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@ import { v4 as uuidv4 } from 'uuid';
import * as requestretry from 'requestretry';
import { injectable, inject } from '@theia/core/shared/inversify';
import URI from '@theia/core/lib/common/uri';
import { PluginDeployerResolver, PluginDeployerResolverContext } from '@theia/plugin-ext/lib/common/plugin-protocol';
import { PluginDeployerHandler, PluginDeployerResolver, PluginDeployerResolverContext } from '@theia/plugin-ext/lib/common/plugin-protocol';
import { VSXExtensionUri } from '../common/vsx-extension-uri';
import { OVSXClientProvider } from '../common/ovsx-client-provider';
import { VSXExtensionRaw } from '@theia/ovsx-client';
import { compareVersion, parseVersion } from '../common/vsx-version';

@injectable()
export class VSXExtensionResolver implements PluginDeployerResolver {

@inject(OVSXClientProvider)
protected clientProvider: OVSXClientProvider;

@inject(PluginDeployerHandler)
protected pluginDeployerHandler: PluginDeployerHandler;

protected readonly downloadPath: string;

constructor() {
Expand Down Expand Up @@ -61,6 +66,12 @@ export class VSXExtensionResolver implements PluginDeployerResolver {
const downloadUrl = extension.files.download;
console.log(`[${id}]: resolved to '${resolvedId}'`);

const existingVersion = this.hasSameOrNewerVersion(id, extension);
if (existingVersion) {
console.log(`[${id}]: is already installed with the same or newer version '${existingVersion}'`);
return;
}

const extensionPath = path.resolve(this.downloadPath, path.basename(downloadUrl));
console.log(`[${resolvedId}]: trying to download from "${downloadUrl}"...`);
if (!await this.download(downloadUrl, extensionPath)) {
Expand All @@ -71,6 +82,19 @@ export class VSXExtensionResolver implements PluginDeployerResolver {
context.addPlugin(resolvedId, extensionPath);
}

protected hasSameOrNewerVersion(id: string, extension: VSXExtensionRaw): string | undefined {
const existingPlugin = this.pluginDeployerHandler.getDeployedPlugin(id);
if (existingPlugin) {
const version = parseVersion(extension.version);
const modelVersion = existingPlugin.metadata.model.version;
const existingVersion = parseVersion(modelVersion);
if (version && existingVersion && compareVersion(existingVersion, version) >= 0) {
return modelVersion;
}
}
return undefined;
}

protected async download(downloadUrl: string, downloadPath: string): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
requestretry(downloadUrl, {
Expand Down

0 comments on commit 74db1db

Please sign in to comment.