diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2dbc881f452a9..933afb251a78a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,10 @@
- [terminal] Use application shell methods for expanding/collapsing bottom panel for "Terminal: Toggle Terminal" command [#13131](https://github.com/eclipse-theia/theia/pull/13131)
- [workspace] Create an empty workspace if no workspace is active on updateWorkspaceFolders [#13181](https://github.com/eclipse-theia/theia/pull/13181) - contributed on behalf of STMicroelectronics
+[Breaking Changes:](#breaking_changes_1.45.0)
+
+- [plugin] handling of vscode extension locations has changed: deployment dir switched to `$CONFDIR/deployedPlugin`, `.vsix` files from `$CONFDIR/extensions` are deployed automatically [#13178](https://github.com/eclipse-theia/theia/pull/13178) - Contributed on behalf of STMicroelectronics
+
## v1.44.0 - 11/30/2023
- [application-manager] added option to copy `trash` dependency to the bundle [#13112](https://github.com/eclipse-theia/theia/pull/13112)
diff --git a/packages/plugin-ext-vscode/package.json b/packages/plugin-ext-vscode/package.json
index 7451191db6c63..5723f802ce95d 100644
--- a/packages/plugin-ext-vscode/package.json
+++ b/packages/plugin-ext-vscode/package.json
@@ -16,6 +16,7 @@
"@theia/typehierarchy": "1.44.0",
"@theia/userstorage": "1.44.0",
"@theia/workspace": "1.44.0",
+ "decompress": "^4.2.1",
"filenamify": "^4.1.0"
},
"publishConfig": {
diff --git a/packages/plugin-ext-vscode/src/common/plugin-vscode-environment.ts b/packages/plugin-ext-vscode/src/common/plugin-vscode-environment.ts
index 16601eac78174..6e534f81c245b 100644
--- a/packages/plugin-ext-vscode/src/common/plugin-vscode-environment.ts
+++ b/packages/plugin-ext-vscode/src/common/plugin-vscode-environment.ts
@@ -24,13 +24,36 @@ export class PluginVSCodeEnvironment {
@inject(EnvVariablesServer)
protected readonly environments: EnvVariablesServer;
- protected _extensionsDirUri: URI | undefined;
- async getExtensionsDirUri(): Promise {
- if (!this._extensionsDirUri) {
+ protected _userExtensionsDirUri: URI | undefined;
+ protected _deployedPluginsUri: URI | undefined;
+ protected _tmpDirUri: URI | undefined;
+
+ async getUserExtensionsDirUri(): Promise {
+ if (!this._userExtensionsDirUri) {
+ const configDir = new URI(await this.environments.getConfigDirUri());
+ this._userExtensionsDirUri = configDir.resolve('extensions');
+ }
+ return this._userExtensionsDirUri;
+ }
+
+ async getDeploymentDirUri(): Promise {
+ if (!this._deployedPluginsUri) {
const configDir = new URI(await this.environments.getConfigDirUri());
- this._extensionsDirUri = configDir.resolve('extensions');
+ this._deployedPluginsUri = configDir.resolve('deployedPlugins');
}
- return this._extensionsDirUri;
+ return this._deployedPluginsUri;
}
+ async getTempDirUri(prefix?: string): Promise {
+ if (!this._tmpDirUri) {
+ const configDir: URI = new URI(await this.environments.getConfigDirUri());
+ this._tmpDirUri = configDir.resolve('tmp');
+ }
+
+ if (prefix) {
+ return this._tmpDirUri.resolve(prefix);
+ }
+
+ return this._tmpDirUri;
+ }
}
diff --git a/packages/plugin-ext-vscode/src/node/local-vsix-file-plugin-deployer-resolver.ts b/packages/plugin-ext-vscode/src/node/local-vsix-file-plugin-deployer-resolver.ts
index a151ea26395bf..5de67f2206fbb 100644
--- a/packages/plugin-ext-vscode/src/node/local-vsix-file-plugin-deployer-resolver.ts
+++ b/packages/plugin-ext-vscode/src/node/local-vsix-file-plugin-deployer-resolver.ts
@@ -14,18 +14,18 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
-import * as fs from '@theia/core/shared/fs-extra';
import * as path from 'path';
import { inject, injectable } from '@theia/core/shared/inversify';
-import { FileUri } from '@theia/core/lib/node';
import { PluginDeployerResolverContext } from '@theia/plugin-ext';
import { LocalPluginDeployerResolver } from '@theia/plugin-ext/lib/main/node/resolvers/local-plugin-deployer-resolver';
import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
import { isVSCodePluginFile } from './plugin-vscode-file-handler';
+import { existsInDeploymentDir, unpackToDeploymentDir } from './plugin-vscode-utils';
@injectable()
export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerResolver {
static LOCAL_FILE = 'local-file';
+ static FILE_EXTENSION = '.vsix';
@inject(PluginVSCodeEnvironment) protected readonly environment: PluginVSCodeEnvironment;
@@ -38,28 +38,14 @@ export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerReso
}
async resolveFromLocalPath(pluginResolverContext: PluginDeployerResolverContext, localPath: string): Promise {
- const fileName = path.basename(localPath);
- const pathInUserExtensionsDirectory = await this.ensureDiscoverability(localPath);
- pluginResolverContext.addPlugin(fileName, pathInUserExtensionsDirectory);
- }
+ const extensionId = path.basename(localPath, LocalVSIXFilePluginDeployerResolver.FILE_EXTENSION);
- /**
- * Ensures that a user-installed plugin file is transferred to the user extension folder.
- */
- protected async ensureDiscoverability(localPath: string): Promise {
- const userExtensionsDir = await this.environment.getExtensionsDirUri();
- if (!userExtensionsDir.isEqualOrParent(FileUri.create(localPath))) {
- try {
- const newPath = FileUri.fsPath(userExtensionsDir.resolve(path.basename(localPath)));
- await fs.mkdirp(FileUri.fsPath(userExtensionsDir));
- await new Promise((resolve, reject) => {
- fs.copyFile(localPath, newPath, error => error ? reject(error) : resolve());
- });
- return newPath;
- } catch (e) {
- console.warn(`Problem copying plugin at ${localPath}:`, e);
- }
+ if (await existsInDeploymentDir(this.environment, extensionId)) {
+ console.log(`[${pluginResolverContext.getOriginId()}]: Target dir already exists in plugin deployment dir`);
+ return;
}
- return localPath;
+
+ const extensionDeploymentDir = await unpackToDeploymentDir(this.environment, localPath, extensionId);
+ pluginResolverContext.addPlugin(extensionId, extensionDeploymentDir);
}
}
diff --git a/packages/plugin-ext-vscode/src/node/plugin-vscode-deployer-participant.ts b/packages/plugin-ext-vscode/src/node/plugin-vscode-deployer-participant.ts
index 5508feda6d79f..aefa68b3f7b5b 100644
--- a/packages/plugin-ext-vscode/src/node/plugin-vscode-deployer-participant.ts
+++ b/packages/plugin-ext-vscode/src/node/plugin-vscode-deployer-participant.ts
@@ -15,8 +15,11 @@
// *****************************************************************************
import { injectable, inject } from '@theia/core/shared/inversify';
+import * as fs from '@theia/core/shared/fs-extra';
+import { FileUri } from '@theia/core/lib/node';
import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
import { PluginDeployerParticipant, PluginDeployerStartContext } from '@theia/plugin-ext/lib/common/plugin-protocol';
+import { LocalVSIXFilePluginDeployerResolver } from './local-vsix-file-plugin-deployer-resolver';
@injectable()
export class PluginVSCodeDeployerParticipant implements PluginDeployerParticipant {
@@ -25,8 +28,21 @@ export class PluginVSCodeDeployerParticipant implements PluginDeployerParticipan
protected readonly environments: PluginVSCodeEnvironment;
async onWillStart(context: PluginDeployerStartContext): Promise {
- const extensionsDirUri = await this.environments.getExtensionsDirUri();
- context.userEntries.push(extensionsDirUri.withScheme('local-dir').toString());
- }
+ const extensionDeploymentDirUri = await this.environments.getDeploymentDirUri();
+ context.userEntries.push(extensionDeploymentDirUri.withScheme('local-dir').toString());
+
+ const userExtensionDirUri = await this.environments.getUserExtensionsDirUri();
+ const userExtensionDirPath = FileUri.fsPath(userExtensionDirUri);
+ if (await fs.pathExists(userExtensionDirPath)) {
+ const files = await fs.readdir(userExtensionDirPath);
+ for (const file of files) {
+ if (file.endsWith(LocalVSIXFilePluginDeployerResolver.FILE_EXTENSION)) {
+ const extensionUri = userExtensionDirUri.resolve(file).withScheme('local-file').toString();
+ console.log(`found drop-in extension "${extensionUri}"`);
+ context.userEntries.push(extensionUri);
+ }
+ }
+ }
+ }
}
diff --git a/packages/plugin-ext-vscode/src/node/plugin-vscode-directory-handler.ts b/packages/plugin-ext-vscode/src/node/plugin-vscode-directory-handler.ts
index f135aead0413e..bcbce5d3fc0cb 100644
--- a/packages/plugin-ext-vscode/src/node/plugin-vscode-directory-handler.ts
+++ b/packages/plugin-ext-vscode/src/node/plugin-vscode-directory-handler.ts
@@ -15,18 +15,16 @@
// *****************************************************************************
import * as path from 'path';
-import * as filenamify from 'filenamify';
import * as fs from '@theia/core/shared/fs-extra';
import { inject, injectable } from '@theia/core/shared/inversify';
import type { RecursivePartial, URI } from '@theia/core';
import { Deferred, firstTrue } from '@theia/core/lib/common/promise-util';
-import { getTempDirPathAsync } from '@theia/plugin-ext/lib/main/node/temp-dir-util';
import {
PluginDeployerDirectoryHandler, PluginDeployerEntry, PluginDeployerDirectoryHandlerContext,
- PluginDeployerEntryType, PluginPackage, PluginType, PluginIdentifiers
+ PluginDeployerEntryType, PluginPackage, PluginIdentifiers
} from '@theia/plugin-ext';
-import { FileUri } from '@theia/core/lib/node';
import { PluginCliContribution } from '@theia/plugin-ext/lib/main/node/plugin-cli-contribution';
+import { TMP_DIR_PREFIX } from './plugin-vscode-utils';
@injectable()
export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHandler {
@@ -35,14 +33,12 @@ export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHand
@inject(PluginCliContribution) protected readonly pluginCli: PluginCliContribution;
- constructor() {
- this.deploymentDirectory = new Deferred();
- getTempDirPathAsync('vscode-copied')
- .then(deploymentDirectoryPath => this.deploymentDirectory.resolve(FileUri.create(deploymentDirectoryPath)));
- }
-
async accept(plugin: PluginDeployerEntry): Promise {
console.debug(`Resolving "${plugin.id()}" as a VS Code extension...`);
+ if (plugin.path().startsWith(TMP_DIR_PREFIX)) {
+ // avoid adding corrupted plugins from temporary directories
+ return false;
+ }
return this.attemptResolution(plugin);
}
@@ -62,7 +58,6 @@ export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHand
}
async handle(context: PluginDeployerDirectoryHandlerContext): Promise {
- await this.copyDirectory(context);
const types: PluginDeployerEntryType[] = [];
const packageJson: PluginPackage = context.pluginEntry().getValue('package.json');
if (packageJson.browser) {
@@ -74,33 +69,6 @@ export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHand
context.pluginEntry().accept(...types);
}
- protected async copyDirectory(context: PluginDeployerDirectoryHandlerContext): Promise {
- if (this.pluginCli.copyUncompressedPlugins() && context.pluginEntry().type === PluginType.User) {
- const entry = context.pluginEntry();
- const id = entry.id();
- const pathToRestore = entry.path();
- const origin = entry.originalPath();
- const targetDir = await this.getExtensionDir(context);
- try {
- if (await fs.pathExists(targetDir) || !entry.path().startsWith(origin)) {
- console.log(`[${id}]: already copied.`);
- } else {
- console.log(`[${id}]: copying to "${targetDir}"`);
- const deploymentDirectory = await this.deploymentDirectory.promise;
- await fs.mkdirp(FileUri.fsPath(deploymentDirectory));
- await context.copy(origin, targetDir);
- entry.updatePath(targetDir);
- if (!this.deriveMetadata(entry)) {
- throw new Error('Unable to resolve plugin metadata after copying');
- }
- }
- } catch (e) {
- console.warn(`[${id}]: Error when copying.`, e);
- entry.updatePath(pathToRestore);
- }
- }
- }
-
protected async resolveFromSources(plugin: PluginDeployerEntry): Promise {
const pluginPath = plugin.path();
const pck = await this.requirePackage(pluginPath);
@@ -152,9 +120,4 @@ export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHand
return undefined;
}
}
-
- protected async getExtensionDir(context: PluginDeployerDirectoryHandlerContext): Promise {
- const deploymentDirectory = await this.deploymentDirectory.promise;
- return FileUri.fsPath(deploymentDirectory.resolve(filenamify(context.pluginEntry().id(), { replacement: '_' })));
- }
}
diff --git a/packages/plugin-ext-vscode/src/node/plugin-vscode-file-handler.ts b/packages/plugin-ext-vscode/src/node/plugin-vscode-file-handler.ts
index 23e3e3e9292d3..f3f6459aa95cc 100644
--- a/packages/plugin-ext-vscode/src/node/plugin-vscode-file-handler.ts
+++ b/packages/plugin-ext-vscode/src/node/plugin-vscode-file-handler.ts
@@ -14,33 +14,21 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
-import { PluginDeployerFileHandler, PluginDeployerEntry, PluginDeployerFileHandlerContext, PluginType } from '@theia/plugin-ext';
-import * as fs from '@theia/core/shared/fs-extra';
-import * as path from 'path';
+import { PluginDeployerFileHandler, PluginDeployerEntry, PluginDeployerFileHandlerContext } from '@theia/plugin-ext';
import * as filenamify from 'filenamify';
-import type { URI } from '@theia/core';
import { inject, injectable } from '@theia/core/shared/inversify';
-import { Deferred } from '@theia/core/lib/common/promise-util';
-import { getTempDirPathAsync } from '@theia/plugin-ext/lib/main/node/temp-dir-util';
+import * as fs from '@theia/core/shared/fs-extra';
+import { FileUri } from '@theia/core/lib/node';
import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
-import { FileUri } from '@theia/core/lib/node/file-uri';
+import { unpackToDeploymentDir } from './plugin-vscode-utils';
export const isVSCodePluginFile = (pluginPath?: string) => Boolean(pluginPath && (pluginPath.endsWith('.vsix') || pluginPath.endsWith('.tgz')));
@injectable()
export class PluginVsCodeFileHandler implements PluginDeployerFileHandler {
-
@inject(PluginVSCodeEnvironment)
protected readonly environment: PluginVSCodeEnvironment;
- private readonly systemExtensionsDirUri: Deferred;
-
- constructor() {
- this.systemExtensionsDirUri = new Deferred();
- getTempDirPathAsync('vscode-unpacked')
- .then(systemExtensionsDirPath => this.systemExtensionsDirUri.resolve(FileUri.create(systemExtensionsDirPath)));
- }
-
async accept(resolvedPlugin: PluginDeployerEntry): Promise {
return resolvedPlugin.isFile().then(file => {
if (!file) {
@@ -51,33 +39,24 @@ export class PluginVsCodeFileHandler implements PluginDeployerFileHandler {
}
async handle(context: PluginDeployerFileHandlerContext): Promise {
- const id = context.pluginEntry().id();
- const extensionDir = await this.getExtensionDir(context);
- console.log(`[${id}]: trying to decompress into "${extensionDir}"...`);
- if (context.pluginEntry().type === PluginType.User && await fs.pathExists(extensionDir)) {
- console.log(`[${id}]: already found`);
- context.pluginEntry().updatePath(extensionDir);
- return;
- }
- await this.decompress(extensionDir, context);
- console.log(`[${id}]: decompressed`);
- context.pluginEntry().updatePath(extensionDir);
- }
-
- protected async getExtensionDir(context: PluginDeployerFileHandlerContext): Promise {
- const systemExtensionsDirUri = await this.systemExtensionsDirUri.promise;
- return FileUri.fsPath(systemExtensionsDirUri.resolve(filenamify(context.pluginEntry().id(), { replacement: '_' })));
- }
-
- protected async decompress(extensionDir: string, context: PluginDeployerFileHandlerContext): Promise {
- await context.unzip(context.pluginEntry().path(), extensionDir);
- if (context.pluginEntry().path().endsWith('.tgz')) {
- const extensionPath = path.join(extensionDir, 'package');
- const vscodeNodeModulesPath = path.join(extensionPath, 'vscode_node_modules.zip');
- if (await fs.pathExists(vscodeNodeModulesPath)) {
- await context.unzip(vscodeNodeModulesPath, path.join(extensionPath, 'node_modules'));
+ const id = this.getNormalizedExtensionId(context.pluginEntry().id());
+ const extensionDeploymentDir = await unpackToDeploymentDir(this.environment, context.pluginEntry().path(), id);
+ context.pluginEntry().updatePath(extensionDeploymentDir);
+ console.log(`root path: ${context.pluginEntry().rootPath}`);
+ const originalPath = context.pluginEntry().originalPath();
+ if (originalPath && originalPath !== extensionDeploymentDir) {
+ const tempDirUri = await this.environment.getTempDirUri();
+ if (originalPath.startsWith(FileUri.fsPath(tempDirUri))) {
+ try {
+ await fs.remove(FileUri.fsPath(originalPath));
+ } catch (e) {
+ console.error(`[${id}]: failed to remove temporary files: "${originalPath}"`, e);
+ }
}
}
}
+ protected getNormalizedExtensionId(pluginId: string): string {
+ return filenamify(pluginId, { replacement: '_' }).replace(/\.vsix$/, '');
+ }
}
diff --git a/packages/plugin-ext-vscode/src/node/plugin-vscode-utils.ts b/packages/plugin-ext-vscode/src/node/plugin-vscode-utils.ts
new file mode 100644
index 0000000000000..6f6b7d6c6d60c
--- /dev/null
+++ b/packages/plugin-ext-vscode/src/node/plugin-vscode-utils.ts
@@ -0,0 +1,101 @@
+// *****************************************************************************
+// Copyright (C) 2023 STMicroelectronics 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-only WITH Classpath-exception-2.0
+// *****************************************************************************
+
+import * as decompress from 'decompress';
+import * as path from 'path';
+import * as filenamify from 'filenamify';
+import { FileUri } from '@theia/core/lib/node';
+import * as fs from '@theia/core/shared/fs-extra';
+import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
+
+export async function decompressExtension(sourcePath: string, destPath: string): Promise {
+ try {
+ await decompress(sourcePath, destPath);
+ if (sourcePath.endsWith('.tgz')) {
+ // unzip node_modules from built-in extensions, see https://github.com/eclipse-theia/theia/issues/5756
+ const extensionPath = path.join(destPath, 'package');
+ const vscodeNodeModulesPath = path.join(extensionPath, 'vscode_node_modules.zip');
+ if (await fs.pathExists(vscodeNodeModulesPath)) {
+ await decompress(vscodeNodeModulesPath, path.join(extensionPath, 'node_modules'));
+ }
+ }
+ return true;
+ } catch (error) {
+ console.error(`Failed to decompress ${sourcePath} to ${destPath}: ${error}`);
+ throw error;
+ }
+}
+
+export async function existsInDeploymentDir(env: PluginVSCodeEnvironment, extensionId: string): Promise {
+ return fs.pathExists(await getExtensionDeploymentDir(env, extensionId));
+}
+
+export const TMP_DIR_PREFIX = 'tmp-vscode-unpacked-';
+export async function unpackToDeploymentDir(env: PluginVSCodeEnvironment, sourcePath: string, extensionId: string): Promise {
+ const extensionDeploymentDir = await getExtensionDeploymentDir(env, extensionId);
+ if (await fs.pathExists(extensionDeploymentDir)) {
+ console.log(`[${extensionId}]: deployment dir "${extensionDeploymentDir}" already exists`);
+ return extensionDeploymentDir;
+ }
+
+ const tempDir = await getTempDir(env, TMP_DIR_PREFIX);
+ try {
+ console.log(`[${extensionId}]: trying to decompress "${sourcePath}" into "${tempDir}"...`);
+ if (!await decompressExtension(sourcePath, tempDir)) {
+ await fs.remove(tempDir);
+ const msg = `[${extensionId}]: decompressing "${sourcePath}" to "${tempDir}" failed`;
+ console.error(msg);
+ throw new Error(msg);
+ }
+ } catch (e) {
+ await fs.remove(tempDir);
+ const msg = `[${extensionId}]: error while decompressing "${sourcePath}" to "${tempDir}"`;
+ console.error(msg, e);
+ throw e;
+ }
+ console.log(`[${extensionId}]: decompressed to temp dir "${tempDir}"`);
+
+ try {
+ console.log(`[${extensionId}]: renaming to extension dir "${extensionDeploymentDir}"...`);
+ await fs.rename(tempDir, extensionDeploymentDir);
+ return extensionDeploymentDir;
+ } catch (e) {
+ await fs.remove(tempDir);
+ console.error(`[${extensionId}]: error while renaming "${tempDir}" to "${extensionDeploymentDir}"`, e);
+ throw e;
+ }
+}
+
+export async function getExtensionDeploymentDir(env: PluginVSCodeEnvironment, extensionId: string): Promise {
+ const deployedPluginsDirUri = await env.getDeploymentDirUri();
+ const normalizedExtensionId = filenamify(extensionId, { replacement: '_' });
+ const extensionDeploymentDirPath = FileUri.fsPath(deployedPluginsDirUri.resolve(normalizedExtensionId));
+ return extensionDeploymentDirPath;
+}
+
+export async function getTempDir(env: PluginVSCodeEnvironment, prefix: string): Promise {
+ const deploymentDirPath = FileUri.fsPath(await env.getDeploymentDirUri());
+ try {
+ if (!await fs.pathExists(deploymentDirPath)) {
+ console.log(`Creating deployment dir ${deploymentDirPath}`);
+ await fs.mkdirs(deploymentDirPath);
+ }
+ return await fs.mkdtemp(path.join(deploymentDirPath, prefix));
+ } catch (error) {
+ console.error(`Failed to create deployment dir ${deploymentDirPath}: ${error}`);
+ throw error;
+ }
+}
diff --git a/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts b/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts
index d5c9f38d7aab9..ffc6dafc83ca0 100644
--- a/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts
+++ b/packages/plugin-ext/src/main/node/plugin-deployer-contribution.ts
@@ -28,7 +28,8 @@ export class PluginDeployerContribution implements BackendApplicationContributio
@inject(PluginDeployer)
protected pluginDeployer: PluginDeployer;
- initialize(): void {
+ initialize(): Promise {
this.pluginDeployer.start().catch(error => this.logger.error('Initializing plugin deployer failed.', error));
+ return Promise.resolve();
}
}
diff --git a/packages/vsx-registry/src/node/vsx-extension-resolver.ts b/packages/vsx-registry/src/node/vsx-extension-resolver.ts
index cfe6ab3d09369..cef7c940918a7 100644
--- a/packages/vsx-registry/src/node/vsx-extension-resolver.ts
+++ b/packages/vsx-registry/src/node/vsx-extension-resolver.ts
@@ -20,6 +20,7 @@ import * as fs from '@theia/core/shared/fs-extra';
import { injectable, inject } from '@theia/core/shared/inversify';
import URI from '@theia/core/lib/common/uri';
import { PluginDeployerHandler, PluginDeployerResolver, PluginDeployerResolverContext, PluginDeployOptions, PluginIdentifiers } from '@theia/plugin-ext/lib/common/plugin-protocol';
+import { FileUri } from '@theia/core/lib/node';
import { VSCodeExtensionUri } from '@theia/plugin-ext-vscode/lib/common/plugin-vscode-uri';
import { OVSXClientProvider } from '../common/ovsx-client-provider';
import { OVSXApiFilter, VSXExtensionRaw } from '@theia/ovsx-client';
@@ -41,6 +42,8 @@ export class VSXExtensionResolver implements PluginDeployerResolver {
return !!VSCodeExtensionUri.toId(new URI(pluginId));
}
+ static readonly TEMP_DIR_PREFIX = 'vscode-download';
+
async resolve(context: PluginDeployerResolverContext, options?: PluginDeployOptions): Promise {
const id = VSCodeExtensionUri.toId(new URI(context.getOriginId()));
if (!id) {
@@ -74,16 +77,24 @@ export class VSXExtensionResolver implements PluginDeployerResolver {
return;
}
}
- const downloadPath = (await this.environment.getExtensionsDirUri()).path.fsPath();
- await fs.ensureDir(downloadPath);
- const extensionPath = path.resolve(downloadPath, path.basename(downloadUrl));
- console.log(`[${resolvedId}]: trying to download from "${downloadUrl}"...`, 'to path', downloadPath);
- if (!await this.download(downloadUrl, extensionPath)) {
+ const downloadDir = await this.getTempDir();
+ await fs.ensureDir(downloadDir);
+ const downloadedExtensionPath = path.resolve(downloadDir, path.basename(downloadUrl));
+ console.log(`[${resolvedId}]: trying to download from "${downloadUrl}"...`, 'to path', downloadDir);
+ if (!await this.download(downloadUrl, downloadedExtensionPath)) {
console.log(`[${resolvedId}]: not found`);
return;
}
- console.log(`[${resolvedId}]: downloaded to ${extensionPath}"`);
- context.addPlugin(resolvedId, extensionPath);
+ console.log(`[${resolvedId}]: downloaded to ${downloadedExtensionPath}"`);
+ context.addPlugin(resolvedId, downloadedExtensionPath);
+ }
+
+ protected async getTempDir(): Promise {
+ const tempDir = FileUri.fsPath(await this.environment.getTempDirUri(VSXExtensionResolver.TEMP_DIR_PREFIX));
+ if (!await fs.pathExists(tempDir)) {
+ await fs.mkdirs(tempDir);
+ }
+ return tempDir;
}
protected hasSameOrNewerVersion(id: string, extension: VSXExtensionRaw): string | undefined {