@theia/plugin-ext-vscode 1.70.0-next.0 → 1.70.0-next.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/node/local-vsix-file-plugin-deployer-resolver.d.ts +2 -1
- package/lib/node/local-vsix-file-plugin-deployer-resolver.d.ts.map +1 -1
- package/lib/node/local-vsix-file-plugin-deployer-resolver.js +37 -5
- package/lib/node/local-vsix-file-plugin-deployer-resolver.js.map +1 -1
- package/lib/node/plugin-vscode-utils.d.ts +11 -0
- package/lib/node/plugin-vscode-utils.d.ts.map +1 -1
- package/lib/node/plugin-vscode-utils.js +39 -0
- package/lib/node/plugin-vscode-utils.js.map +1 -1
- package/package.json +16 -16
- package/src/node/local-vsix-file-plugin-deployer-resolver.ts +42 -7
- package/src/node/plugin-vscode-utils.ts +44 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { PluginDeployerResolverContext } from '@theia/plugin-ext';
|
|
1
|
+
import { PluginDeployerResolverContext, PluginDeployerHandler } from '@theia/plugin-ext';
|
|
2
2
|
import { LocalPluginDeployerResolver } from '@theia/plugin-ext/lib/main/node/resolvers/local-plugin-deployer-resolver';
|
|
3
3
|
import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
|
|
4
4
|
export declare class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerResolver {
|
|
5
5
|
static LOCAL_FILE: string;
|
|
6
6
|
static FILE_EXTENSION: string;
|
|
7
7
|
protected readonly environment: PluginVSCodeEnvironment;
|
|
8
|
+
protected readonly pluginDeployerHandler: PluginDeployerHandler;
|
|
8
9
|
protected get supportedScheme(): string;
|
|
9
10
|
accept(pluginId: string): boolean;
|
|
10
11
|
resolveFromLocalPath(pluginResolverContext: PluginDeployerResolverContext, localPath: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-vsix-file-plugin-deployer-resolver.d.ts","sourceRoot":"","sources":["../../src/node/local-vsix-file-plugin-deployer-resolver.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"local-vsix-file-plugin-deployer-resolver.d.ts","sourceRoot":"","sources":["../../src/node/local-vsix-file-plugin-deployer-resolver.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAqB,MAAM,mBAAmB,CAAC;AAC5G,OAAO,EAAE,2BAA2B,EAAE,MAAM,0EAA0E,CAAC;AACvH,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAI9E,qBACa,mCAAoC,SAAQ,2BAA2B;IAChF,MAAM,CAAC,UAAU,SAAgB;IACjC,MAAM,CAAC,cAAc,SAAW;IAEC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,uBAAuB,CAAC;IAC1D,SAAS,CAAC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IAE/F,SAAS,KAAK,eAAe,IAAI,MAAM,CAEtC;IAEQ,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIpC,oBAAoB,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA6CrH"}
|
|
@@ -20,6 +20,7 @@ exports.LocalVSIXFilePluginDeployerResolver = void 0;
|
|
|
20
20
|
const tslib_1 = require("tslib");
|
|
21
21
|
const path = require("path");
|
|
22
22
|
const inversify_1 = require("@theia/core/shared/inversify");
|
|
23
|
+
const plugin_ext_1 = require("@theia/plugin-ext");
|
|
23
24
|
const local_plugin_deployer_resolver_1 = require("@theia/plugin-ext/lib/main/node/resolvers/local-plugin-deployer-resolver");
|
|
24
25
|
const plugin_vscode_environment_1 = require("../common/plugin-vscode-environment");
|
|
25
26
|
const plugin_vscode_file_handler_1 = require("./plugin-vscode-file-handler");
|
|
@@ -35,13 +36,40 @@ let LocalVSIXFilePluginDeployerResolver = class LocalVSIXFilePluginDeployerResol
|
|
|
35
36
|
return super.accept(pluginId) && (0, plugin_vscode_file_handler_1.isVSCodePluginFile)(pluginId);
|
|
36
37
|
}
|
|
37
38
|
async resolveFromLocalPath(pluginResolverContext, localPath) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
// Extract the true extension identity from the VSIX package.json
|
|
40
|
+
// This prevents duplicate installations when the same extension is installed from VSIX files with different filenames
|
|
41
|
+
// See: https://github.com/eclipse-theia/theia/issues/16845
|
|
42
|
+
const components = await (0, plugin_vscode_utils_1.extractExtensionIdentityFromVsix)(localPath);
|
|
43
|
+
if (!components) {
|
|
44
|
+
// Fallback to filename-based ID if package.json cannot be read
|
|
45
|
+
// This maintains backward compatibility for edge cases
|
|
46
|
+
const fallbackId = path.basename(localPath, LocalVSIXFilePluginDeployerResolver_1.FILE_EXTENSION);
|
|
47
|
+
console.warn(`[${pluginResolverContext.getOriginId()}]: Could not read extension identity from VSIX, falling back to filename: ${fallbackId}`);
|
|
48
|
+
if (await (0, plugin_vscode_utils_1.existsInDeploymentDir)(this.environment, fallbackId)) {
|
|
49
|
+
console.log(`[${pluginResolverContext.getOriginId()}]: Target dir already exists in plugin deployment dir`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const fallbackDeploymentDir = await (0, plugin_vscode_utils_1.unpackToDeploymentDir)(this.environment, localPath, fallbackId);
|
|
53
|
+
pluginResolverContext.addPlugin(fallbackId, fallbackDeploymentDir);
|
|
41
54
|
return;
|
|
42
55
|
}
|
|
43
|
-
const
|
|
44
|
-
|
|
56
|
+
const unversionedId = plugin_ext_1.PluginIdentifiers.componentsToUnversionedId(components);
|
|
57
|
+
const versionedId = plugin_ext_1.PluginIdentifiers.componentsToVersionedId(components);
|
|
58
|
+
// Check if an extension with this identity is already deployed in memory
|
|
59
|
+
const existingPlugins = this.pluginDeployerHandler.getDeployedPluginsById(unversionedId);
|
|
60
|
+
if (existingPlugins.length > 0) {
|
|
61
|
+
const existingVersions = existingPlugins.map(p => p.metadata.model.version);
|
|
62
|
+
console.log('Extension ' + unversionedId + ' (version(s): ' + existingVersions.join(', ') + ') is already installed.\n' +
|
|
63
|
+
'Uninstall the existing extension before installing a new version from VSIX.');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Check if the deployment directory already exists on disk
|
|
67
|
+
if (await (0, plugin_vscode_utils_1.existsInDeploymentDir)(this.environment, versionedId)) {
|
|
68
|
+
console.log(`[${pluginResolverContext.getOriginId()}]: Extension "${versionedId}" already exists in deployment dir`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const extensionDeploymentDir = await (0, plugin_vscode_utils_1.unpackToDeploymentDir)(this.environment, localPath, versionedId);
|
|
72
|
+
pluginResolverContext.addPlugin(versionedId, extensionDeploymentDir);
|
|
45
73
|
}
|
|
46
74
|
};
|
|
47
75
|
exports.LocalVSIXFilePluginDeployerResolver = LocalVSIXFilePluginDeployerResolver;
|
|
@@ -49,6 +77,10 @@ tslib_1.__decorate([
|
|
|
49
77
|
(0, inversify_1.inject)(plugin_vscode_environment_1.PluginVSCodeEnvironment),
|
|
50
78
|
tslib_1.__metadata("design:type", plugin_vscode_environment_1.PluginVSCodeEnvironment)
|
|
51
79
|
], LocalVSIXFilePluginDeployerResolver.prototype, "environment", void 0);
|
|
80
|
+
tslib_1.__decorate([
|
|
81
|
+
(0, inversify_1.inject)(plugin_ext_1.PluginDeployerHandler),
|
|
82
|
+
tslib_1.__metadata("design:type", Object)
|
|
83
|
+
], LocalVSIXFilePluginDeployerResolver.prototype, "pluginDeployerHandler", void 0);
|
|
52
84
|
exports.LocalVSIXFilePluginDeployerResolver = LocalVSIXFilePluginDeployerResolver = LocalVSIXFilePluginDeployerResolver_1 = tslib_1.__decorate([
|
|
53
85
|
(0, inversify_1.injectable)()
|
|
54
86
|
], LocalVSIXFilePluginDeployerResolver);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-vsix-file-plugin-deployer-resolver.js","sourceRoot":"","sources":["../../src/node/local-vsix-file-plugin-deployer-resolver.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,+CAA+C;AAC/C,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;;AAEhF,6BAA6B;AAC7B,4DAAkE;
|
|
1
|
+
{"version":3,"file":"local-vsix-file-plugin-deployer-resolver.js","sourceRoot":"","sources":["../../src/node/local-vsix-file-plugin-deployer-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
|
|
2
|
+
import { PluginIdentifiers } from '@theia/plugin-ext/lib/common/plugin-protocol';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts extension identity from a VSIX file by reading its package.json.
|
|
5
|
+
*
|
|
6
|
+
* VSIX files are ZIP archives with the extension content in an `extension/` subdirectory.
|
|
7
|
+
* This function extracts only the `extension/package.json` file to read the extension metadata.
|
|
8
|
+
*
|
|
9
|
+
* @param vsixPath Path to the VSIX file
|
|
10
|
+
* @returns PluginIdentifiers.Components (publisher?, name, version), or undefined if the package.json cannot be read or is invalid
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractExtensionIdentityFromVsix(vsixPath: string): Promise<PluginIdentifiers.Components | undefined>;
|
|
2
13
|
export declare function decompressExtension(sourcePath: string, destPath: string): Promise<boolean>;
|
|
3
14
|
export declare function existsInDeploymentDir(env: PluginVSCodeEnvironment, extensionId: string): Promise<boolean>;
|
|
4
15
|
export declare const TMP_DIR_PREFIX = "tmp-vscode-unpacked-";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-vscode-utils.d.ts","sourceRoot":"","sources":["../../src/node/plugin-vscode-utils.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin-vscode-utils.d.ts","sourceRoot":"","sources":["../../src/node/plugin-vscode-utils.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAiB,MAAM,8CAA8C,CAAC;AAEhG;;;;;;;;GAQG;AACH,wBAAsB,gCAAgC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,UAAU,GAAG,SAAS,CAAC,CAgC1H;AAED,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgBhG;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE/G;AAED,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiClI;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,uBAAuB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKlH;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY9F"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// *****************************************************************************
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.TMP_DIR_PREFIX = void 0;
|
|
19
|
+
exports.extractExtensionIdentityFromVsix = extractExtensionIdentityFromVsix;
|
|
19
20
|
exports.decompressExtension = decompressExtension;
|
|
20
21
|
exports.existsInDeploymentDir = existsInDeploymentDir;
|
|
21
22
|
exports.unpackToDeploymentDir = unpackToDeploymentDir;
|
|
@@ -26,6 +27,44 @@ const path = require("path");
|
|
|
26
27
|
const filenamify = require("filenamify");
|
|
27
28
|
const node_1 = require("@theia/core/lib/node");
|
|
28
29
|
const fs = require("@theia/core/shared/fs-extra");
|
|
30
|
+
/**
|
|
31
|
+
* Extracts extension identity from a VSIX file by reading its package.json.
|
|
32
|
+
*
|
|
33
|
+
* VSIX files are ZIP archives with the extension content in an `extension/` subdirectory.
|
|
34
|
+
* This function extracts only the `extension/package.json` file to read the extension metadata.
|
|
35
|
+
*
|
|
36
|
+
* @param vsixPath Path to the VSIX file
|
|
37
|
+
* @returns PluginIdentifiers.Components (publisher?, name, version), or undefined if the package.json cannot be read or is invalid
|
|
38
|
+
*/
|
|
39
|
+
async function extractExtensionIdentityFromVsix(vsixPath) {
|
|
40
|
+
try {
|
|
41
|
+
// Extract only the package.json file from the VSIX
|
|
42
|
+
const files = await decompress(vsixPath, {
|
|
43
|
+
filter: file => file.path === 'extension/package.json'
|
|
44
|
+
});
|
|
45
|
+
if (files.length === 0) {
|
|
46
|
+
console.warn(`[${vsixPath}]: No extension/package.json found in VSIX`);
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const packageJsonContent = files[0].data.toString('utf8');
|
|
50
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
51
|
+
// Validate required fields
|
|
52
|
+
if (!packageJson.name || !packageJson.version) {
|
|
53
|
+
console.warn(`[${vsixPath}]: Invalid package.json - missing name or version`);
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const components = {
|
|
57
|
+
publisher: packageJson.publisher,
|
|
58
|
+
name: packageJson.name,
|
|
59
|
+
version: packageJson.version
|
|
60
|
+
};
|
|
61
|
+
return components;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.error(`[${vsixPath}]: Failed to extract extension identity from VSIX`, error);
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
29
68
|
async function decompressExtension(sourcePath, destPath) {
|
|
30
69
|
try {
|
|
31
70
|
await decompress(sourcePath, destPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-vscode-utils.js","sourceRoot":"","sources":["../../src/node/plugin-vscode-utils.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;
|
|
1
|
+
{"version":3,"file":"plugin-vscode-utils.js","sourceRoot":"","sources":["../../src/node/plugin-vscode-utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/plugin-ext-vscode",
|
|
3
|
-
"version": "1.70.0-next.
|
|
3
|
+
"version": "1.70.0-next.11+fbd7ab9f7",
|
|
4
4
|
"description": "Theia - Plugin Extension for VsCode",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@theia/callhierarchy": "1.70.0-next.
|
|
7
|
-
"@theia/core": "1.70.0-next.
|
|
8
|
-
"@theia/editor": "1.70.0-next.
|
|
9
|
-
"@theia/filesystem": "1.70.0-next.
|
|
10
|
-
"@theia/monaco": "1.70.0-next.
|
|
6
|
+
"@theia/callhierarchy": "1.70.0-next.11+fbd7ab9f7",
|
|
7
|
+
"@theia/core": "1.70.0-next.11+fbd7ab9f7",
|
|
8
|
+
"@theia/editor": "1.70.0-next.11+fbd7ab9f7",
|
|
9
|
+
"@theia/filesystem": "1.70.0-next.11+fbd7ab9f7",
|
|
10
|
+
"@theia/monaco": "1.70.0-next.11+fbd7ab9f7",
|
|
11
11
|
"@theia/monaco-editor-core": "1.96.302",
|
|
12
|
-
"@theia/navigator": "1.70.0-next.
|
|
13
|
-
"@theia/outline-view": "1.70.0-next.
|
|
14
|
-
"@theia/plugin": "1.70.0-next.
|
|
15
|
-
"@theia/plugin-ext": "1.70.0-next.
|
|
16
|
-
"@theia/scm": "1.70.0-next.
|
|
17
|
-
"@theia/terminal": "1.70.0-next.
|
|
18
|
-
"@theia/typehierarchy": "1.70.0-next.
|
|
19
|
-
"@theia/userstorage": "1.70.0-next.
|
|
20
|
-
"@theia/workspace": "1.70.0-next.
|
|
12
|
+
"@theia/navigator": "1.70.0-next.11+fbd7ab9f7",
|
|
13
|
+
"@theia/outline-view": "1.70.0-next.11+fbd7ab9f7",
|
|
14
|
+
"@theia/plugin": "1.70.0-next.11+fbd7ab9f7",
|
|
15
|
+
"@theia/plugin-ext": "1.70.0-next.11+fbd7ab9f7",
|
|
16
|
+
"@theia/scm": "1.70.0-next.11+fbd7ab9f7",
|
|
17
|
+
"@theia/terminal": "1.70.0-next.11+fbd7ab9f7",
|
|
18
|
+
"@theia/typehierarchy": "1.70.0-next.11+fbd7ab9f7",
|
|
19
|
+
"@theia/userstorage": "1.70.0-next.11+fbd7ab9f7",
|
|
20
|
+
"@theia/workspace": "1.70.0-next.11+fbd7ab9f7",
|
|
21
21
|
"decompress": "^4.2.1",
|
|
22
22
|
"filenamify": "^4.1.0",
|
|
23
23
|
"tslib": "^2.6.2"
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"nyc": {
|
|
62
62
|
"extends": "../../configs/nyc.json"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "fbd7ab9f7bc4ddfdbf581582b9cfbcc6a287e3ed"
|
|
65
65
|
}
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
|
|
17
17
|
import * as path from 'path';
|
|
18
18
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
19
|
-
import { PluginDeployerResolverContext } from '@theia/plugin-ext';
|
|
19
|
+
import { PluginDeployerResolverContext, PluginDeployerHandler, PluginIdentifiers } from '@theia/plugin-ext';
|
|
20
20
|
import { LocalPluginDeployerResolver } from '@theia/plugin-ext/lib/main/node/resolvers/local-plugin-deployer-resolver';
|
|
21
21
|
import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
|
|
22
22
|
import { isVSCodePluginFile } from './plugin-vscode-file-handler';
|
|
23
|
-
import { existsInDeploymentDir, unpackToDeploymentDir } from './plugin-vscode-utils';
|
|
23
|
+
import { existsInDeploymentDir, unpackToDeploymentDir, extractExtensionIdentityFromVsix } from './plugin-vscode-utils';
|
|
24
24
|
|
|
25
25
|
@injectable()
|
|
26
26
|
export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerResolver {
|
|
@@ -28,6 +28,7 @@ export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerReso
|
|
|
28
28
|
static FILE_EXTENSION = '.vsix';
|
|
29
29
|
|
|
30
30
|
@inject(PluginVSCodeEnvironment) protected readonly environment: PluginVSCodeEnvironment;
|
|
31
|
+
@inject(PluginDeployerHandler) protected readonly pluginDeployerHandler: PluginDeployerHandler;
|
|
31
32
|
|
|
32
33
|
protected get supportedScheme(): string {
|
|
33
34
|
return LocalVSIXFilePluginDeployerResolver.LOCAL_FILE;
|
|
@@ -38,14 +39,48 @@ export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerReso
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
async resolveFromLocalPath(pluginResolverContext: PluginDeployerResolverContext, localPath: string): Promise<void> {
|
|
41
|
-
|
|
42
|
+
// Extract the true extension identity from the VSIX package.json
|
|
43
|
+
// This prevents duplicate installations when the same extension is installed from VSIX files with different filenames
|
|
44
|
+
// See: https://github.com/eclipse-theia/theia/issues/16845
|
|
45
|
+
const components = await extractExtensionIdentityFromVsix(localPath);
|
|
42
46
|
|
|
43
|
-
if (
|
|
44
|
-
|
|
47
|
+
if (!components) {
|
|
48
|
+
// Fallback to filename-based ID if package.json cannot be read
|
|
49
|
+
// This maintains backward compatibility for edge cases
|
|
50
|
+
const fallbackId = path.basename(localPath, LocalVSIXFilePluginDeployerResolver.FILE_EXTENSION);
|
|
51
|
+
console.warn(`[${pluginResolverContext.getOriginId()}]: Could not read extension identity from VSIX, falling back to filename: ${fallbackId}`);
|
|
52
|
+
|
|
53
|
+
if (await existsInDeploymentDir(this.environment, fallbackId)) {
|
|
54
|
+
console.log(`[${pluginResolverContext.getOriginId()}]: Target dir already exists in plugin deployment dir`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const fallbackDeploymentDir = await unpackToDeploymentDir(this.environment, localPath, fallbackId);
|
|
59
|
+
pluginResolverContext.addPlugin(fallbackId, fallbackDeploymentDir);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const unversionedId = PluginIdentifiers.componentsToUnversionedId(components);
|
|
64
|
+
const versionedId = PluginIdentifiers.componentsToVersionedId(components);
|
|
65
|
+
|
|
66
|
+
// Check if an extension with this identity is already deployed in memory
|
|
67
|
+
const existingPlugins = this.pluginDeployerHandler.getDeployedPluginsById(unversionedId);
|
|
68
|
+
if (existingPlugins.length > 0) {
|
|
69
|
+
const existingVersions = existingPlugins.map(p => p.metadata.model.version);
|
|
70
|
+
console.log(
|
|
71
|
+
'Extension ' + unversionedId + ' (version(s): ' + existingVersions.join(', ') + ') is already installed.\n' +
|
|
72
|
+
'Uninstall the existing extension before installing a new version from VSIX.'
|
|
73
|
+
);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check if the deployment directory already exists on disk
|
|
78
|
+
if (await existsInDeploymentDir(this.environment, versionedId)) {
|
|
79
|
+
console.log(`[${pluginResolverContext.getOriginId()}]: Extension "${versionedId}" already exists in deployment dir`);
|
|
45
80
|
return;
|
|
46
81
|
}
|
|
47
82
|
|
|
48
|
-
const extensionDeploymentDir = await unpackToDeploymentDir(this.environment, localPath,
|
|
49
|
-
pluginResolverContext.addPlugin(
|
|
83
|
+
const extensionDeploymentDir = await unpackToDeploymentDir(this.environment, localPath, versionedId);
|
|
84
|
+
pluginResolverContext.addPlugin(versionedId, extensionDeploymentDir);
|
|
50
85
|
}
|
|
51
86
|
}
|
|
@@ -20,6 +20,50 @@ import * as filenamify from 'filenamify';
|
|
|
20
20
|
import { FileUri } from '@theia/core/lib/node';
|
|
21
21
|
import * as fs from '@theia/core/shared/fs-extra';
|
|
22
22
|
import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
|
|
23
|
+
import { PluginIdentifiers, PluginPackage } from '@theia/plugin-ext/lib/common/plugin-protocol';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Extracts extension identity from a VSIX file by reading its package.json.
|
|
27
|
+
*
|
|
28
|
+
* VSIX files are ZIP archives with the extension content in an `extension/` subdirectory.
|
|
29
|
+
* This function extracts only the `extension/package.json` file to read the extension metadata.
|
|
30
|
+
*
|
|
31
|
+
* @param vsixPath Path to the VSIX file
|
|
32
|
+
* @returns PluginIdentifiers.Components (publisher?, name, version), or undefined if the package.json cannot be read or is invalid
|
|
33
|
+
*/
|
|
34
|
+
export async function extractExtensionIdentityFromVsix(vsixPath: string): Promise<PluginIdentifiers.Components | undefined> {
|
|
35
|
+
try {
|
|
36
|
+
// Extract only the package.json file from the VSIX
|
|
37
|
+
const files = await decompress(vsixPath, {
|
|
38
|
+
filter: file => file.path === 'extension/package.json'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (files.length === 0) {
|
|
42
|
+
console.warn(`[${vsixPath}]: No extension/package.json found in VSIX`);
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const packageJsonContent = files[0].data.toString('utf8');
|
|
47
|
+
const packageJson: Partial<PluginPackage> = JSON.parse(packageJsonContent);
|
|
48
|
+
|
|
49
|
+
// Validate required fields
|
|
50
|
+
if (!packageJson.name || !packageJson.version) {
|
|
51
|
+
console.warn(`[${vsixPath}]: Invalid package.json - missing name or version`);
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const components: PluginIdentifiers.Components = {
|
|
56
|
+
publisher: packageJson.publisher,
|
|
57
|
+
name: packageJson.name,
|
|
58
|
+
version: packageJson.version
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return components;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(`[${vsixPath}]: Failed to extract extension identity from VSIX`, error);
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
23
67
|
|
|
24
68
|
export async function decompressExtension(sourcePath: string, destPath: string): Promise<boolean> {
|
|
25
69
|
try {
|