Add shimming for open module

This commit is contained in:
Dirk Baeumer
2019-04-10 16:23:19 +02:00
parent db4c9baa6a
commit fd5aa72bdc
2 changed files with 97 additions and 6 deletions

View File

@@ -16,7 +16,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
import { score } from 'vs/editor/common/modes/languageSelector';
import * as files from 'vs/platform/files/common/files';
import { ExtHostContext, IInitData, IMainContext, MainContext, MainThreadKeytarShape, IEnvironment } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostContext, IInitData, IMainContext, MainContext, MainThreadKeytarShape, IEnvironment, MainThreadWindowShape, MainThreadTelemetryShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostApiCommands } from 'vs/workbench/api/node/extHostApiCommands';
import { ExtHostClipboard } from 'vs/workbench/api/node/extHostClipboard';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
@@ -65,6 +65,7 @@ import { originalFSPath } from 'vs/base/common/resources';
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
import { withNullAsUndefined } from 'vs/base/common/types';
import { values } from 'vs/base/common/collections';
import { endsWith } from 'vs/base/common/strings';
export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
@@ -871,9 +872,13 @@ class Extension<T> implements vscode.Extension<T> {
}
}
interface LoadFunction {
(request: string, parent: { filename: string; }, isMain: any): any;
}
interface INodeModuleFactory {
readonly nodeModuleName: string | string[];
load(request: string, parent: { filename: string; }): any;
load(request: string, parent: { filename: string; }, isMain: any, original: LoadFunction): any;
alternaiveModuleName?(name: string): string | undefined;
}
@@ -903,7 +908,7 @@ export class NodeModuleRequireInterceptor {
if (!factories.has(request)) {
return original.apply(this, arguments);
}
return factories.get(request)!.load(request, parent);
return factories.get(request)!.load(request, parent, isMain, original);
};
}
@@ -974,7 +979,6 @@ export class KeytarNodeModuleFactory implements INodeModuleFactory {
private alternativeNames: Set<string> | undefined;
private _impl: IKeytarModule;
constructor(mainThreadKeytar: MainThreadKeytarShape, environment: IEnvironment) {
if (environment.appRoot) {
let appRoot = environment.appRoot.fsPath;
@@ -1015,7 +1019,8 @@ export class KeytarNodeModuleFactory implements INodeModuleFactory {
if (length <= 7 || !this.alternativeNames) {
return undefined;
}
if (name.match(/[\\\/]keytar$/)) {
const sep = length - 7;
if ((name.charAt(sep) === '/' || name.charAt(sep) === '\\') && endsWith(name, 'keytar')) {
name = name.replace(/\\/g, '/');
if (this.alternativeNames.has(name)) {
return 'keytar';
@@ -1024,3 +1029,82 @@ export class KeytarNodeModuleFactory implements INodeModuleFactory {
return undefined;
}
}
interface OpenOptions {
wait: boolean;
app: string | string[];
}
interface IOriginalOpen {
(target: string, options?: OpenOptions): Thenable<any>;
}
interface IOpenModule {
(target: string, options?: OpenOptions): Thenable<void>;
}
export class OpenNodeModuleFactory implements INodeModuleFactory {
public readonly nodeModuleName: string[] = ['open', 'opn'];
private _extensionId: string | undefined;
private _original: IOriginalOpen;
private _impl: IOpenModule;
constructor(mainThreadWindow: MainThreadWindowShape, private _mainThreadTelemerty: MainThreadTelemetryShape, private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>) {
this._impl = (target, options) => {
const uri: URI = URI.parse(target);
// If we have options use the original method.
if (options) {
return this.callOriginal(target, options);
}
if (uri.scheme === 'http' || uri.scheme === 'https') {
return mainThreadWindow.$openUri(uri);
} else if (uri.scheme === 'mailto') {
return mainThreadWindow.$openUri(uri);
}
return this.callOriginal(target, options);
};
}
public load(request: string, parent: { filename: string; }, isMain: any, original: LoadFunction): any {
// get extension id from filename and api for extension
const extension = this._extensionPaths.findSubstr(URI.file(parent.filename).fsPath);
if (extension) {
this._extensionId = extension.identifier.value;
this.sendShimmingTelemetry();
}
this._original = original(request, parent, isMain);
return this._impl;
}
private callOriginal(target: string, options: OpenOptions | undefined): Thenable<any> {
this.sendNoForwardTelemetry();
return this._original(target, options);
}
private sendShimmingTelemetry(): void {
if (!this._extensionId) {
return;
}
/* __GDPR__
"shimming.open" : {
"extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this._mainThreadTelemerty.$publicLog('shimming.open', { extension: this._extensionId });
}
private sendNoForwardTelemetry(): void {
if (!this._extensionId) {
return;
}
/* __GDPR__
"shimming.open.call.noForward" : {
"extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this._mainThreadTelemerty.$publicLog('shimming.open.call.noForward', { extension: this._extensionId });
}
}