Implement multiple extension directories

This commit is contained in:
Asher 2019-07-12 16:39:38 -05:00
parent 97167e75ff
commit 286f9a8978
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
3 changed files with 151 additions and 32 deletions

View File

@ -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

View File

@ -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));

View File

@ -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 = {