Implement multiple extension directories
This commit is contained in:
parent
97167e75ff
commit
286f9a8978
|
@ -1,3 +1,36 @@
|
||||||
|
diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts
|
||||||
|
index 443e430fcd..fdd9900598 100644
|
||||||
|
--- a/src/vs/platform/environment/common/environment.ts
|
||||||
|
+++ b/src/vs/platform/environment/common/environment.ts
|
||||||
|
@@ -156,4 +156,7 @@ export interface IEnvironmentService {
|
||||||
|
|
||||||
|
webviewEndpoint?: string;
|
||||||
|
readonly webviewResourceRoot: string;
|
||||||
|
+
|
||||||
|
+ extraExtensionPaths: string[];
|
||||||
|
+ extraBuiltinExtensionPaths: string[];
|
||||||
|
}
|
||||||
|
diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts
|
||||||
|
index 55c3d8302a..b8568fa785 100644
|
||||||
|
--- a/src/vs/platform/environment/node/environmentService.ts
|
||||||
|
+++ b/src/vs/platform/environment/node/environmentService.ts
|
||||||
|
@@ -276,6 +276,16 @@ export class EnvironmentService implements IEnvironmentService {
|
||||||
|
return 'vscode-resource:';
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @memoize
|
||||||
|
+ get extraExtensionPaths(): string[] {
|
||||||
|
+ return (this._args['extra-extensions-dir'] || []).map((p: string) => parsePathArg(p, process));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @memoize
|
||||||
|
+ get extraBuiltinExtensionPaths(): string[] {
|
||||||
|
+ return (this._args['extra-builtin-extensions-dir'] || []).map((p: string) => parsePathArg(p, process));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
constructor(private _args: ParsedArgs, private _execPath: string) {
|
||||||
|
if (!process.env['VSCODE_LOGS']) {
|
||||||
|
const key = toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '');
|
||||||
diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryIpc.ts b/src/vs/platform/extensionManagement/node/extensionGalleryIpc.ts
|
diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryIpc.ts b/src/vs/platform/extensionManagement/node/extensionGalleryIpc.ts
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..ef1db87989
|
index 0000000000..ef1db87989
|
||||||
|
@ -100,6 +133,74 @@ index 0000000000..ef1db87989
|
||||||
+ return this.channel.call('getCompatibleExtension', [ id, version ]);
|
+ return this.channel.call('getCompatibleExtension', [ id, version ]);
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
|
diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts
|
||||||
|
index e09049c5b9..d93ffa527a 100644
|
||||||
|
--- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts
|
||||||
|
+++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts
|
||||||
|
@@ -724,11 +724,15 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||||
|
|
||||||
|
private scanSystemExtensions(): Promise<ILocalExtension[]> {
|
||||||
|
this.logService.trace('Started scanning system extensions');
|
||||||
|
- const systemExtensionsPromise = this.scanExtensions(this.systemExtensionsPath, ExtensionType.System)
|
||||||
|
- .then(result => {
|
||||||
|
- this.logService.trace('Scanned system extensions:', result.length);
|
||||||
|
- return result;
|
||||||
|
- });
|
||||||
|
+ const systemExtensionsPromise = Promise.all([
|
||||||
|
+ this.scanExtensions(this.systemExtensionsPath, ExtensionType.System),
|
||||||
|
+ ...this.environmentService.extraBuiltinExtensionPaths
|
||||||
|
+ .map((path) => this.scanExtensions(path, ExtensionType.System))
|
||||||
|
+ ]).then((results) => {
|
||||||
|
+ const result = results.reduce((flat, current) => flat.concat(current), []);
|
||||||
|
+ this.logService.info('Scanned system extensions:', result.length);
|
||||||
|
+ return result;
|
||||||
|
+ });
|
||||||
|
if (this.environmentService.isBuilt) {
|
||||||
|
return systemExtensionsPromise;
|
||||||
|
}
|
||||||
|
@@ -750,9 +754,16 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||||
|
.then(([systemExtensions, devSystemExtensions]) => [...systemExtensions, ...devSystemExtensions]);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ private scanAllUserExtensions(folderName: string, type: ExtensionType): Promise<ILocalExtension[]> {
|
||||||
|
+ return Promise.all([
|
||||||
|
+ this.scanExtensions(folderName, type),
|
||||||
|
+ ...this.environmentService.extraExtensionPaths.map((p) => this.scanExtensions(p, ExtensionType.User))
|
||||||
|
+ ]).then((results) => results.reduce((flat, current) => flat.concat(current), []));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
private scanUserExtensions(excludeOutdated: boolean): Promise<ILocalExtension[]> {
|
||||||
|
this.logService.trace('Started scanning user extensions');
|
||||||
|
- return Promise.all([this.getUninstalledExtensions(), this.scanExtensions(this.extensionsPath, ExtensionType.User)])
|
||||||
|
+ return Promise.all([this.getUninstalledExtensions(), this.scanAllUserExtensions(this.extensionsPath, ExtensionType.User)])
|
||||||
|
.then(([uninstalled, extensions]) => {
|
||||||
|
extensions = extensions.filter(e => !uninstalled[new ExtensionIdentifierWithVersion(e.identifier, e.manifest.version).key()]);
|
||||||
|
if (excludeOutdated) {
|
||||||
|
@@ -805,7 +816,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||||
|
|
||||||
|
private async removeUninstalledExtensions(): Promise<void> {
|
||||||
|
const uninstalled = await this.getUninstalledExtensions();
|
||||||
|
- const extensions = await this.scanExtensions(this.extensionsPath, ExtensionType.User); // All user extensions
|
||||||
|
+ const extensions = await this.scanAllUserExtensions(this.extensionsPath, ExtensionType.User); // All user extensions
|
||||||
|
const installed: Set<string> = new Set<string>();
|
||||||
|
for (const e of extensions) {
|
||||||
|
if (!uninstalled[new ExtensionIdentifierWithVersion(e.identifier, e.manifest.version).key()]) {
|
||||||
|
@@ -824,7 +835,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeOutdatedExtensions(): Promise<void> {
|
||||||
|
- return this.scanExtensions(this.extensionsPath, ExtensionType.User) // All user extensions
|
||||||
|
+ return this.scanAllUserExtensions(this.extensionsPath, ExtensionType.User) // All user extensions
|
||||||
|
.then(extensions => {
|
||||||
|
const toRemove: ILocalExtension[] = [];
|
||||||
|
|
||||||
|
@@ -982,4 +993,4 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||||
|
*/
|
||||||
|
this.telemetryService.publicLog(eventName, assign(extensionData, { success: !error, duration, errorcode }));
|
||||||
|
}
|
||||||
|
-}
|
||||||
|
\ No newline at end of file
|
||||||
|
+}
|
||||||
diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts
|
diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts
|
||||||
index 1986fb6642..7c66b644f2 100644
|
index 1986fb6642..7c66b644f2 100644
|
||||||
--- a/src/vs/workbench/browser/web.main.ts
|
--- a/src/vs/workbench/browser/web.main.ts
|
||||||
|
@ -796,6 +897,19 @@ index c08a6e37c1..31640d7e66 100644
|
||||||
}
|
}
|
||||||
return this._extensionAllowedBadgeProviders;
|
return this._extensionAllowedBadgeProviders;
|
||||||
}
|
}
|
||||||
|
diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts
|
||||||
|
index 3525569601..a91a5fce7d 100644
|
||||||
|
--- a/src/vs/workbench/services/environment/browser/environmentService.ts
|
||||||
|
+++ b/src/vs/workbench/services/environment/browser/environmentService.ts
|
||||||
|
@@ -136,6 +136,8 @@ export class BrowserWorkbenchEnvironmentService implements IEnvironmentService {
|
||||||
|
driverHandle?: string;
|
||||||
|
driverVerbose: boolean;
|
||||||
|
webviewEndpoint?: string;
|
||||||
|
+ extraExtensionPaths: string[];
|
||||||
|
+ extraBuiltinExtensionPaths: string[];
|
||||||
|
|
||||||
|
get webviewResourceRoot(): string {
|
||||||
|
return this.webviewEndpoint ? this.webviewEndpoint + '/vscode-resource' : 'vscode-resource:';
|
||||||
diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts
|
diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts
|
||||||
index 611ab9aec9..4e4bea89be 100644
|
index 611ab9aec9..4e4bea89be 100644
|
||||||
--- a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts
|
--- a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
import { getPathFromAmdModule } from "vs/base/common/amd";
|
|
||||||
import { VSBuffer } from "vs/base/common/buffer";
|
import { VSBuffer } from "vs/base/common/buffer";
|
||||||
import { Emitter, Event } from "vs/base/common/event";
|
import { Emitter, Event } from "vs/base/common/event";
|
||||||
import { IDisposable } from "vs/base/common/lifecycle";
|
import { IDisposable } from "vs/base/common/lifecycle";
|
||||||
|
@ -207,36 +206,36 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async scanExtensions(locale: string): Promise<IExtensionDescription[]> {
|
private async scanExtensions(locale: string): Promise<IExtensionDescription[]> {
|
||||||
const root = getPathFromAmdModule(require, "");
|
|
||||||
|
|
||||||
const translations = {}; // TODO: translations
|
const translations = {}; // TODO: translations
|
||||||
|
|
||||||
// TODO: there is also this.environment.extensionDevelopmentLocationURI to look into.
|
const scanMultiple = (isBuiltin: boolean, isUnderDevelopment: boolean, paths: string[]): Promise<IExtensionDescription[][]> => {
|
||||||
const scanBuiltin = async (): Promise<IExtensionDescription[]> => {
|
return Promise.all(paths.map((path) => {
|
||||||
const input = new ExtensionScannerInput(
|
return ExtensionScanner.scanExtensions(new ExtensionScannerInput(
|
||||||
pkg.version, product.commit, locale, !!process.env.VSCODE_DEV,
|
pkg.version,
|
||||||
path.resolve(root, "../extensions"),
|
product.commit,
|
||||||
true,
|
locale,
|
||||||
false,
|
!!process.env.VSCODE_DEV,
|
||||||
|
path,
|
||||||
|
isBuiltin,
|
||||||
|
isUnderDevelopment,
|
||||||
translations,
|
translations,
|
||||||
);
|
), this.log);
|
||||||
const extensions = await ExtensionScanner.scanExtensions(input, this.log);
|
}));
|
||||||
// TODO: there is more to do if process.env.VSCODE_DEV is true.
|
|
||||||
return extensions;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const scanInstalled = async (): Promise<IExtensionDescription[]> => {
|
const scanBuiltin = async (): Promise<IExtensionDescription[][]> => {
|
||||||
const input = new ExtensionScannerInput(
|
return scanMultiple(true, false, [this.environment.builtinExtensionsPath, ...this.environment.extraBuiltinExtensionPaths]);
|
||||||
pkg.version, product.commit, locale, !!process.env.VSCODE_DEV,
|
};
|
||||||
this.environment.extensionsPath, false, true, translations,
|
|
||||||
);
|
const scanInstalled = async (): Promise<IExtensionDescription[][]> => {
|
||||||
return ExtensionScanner.scanExtensions(input, this.log);
|
return scanMultiple(false, true, [this.environment.extensionsPath, ...this.environment.extraExtensionPaths]);
|
||||||
};
|
};
|
||||||
|
|
||||||
return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => {
|
return Promise.all([scanBuiltin(), scanInstalled()]).then((allExtensions) => {
|
||||||
// It's possible to get duplicates.
|
// It's possible to get duplicates.
|
||||||
const uniqueExtensions = new Map<string, IExtensionDescription>();
|
const uniqueExtensions = new Map<string, IExtensionDescription>();
|
||||||
allExtensions.forEach((extensions) => {
|
allExtensions.forEach((multipleExtensions) => {
|
||||||
|
multipleExtensions.forEach((extensions) => {
|
||||||
extensions.forEach((extension) => {
|
extensions.forEach((extension) => {
|
||||||
const id = ExtensionIdentifier.toKey(extension.identifier);
|
const id = ExtensionIdentifier.toKey(extension.identifier);
|
||||||
if (uniqueExtensions.has(id)) {
|
if (uniqueExtensions.has(id)) {
|
||||||
|
@ -249,6 +248,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
|
||||||
uniqueExtensions.set(id, extension);
|
uniqueExtensions.set(id, extension);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const finalExtensions = <IExtensionDescription[]>[];
|
const finalExtensions = <IExtensionDescription[]>[];
|
||||||
uniqueExtensions.forEach((e) => finalExtensions.push(e));
|
uniqueExtensions.forEach((e) => finalExtensions.push(e));
|
||||||
|
|
|
@ -74,6 +74,11 @@ interface IMainCli {
|
||||||
|
|
||||||
const main = async (): Promise<void> => {
|
const main = async (): Promise<void> => {
|
||||||
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args;
|
const args = validatePaths(parseMainProcessArgv(process.argv)) as Args;
|
||||||
|
["extra-extensions-dir", "extra-builtin-extensions-dir"].forEach((key) => {
|
||||||
|
if (typeof args[key] === "string") {
|
||||||
|
args[key] = [args[key]];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!product.extensionsGallery) {
|
if (!product.extensionsGallery) {
|
||||||
product.extensionsGallery = {
|
product.extensionsGallery = {
|
||||||
|
|
Loading…
Reference in New Issue