提交 288445a5 编写于 作者: S Sandeep Somavarapu

#94599 Move exe based tips to new service in shared process

上级 9fdfbbc3
...@@ -13,8 +13,8 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia ...@@ -13,8 +13,8 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ParsedArgs } from 'vs/platform/environment/node/argv'; import { ParsedArgs } from 'vs/platform/environment/node/argv';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { ExtensionManagementChannel, ExtensionTipsChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
...@@ -69,6 +69,7 @@ import { IAuthenticationTokenService, AuthenticationTokenService } from 'vs/plat ...@@ -69,6 +69,7 @@ import { IAuthenticationTokenService, AuthenticationTokenService } from 'vs/plat
import { AuthenticationTokenServiceChannel } from 'vs/platform/authentication/common/authenticationIpc'; import { AuthenticationTokenServiceChannel } from 'vs/platform/authentication/common/authenticationIpc';
import { UserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSyncBackupStoreService'; import { UserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSyncBackupStoreService';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys'; import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { ExtensionTipsService } from 'vs/platform/extensionManagement/node/extensionTipsService';
export interface ISharedProcessConfiguration { export interface ISharedProcessConfiguration {
readonly machineId: string; readonly machineId: string;
...@@ -190,6 +191,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat ...@@ -190,6 +191,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
services.set(IExtensionTipsService, new SyncDescriptor(ExtensionTipsService));
services.set(ICredentialsService, new SyncDescriptor(KeytarCredentialsService)); services.set(ICredentialsService, new SyncDescriptor(KeytarCredentialsService));
services.set(IAuthenticationTokenService, new SyncDescriptor(AuthenticationTokenService)); services.set(IAuthenticationTokenService, new SyncDescriptor(AuthenticationTokenService));
...@@ -218,6 +220,10 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat ...@@ -218,6 +220,10 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService); const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService);
server.registerChannel('diagnostics', diagnosticsChannel); server.registerChannel('diagnostics', diagnosticsChannel);
const extensionTipsService = accessor.get(IExtensionTipsService);
const extensionTipsChannel = new ExtensionTipsChannel(extensionTipsService);
server.registerChannel('extensionTipsService', extensionTipsChannel);
const authTokenService = accessor.get(IAuthenticationTokenService); const authTokenService = accessor.get(IAuthenticationTokenService);
const authTokenChannel = new AuthenticationTokenServiceChannel(authTokenService); const authTokenChannel = new AuthenticationTokenServiceChannel(authTokenService);
server.registerChannel('authToken', authTokenChannel); server.registerChannel('authToken', authTokenChannel);
......
...@@ -10,6 +10,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' ...@@ -10,6 +10,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { IExtensionManifest, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions'; import { IExtensionManifest, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
import { IExeBasedExtensionTip } from 'vs/platform/product/common/productService';
export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$'; export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$';
export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN); export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);
...@@ -221,6 +222,18 @@ export interface IGlobalExtensionEnablementService { ...@@ -221,6 +222,18 @@ export interface IGlobalExtensionEnablementService {
} }
export type IExecutableBasedExtensionTip = { extensionId: string } & Omit<Omit<IExeBasedExtensionTip, 'recommendations'>, 'important'>;
export const IExtensionTipsService = createDecorator<IExtensionTipsService>('IExtensionTipsService');
export interface IExtensionTipsService {
_serviceBrand: undefined;
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]>;
}
export const ExtensionsLabel = localize('extensions', "Extensions"); export const ExtensionsLabel = localize('extensions', "Extensions");
export const ExtensionsChannelId = 'extensions'; export const ExtensionsChannelId = 'extensions';
export const PreferencesLabel = localize('preferences', "Preferences"); export const PreferencesLabel = localize('preferences', "Preferences");
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, DidUninstallExtensionEvent, IExtensionIdentifier, IGalleryMetadata, IReportedExtension, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri'; import { URI, UriComponents } from 'vs/base/common/uri';
import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc'; import { IURITransformer, DefaultURITransformer, transformAndReviveIncomingURIs } from 'vs/base/common/uriIpc';
...@@ -130,3 +130,22 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer ...@@ -130,3 +130,22 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
return Promise.resolve(this.channel.call('getExtensionsReport')); return Promise.resolve(this.channel.call('getExtensionsReport'));
} }
} }
export class ExtensionTipsChannel implements IServerChannel {
constructor(private service: IExtensionTipsService) {
}
listen(context: any, event: string): Event<any> {
throw new Error('Invalid listen');
}
call(context: any, command: string, args?: any): Promise<any> {
switch (command) {
case 'getImportantExecutableBasedTips': return this.service.getImportantExecutableBasedTips();
case 'getOtherExecutableBasedTips': return this.service.getOtherExecutableBasedTips();
}
throw new Error('Invalid call');
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { join, } from 'vs/base/common/path';
import { IProductService, IExeBasedExtensionTip } from 'vs/platform/product/common/productService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { env as processEnv } from 'vs/base/common/process';
import { INativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IFileService } from 'vs/platform/files/common/files';
import { isWindows } from 'vs/base/common/platform';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { IExtensionTipsService, IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IStringDictionary, forEach } from 'vs/base/common/collections';
export class ExtensionTipsService implements IExtensionTipsService {
_serviceBrand: any;
private readonly allImportantExecutableTips: IStringDictionary<IExeBasedExtensionTip> = {};
private readonly allOtherExecutableTips: IStringDictionary<IExeBasedExtensionTip> = {};
constructor(
@IFileService private readonly fileService: IFileService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IProductService private readonly productService: IProductService,
) {
if (this.productService.exeBasedExtensionTips) {
forEach(this.productService.exeBasedExtensionTips, ({ key, value }) => {
if (value.important) {
this.allImportantExecutableTips[key] = value;
} else {
this.allOtherExecutableTips[key] = value;
}
});
}
}
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
return this.getValidExecutableBasedExtensionTips(this.allImportantExecutableTips);
}
getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
return this.getValidExecutableBasedExtensionTips(this.allOtherExecutableTips);
}
private async getValidExecutableBasedExtensionTips(executableTips: IStringDictionary<IExeBasedExtensionTip>): Promise<IExecutableBasedExtensionTip[]> {
const result: IExecutableBasedExtensionTip[] = [];
const checkedExecutables: Map<string, boolean> = new Map<string, boolean>();
for (const exeName of Object.keys(executableTips)) {
const extensionTip = executableTips[exeName];
if (!isNonEmptyArray(extensionTip?.recommendations)) {
continue;
}
const exePaths: string[] = [];
if (isWindows) {
if (extensionTip.windowsPath) {
exePaths.push(extensionTip.windowsPath.replace('%USERPROFILE%', processEnv['USERPROFILE']!)
.replace('%ProgramFiles(x86)%', processEnv['ProgramFiles(x86)']!)
.replace('%ProgramFiles%', processEnv['ProgramFiles']!)
.replace('%APPDATA%', processEnv['APPDATA']!)
.replace('%WINDIR%', processEnv['WINDIR']!));
}
} else {
exePaths.push(join('/usr/local/bin', exeName));
exePaths.push(join((this.environmentService as INativeEnvironmentService).userHome.fsPath, exeName));
}
for (const exePath of exePaths) {
let exists = checkedExecutables.get(exePath);
if (exists === undefined) {
exists = await this.fileService.exists(URI.file(exePath));
checkedExecutables.set(exePath, exists);
}
if (exists) {
extensionTip.recommendations.forEach(recommendation => result.push({
extensionId: recommendation,
friendlyName: extensionTip.friendlyName,
exeFriendlyName: extensionTip.exeFriendlyName,
windowsPath: extensionTip.windowsPath,
}));
}
}
}
return result;
}
}
...@@ -5,11 +5,10 @@ ...@@ -5,11 +5,10 @@
import { ExtensionRecommendationsService, milliSecondsInADay, choiceNever } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService'; import { ExtensionRecommendationsService, milliSecondsInADay, choiceNever } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService';
import { IExtensionRecommendationsService, IWorkbenchExtensionEnablementService, ExtensionRecommendationReason, IExtensionRecommendation, ExtensionRecommendationSource } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IExtensionRecommendationsService, IWorkbenchExtensionEnablementService, ExtensionRecommendationReason, IExtensionRecommendation, ExtensionRecommendationSource } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { URI } from 'vs/base/common/uri'; import { basename } from 'vs/base/common/path';
import { join, basename } from 'vs/base/common/path';
import { distinct, shuffle } from 'vs/base/common/arrays'; import { distinct, shuffle } from 'vs/base/common/arrays';
import { IExeBasedExtensionTip, IProductService } from 'vs/platform/product/common/productService'; import { IProductService } from 'vs/platform/product/common/productService';
import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IModelService } from 'vs/editor/common/services/modelService'; import { IModelService } from 'vs/editor/common/services/modelService';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
...@@ -31,10 +30,8 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions'; ...@@ -31,10 +30,8 @@ import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
import Severity from 'vs/base/common/severity'; import Severity from 'vs/base/common/severity';
import { InstallRecommendedExtensionAction, ShowRecommendedExtensionsAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { InstallRecommendedExtensionAction, ShowRecommendedExtensionsAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { forEach } from 'vs/base/common/collections'; import { forEach, IStringDictionary } from 'vs/base/common/collections';
import { platform, env as processEnv } from 'vs/base/common/process';
import { isNumber } from 'vs/base/common/types'; import { isNumber } from 'vs/base/common/types';
import { INativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
interface IDynamicWorkspaceRecommendations { interface IDynamicWorkspaceRecommendations {
remoteSet: string[]; remoteSet: string[];
...@@ -43,8 +40,7 @@ interface IDynamicWorkspaceRecommendations { ...@@ -43,8 +40,7 @@ interface IDynamicWorkspaceRecommendations {
export class NativeExtensionRecommendationsService extends ExtensionRecommendationsService implements IExtensionRecommendationsService { export class NativeExtensionRecommendationsService extends ExtensionRecommendationsService implements IExtensionRecommendationsService {
private _exeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null); private _exeBasedRecommendations: { [id: string]: IExecutableBasedExtensionTip; } = Object.create(null);
private _importantExeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null);
private proactiveRecommendationsFetched: boolean = false; private proactiveRecommendationsFetched: boolean = false;
private _extensionsRecommendationsUrl: string | undefined; private _extensionsRecommendationsUrl: string | undefined;
private _dynamicWorkspaceRecommendations: string[] = []; private _dynamicWorkspaceRecommendations: string[] = [];
...@@ -71,6 +67,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati ...@@ -71,6 +67,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
@IProductService productService: IProductService, @IProductService productService: IProductService,
@IRequestService private readonly requestService: IRequestService, @IRequestService private readonly requestService: IRequestService,
@IWorkspaceTagsService private readonly workspaceTagsService: IWorkspaceTagsService, @IWorkspaceTagsService private readonly workspaceTagsService: IWorkspaceTagsService,
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
) { ) {
super(galleryService, modelService, storageService, extensionsService, extensionEnablementService, instantiationService, fileService, contextService, super(galleryService, modelService, storageService, extensionsService, extensionEnablementService, instantiationService, fileService, contextService,
configurationService, telemetryService, environmentService, extensionService, viewletService, notificationService, extensionManagementService, extensionWorkbenchService, configurationService, telemetryService, environmentService, extensionService, viewletService, notificationService, extensionManagementService, extensionWorkbenchService,
...@@ -111,14 +108,15 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati ...@@ -111,14 +108,15 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
if (!this.proactiveRecommendationsFetched) { if (!this.proactiveRecommendationsFetched) {
this.proactiveRecommendationsFetched = true; this.proactiveRecommendationsFetched = true;
// Executable based recommendations carry out a lot of file stats, delay the resolution so that the startup is not affected // Executable based recommendations carry out a lot of file stats, delay the resolution so that the startup is not affected
fetchPromise = timeout(10000).then(() => Promise.all([this.fetchDynamicWorkspaceRecommendations(), this.fetchExecutableRecommendations(false)])); fetchPromise = timeout(10000).then(() => Promise.all([this.fetchDynamicWorkspaceRecommendations(), this.fetchOtherExeBasedRecommendations()]));
} }
return fetchPromise; return fetchPromise;
} }
private async fetchImportantExeBasedRecommendation(): Promise<void> { private async fetchImportantExeBasedRecommendation(): Promise<void> {
await this.fetchExecutableRecommendations(true); const importantExectuableBasedTips = await this.extensionTipsService.getImportantExecutableBasedTips();
await this.promptForImportantExeBasedExtension(); importantExectuableBasedTips.forEach(tip => this._exeBasedRecommendations[tip.extensionId.toLowerCase()] = tip);
await this.promptForImportantExeBasedExtension(importantExectuableBasedTips);
} }
/** /**
...@@ -209,13 +207,16 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati ...@@ -209,13 +207,16 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
} }
} }
private async promptForImportantExeBasedExtension(): Promise<boolean> { private async promptForImportantExeBasedExtension(importantExectuableBasedTips: IExecutableBasedExtensionTip[]): Promise<boolean> {
let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); const importantExeBasedRecommendations: IStringDictionary<IExecutableBasedExtensionTip> = {};
importantExectuableBasedTips.forEach(tip => importantExeBasedRecommendations[tip.extensionId.toLowerCase()] = tip);
let recommendationsToSuggest = Object.keys(importantExeBasedRecommendations);
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
recommendationsToSuggest = this.filterInstalled(recommendationsToSuggest, installed, (extensionId) => { recommendationsToSuggest = this.filterInstalled(recommendationsToSuggest, installed, (extensionId) => {
const tip = this._importantExeBasedRecommendations[extensionId]; const tip = importantExeBasedRecommendations[extensionId];
/* __GDPR__ /* __GDPR__
"exeExtensionRecommendations:alreadyInstalled" : { "exeExtensionRecommendations:alreadyInstalled" : {
...@@ -232,7 +233,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati ...@@ -232,7 +233,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
} }
for (const extensionId of recommendationsToSuggest) { for (const extensionId of recommendationsToSuggest) {
const tip = this._importantExeBasedRecommendations[extensionId]; const tip = importantExeBasedRecommendations[extensionId];
/* __GDPR__ /* __GDPR__
"exeExtensionRecommendations:notInstalled" : { "exeExtensionRecommendations:notInstalled" : {
...@@ -259,7 +260,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati ...@@ -259,7 +260,7 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
} }
const extensionId = recommendationsToSuggest[0]; const extensionId = recommendationsToSuggest[0];
const tip = this._importantExeBasedRecommendations[extensionId]; const tip = importantExeBasedRecommendations[extensionId];
const message = localize('exeRecommended', "The '{0}' extension is recommended as you have {1} installed on your system.", tip.friendlyName!, tip.exeFriendlyName || basename(tip.windowsPath!)); const message = localize('exeRecommended', "The '{0}' extension is recommended as you have {1} installed on your system.", tip.friendlyName!, tip.exeFriendlyName || basename(tip.windowsPath!));
this.notificationService.prompt(Severity.Info, message, this.notificationService.prompt(Severity.Info, message,
...@@ -332,59 +333,9 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati ...@@ -332,59 +333,9 @@ export class NativeExtensionRecommendationsService extends ExtensionRecommendati
return true; return true;
} }
/** private async fetchOtherExeBasedRecommendations(): Promise<void> {
* If user has any of the tools listed in this.productService.exeBasedExtensionTips, fetch corresponding recommendations const otherExectuableBasedTips = await this.extensionTipsService.getOtherExecutableBasedTips();
*/ otherExectuableBasedTips.forEach(tip => this._exeBasedRecommendations[tip.extensionId.toLowerCase()] = tip);
private async fetchExecutableRecommendations(important: boolean): Promise<void> {
if (!this.productService.exeBasedExtensionTips) {
return;
}
const foundExecutables: Set<string> = new Set<string>();
const findExecutable = (exeName: string, tip: IExeBasedExtensionTip, path: string) => {
return this.fileService.exists(URI.file(path)).then(exists => {
if (exists && !foundExecutables.has(exeName)) {
foundExecutables.add(exeName);
(tip['recommendations'] || []).forEach(extensionId => {
if (tip.friendlyName) {
if (important) {
this._importantExeBasedRecommendations[extensionId.toLowerCase()] = tip;
}
this._exeBasedRecommendations[extensionId.toLowerCase()] = tip;
}
});
}
});
};
const promises: Promise<void>[] = [];
// Loop through recommended extensions
forEach(this.productService.exeBasedExtensionTips, entry => {
if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) {
return;
}
if (important !== !!entry.value.important) {
return;
}
const exeName = entry.key;
if (platform === 'win32') {
let windowsPath = entry.value['windowsPath'];
if (!windowsPath || typeof windowsPath !== 'string') {
return;
}
windowsPath = windowsPath.replace('%USERPROFILE%', processEnv['USERPROFILE']!)
.replace('%ProgramFiles(x86)%', processEnv['ProgramFiles(x86)']!)
.replace('%ProgramFiles%', processEnv['ProgramFiles']!)
.replace('%APPDATA%', processEnv['APPDATA']!)
.replace('%WINDIR%', processEnv['WINDIR']!);
promises.push(findExecutable(exeName, entry.value, windowsPath));
} else {
promises.push(findExecutable(exeName, entry.value, join('/usr/local/bin', exeName)));
promises.push(findExecutable(exeName, entry.value, join((this.environmentService as INativeEnvironmentService).userHome.fsPath, exeName)));
}
});
await Promise.all(promises);
} }
getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; } { getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; } {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionTipsService, IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
class WebExtensionTipsService implements IExtensionTipsService {
_serviceBrand: any;
constructor() {
}
async getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
return [];
}
async getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
return [];
}
}
registerSingleton(IExtensionTipsService, WebExtensionTipsService);
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionTipsService, IExecutableBasedExtensionTip } from 'vs/platform/extensionManagement/common/extensionManagement';
class NativeExtensionTipsService implements IExtensionTipsService {
_serviceBrand: any;
private readonly channel: IChannel;
constructor(
@ISharedProcessService sharedProcessService: ISharedProcessService
) {
this.channel = sharedProcessService.getChannel('extensionTipsService');
}
getImportantExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
return this.channel.call<IExecutableBasedExtensionTip[]>('getImportantExecutableBasedTips');
}
getOtherExecutableBasedTips(): Promise<IExecutableBasedExtensionTip[]> {
return this.channel.call<IExecutableBasedExtensionTip[]>('getOtherExecutableBasedTips');
}
}
registerSingleton(IExtensionTipsService, NativeExtensionTipsService);
...@@ -39,6 +39,7 @@ import 'vs/workbench/services/keybinding/electron-browser/keybinding.contributio ...@@ -39,6 +39,7 @@ import 'vs/workbench/services/keybinding/electron-browser/keybinding.contributio
import 'vs/workbench/services/extensions/electron-browser/extensionService'; import 'vs/workbench/services/extensions/electron-browser/extensionService';
import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService';
import 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService'; import 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService';
import 'vs/workbench/services/extensionManagement/electron-browser/extensionTipsService';
import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
import 'vs/workbench/services/telemetry/electron-browser/telemetryService'; import 'vs/workbench/services/telemetry/electron-browser/telemetryService';
import 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; import 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService';
......
...@@ -34,6 +34,7 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService'; ...@@ -34,6 +34,7 @@ import 'vs/workbench/services/textfile/browser/browserTextFileService';
import 'vs/workbench/services/keybinding/browser/keymapService'; import 'vs/workbench/services/keybinding/browser/keymapService';
import 'vs/workbench/services/extensions/browser/extensionService'; import 'vs/workbench/services/extensions/browser/extensionService';
import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService'; import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService';
import 'vs/workbench/services/extensionManagement/common/extensionTipsService';
import 'vs/workbench/services/telemetry/browser/telemetryService'; import 'vs/workbench/services/telemetry/browser/telemetryService';
import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService';
import 'vs/workbench/services/credentials/browser/credentialsService'; import 'vs/workbench/services/credentials/browser/credentialsService';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册