diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 3687285e230..64546caf253 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -99,7 +99,7 @@ import { DiskFileSystemProviderClient, LOCAL_FILE_SYSTEM_CHANNEL_NAME } from 'vs import { InspectProfilingService as V8InspectProfilingService } from 'vs/platform/profiling/node/profilingService'; import { IV8InspectProfilingService } from 'vs/platform/profiling/common/profiling'; import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService'; -import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService'; +import { ExtensionsScannerService } from 'vs/platform/extensionManagement/electron-sandbox/extensionsScannerService'; class SharedProcessMain extends Disposable { diff --git a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts index f5ac106af57..83037b7d795 100644 --- a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts +++ b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts @@ -12,6 +12,7 @@ import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import { Disposable } from 'vs/base/common/lifecycle'; import { FileAccess, Schemas } from 'vs/base/common/network'; import * as path from 'vs/base/common/path'; +import * as platform from 'vs/base/common/platform'; import { basename, isEqualOrParent, joinPath } from 'vs/base/common/resources'; import * as semver from 'vs/base/common/semver/semver'; import Severity from 'vs/base/common/severity'; @@ -72,7 +73,7 @@ export namespace Translations { } } -export interface NlsConfiguration { +interface NlsConfiguration { readonly devMode: boolean; readonly locale: string | undefined; readonly pseudo: boolean; @@ -100,10 +101,10 @@ interface IBuiltInExtensionControl { export type ScanOptions = { readonly includeInvalid?: boolean; - readonly nlsConfiguration?: NlsConfiguration; readonly includeAllVersions?: boolean; readonly includeUninstalled?: boolean; readonly checkControlFile?: boolean; + readonly language?: string; }; export const IExtensionsScannerService = createDecorator('IExtensionsScannerService'); @@ -132,10 +133,11 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem abstract readonly systemExtensionsLocation: URI; abstract readonly userExtensionsLocation: URI; protected abstract readonly extensionsControlLocation: URI; + protected abstract getTranslations(language: string): Promise; constructor( - @IFileService private readonly fileService: IFileService, - @ILogService private readonly logService: ILogService, + @IFileService protected readonly fileService: IFileService, + @ILogService protected readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IProductService private readonly productService: IProductService, ) { @@ -160,20 +162,22 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem } async scanSystemExtensions(scanOptions: ScanOptions): Promise { + const nlsConfiguration = await this.getNlsConfiguration(scanOptions.language); const promises: Promise[] = []; - promises.push(this.scanDefaultSystemExtensions()); - promises.push(this.scanDevSystemExtensions(scanOptions)); + promises.push(this.scanDefaultSystemExtensions(nlsConfiguration)); + promises.push(this.scanDevSystemExtensions(nlsConfiguration, !!scanOptions.checkControlFile)); const [defaultSystemExtensions, devSystemExtensions] = await Promise.all(promises); return this.applyScanOptions([...defaultSystemExtensions, ...devSystemExtensions], scanOptions, false); } async scanUserExtensions(scanOptions: ScanOptions): Promise { this.logService.trace('Started scanning user extensions'); + const nlsConfiguration = await this.getNlsConfiguration(scanOptions.language); let extensions: IRelaxedScannedExtension[]; if (scanOptions.includeUninstalled) { - extensions = await this.scanFromUserExtensionsLocation(); + extensions = await this.scanFromUserExtensionsLocation(nlsConfiguration); } else { - let [uninstalled, scannedExtensions] = await Promise.all([this.getUninstalledExtensions(), this.scanFromUserExtensionsLocation()]); + let [uninstalled, scannedExtensions] = await Promise.all([this.getUninstalledExtensions(), this.scanFromUserExtensionsLocation(nlsConfiguration)]); extensions = scannedExtensions.filter(e => !uninstalled[ExtensionKey.create(e).toString()]); } extensions = await this.applyScanOptions(extensions, scanOptions, true); @@ -183,8 +187,9 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem async scanExtensionsUnderDevelopment(scanOptions: ScanOptions): Promise { if (this.environmentService.isExtensionDevelopment && this.environmentService.extensionDevelopmentLocationURI) { + const nlsConfiguration = await this.getNlsConfiguration(scanOptions.language); const extensions = (await Promise.all(this.environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file) - .map(async extensionDevelopmentLocationURI => await this.doScanOneOrMultipleExtensions(extensionDevelopmentLocationURI, ExtensionType.User)))) + .map(async extensionDevelopmentLocationURI => await this.doScanOneOrMultipleExtensions(extensionDevelopmentLocationURI, ExtensionType.User, nlsConfiguration)))) .flat(); return this.applyScanOptions(extensions, scanOptions, true); } @@ -192,19 +197,21 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem } async scanExistingExtension(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise { - const extension = await this.scanExtension(extensionLocation, extensionType); + const nlsConfiguration = await this.getNlsConfiguration(scanOptions.language); + const extension = await this.scanExtension(extensionLocation, extensionType, nlsConfiguration); if (!extension) { return null; } if (!scanOptions.includeInvalid && !extension.isValid) { return null; } - extension.manifest = await this.localizeManifest(extension.location, extension.manifest, scanOptions.nlsConfiguration); + extension.manifest = (await this.localizeExtensions([extension], scanOptions.language))[0].manifest; return extension; } async scanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType, scanOptions: ScanOptions): Promise { - const extensions = await this.doScanOneOrMultipleExtensions(extensionLocation, extensionType); + const nlsConfiguration = await this.getNlsConfiguration(scanOptions.language); + const extensions = await this.doScanOneOrMultipleExtensions(extensionLocation, extensionType, nlsConfiguration); return this.applyScanOptions(extensions, scanOptions, true); } @@ -228,7 +235,6 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem if (!scanOptions.includeInvalid) { extensions = extensions.filter(extension => extension.isValid); } - extensions = await this.localizeExtensions(extensions, scanOptions.nlsConfiguration); return extensions.sort((a, b) => { const aLastSegment = path.basename(a.location.fsPath); const bLastSegment = path.basename(b.location.fsPath); @@ -242,13 +248,13 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem }); } - private async doScanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType): Promise { + private async doScanOneOrMultipleExtensions(extensionLocation: URI, extensionType: ExtensionType, nlsConfiguration: NlsConfiguration): Promise { try { if (await this.fileService.exists(joinPath(extensionLocation, 'package.json'))) { - const extension = await this.scanExtension(extensionLocation, extensionType); + const extension = await this.scanExtension(extensionLocation, extensionType, nlsConfiguration); return extension ? [extension] : []; } else { - return await this.scanExtensionsInLocation(extensionLocation, extensionType); + return await this.scanExtensionsInLocation(extensionLocation, extensionType, nlsConfiguration); } } catch (error) { this.logService.error(`Error scanning extensions at ${extensionLocation.path}:`, getErrorMessage(error)); @@ -256,7 +262,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem } } - private async scanExtensionsInLocation(location: URI, preferredType: ExtensionType): Promise { + private async scanExtensionsInLocation(location: URI, preferredType: ExtensionType, nlsConfiguration: NlsConfiguration): Promise { const stat = await this.fileService.resolve(location); if (stat.children) { const extensions = await Promise.all( @@ -265,28 +271,28 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem if (isEqualOrParent(c.resource, this.userExtensionsLocation) && basename(c.resource).indexOf('.') === 0) { // Do not consider user extension folder starting with `.` return null; } - return this.scanExtension(c.resource, preferredType); + return this.scanExtension(c.resource, preferredType, nlsConfiguration); })); return coalesce(extensions); } return []; } - private async scanDefaultSystemExtensions(): Promise { + private async scanDefaultSystemExtensions(nlsConfiguration: NlsConfiguration): Promise { this.logService.trace('Started scanning system extensions'); - const result = await this.scanExtensionsInLocation(this.systemExtensionsLocation, ExtensionType.System); + const result = await this.scanExtensionsInLocation(this.systemExtensionsLocation, ExtensionType.System, nlsConfiguration); this.logService.trace('Scanned system extensions:', result.length); return result; } - private async scanDevSystemExtensions(scanOptions: ScanOptions): Promise { + private async scanDevSystemExtensions(nlsConfiguration: NlsConfiguration, checkControlFile: boolean): Promise { const devSystemExtensionsList = this.environmentService.isBuilt ? [] : this.productService.builtInExtensions; if (!devSystemExtensionsList?.length) { return []; } this.logService.trace('Started scanning dev system extensions'); - const builtinExtensionControl = scanOptions.checkControlFile ? await this.getBuiltInExtensionControl() : {}; + const builtinExtensionControl = checkControlFile ? await this.getBuiltInExtensionControl() : {}; const devSystemExtensionsLocations: URI[] = []; for (const extension of devSystemExtensionsList) { const controlState = builtinExtensionControl[extension.name] || 'marketplace'; @@ -301,7 +307,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem break; } } - const result = await Promise.all(devSystemExtensionsLocations.map(location => this.scanExtension(location, ExtensionType.System))); + const result = await Promise.all(devSystemExtensionsLocations.map(location => this.scanExtension(location, ExtensionType.System, nlsConfiguration))); this.logService.trace('Scanned dev system extensions:', result.length); return coalesce(result); } @@ -315,8 +321,8 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem } } - private async scanFromUserExtensionsLocation(): Promise { - return this.scanExtensionsInLocation(this.userExtensionsLocation, ExtensionType.User); + private async scanFromUserExtensionsLocation(nlsConfiguration: NlsConfiguration): Promise { + return this.scanExtensionsInLocation(this.userExtensionsLocation, ExtensionType.User, nlsConfiguration); } private dedupExtensions(extensions: IRelaxedScannedExtension[], targetPlatform: TargetPlatform, pickLatest: boolean): IRelaxedScannedExtension[] { @@ -367,9 +373,9 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem return {}; } - private async scanExtension(extensionLocation: URI, preferredType: ExtensionType): Promise { + private async scanExtension(extensionLocation: URI, preferredType: ExtensionType, nlsConfiguration: NlsConfiguration): Promise { try { - const manifest = await this.scanExtensionManifest(extensionLocation); + let manifest = await this.scanExtensionManifest(extensionLocation); if (manifest) { // allow publisher to be undefined to make the initial extension authoring experience smoother if (!manifest.publisher) { @@ -388,6 +394,7 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem this.logService.error(this.formatMessage(extensionLocation, message)); } } + manifest = await this.translateManifest(extensionLocation, manifest, nlsConfiguration); return { type, identifier, @@ -438,10 +445,11 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem return manifest; } - private async localizeExtensions(extensions: IRelaxedScannedExtension[], nlsConfig?: NlsConfiguration): Promise { + private async localizeExtensions(extensions: IRelaxedScannedExtension[], language: string | undefined): Promise { + const nlsConfig = await this.getNlsConfiguration(language); await Promise.all(extensions.map(async extension => { try { - extension.manifest = await this.localizeManifest(extension.location, extension.manifest, nlsConfig); + extension.manifest = await this.translateManifest(extension.location, extension.manifest, nlsConfig); } catch (error) { /* Ignore Error */ } @@ -449,7 +457,18 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem return extensions; } - private async localizeManifest(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfig?: NlsConfiguration): Promise { + private async getNlsConfiguration(language: string | undefined): Promise { + language = language ?? platform.language; + const translations = await this.getTranslations(language); + return { + locale: language, + pseudo: language === 'pseudo', + translations, + devMode: !this.environmentService.isBuilt + }; + } + + private async translateManifest(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfig: NlsConfiguration): Promise { const localizedMessages = await this.getLocalizedMessages(extensionLocation, extensionManifest, nlsConfig); if (localizedMessages) { try { @@ -474,12 +493,8 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem return extensionManifest; } - private async getLocalizedMessages(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfig?: NlsConfiguration): Promise { + private async getLocalizedMessages(extensionLocation: URI, extensionManifest: IExtensionManifest, nlsConfig: NlsConfiguration): Promise { const defaultPackageNLS = joinPath(extensionLocation, 'package.nls.json'); - if (!nlsConfig) { - return { values: undefined, default: defaultPackageNLS }; - } - const reportErrors = (localized: URI | null, errors: ParseError[]): void => { errors.forEach((error) => { this.logService.error(this.formatMessage(extensionLocation, localize('jsonsParseReportErrors', "Failed to parse {0}: {1}.", localized?.path, getParseErrorMessage(error.error)))); diff --git a/src/vs/platform/extensionManagement/node/extensionsScannerService.ts b/src/vs/platform/extensionManagement/electron-sandbox/extensionsScannerService.ts similarity index 73% rename from src/vs/platform/extensionManagement/node/extensionsScannerService.ts rename to src/vs/platform/extensionManagement/electron-sandbox/extensionsScannerService.ts index 20ff1608038..273c8a35e6b 100644 --- a/src/vs/platform/extensionManagement/node/extensionsScannerService.ts +++ b/src/vs/platform/extensionManagement/electron-sandbox/extensionsScannerService.ts @@ -6,11 +6,12 @@ import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { AbstractExtensionsScannerService, IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService'; +import { AbstractExtensionsScannerService, IExtensionsScannerService, Translations } from 'vs/platform/extensionManagement/common/extensionsScannerService'; import { IFileService } from 'vs/platform/files/common/files'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; +import * as platform from 'vs/base/common/platform'; export class ExtensionsScannerService extends AbstractExtensionsScannerService implements IExtensionsScannerService { @@ -18,6 +19,8 @@ export class ExtensionsScannerService extends AbstractExtensionsScannerService i readonly userExtensionsLocation: URI; protected readonly extensionsControlLocation: URI; + private readonly translationsPromise: Promise; + constructor( @IFileService fileService: IFileService, @ILogService logService: ILogService, @@ -28,6 +31,19 @@ export class ExtensionsScannerService extends AbstractExtensionsScannerService i this.systemExtensionsLocation = URI.file(environmentService.builtinExtensionsPath); this.userExtensionsLocation = URI.file(environmentService.extensionsPath); this.extensionsControlLocation = joinPath(environmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json'); + this.translationsPromise = (async () => { + if (platform.translationsConfigFile) { + try { + const content = await this.fileService.readFile(URI.file(platform.translationsConfigFile)); + return JSON.parse(content.value.toString()); + } catch (err) { /* Ignore Error */ } + } + return Object.create(null); + })(); + } + + protected getTranslations(language: string): Promise { + return this.translationsPromise; } } diff --git a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts index 938adcbd388..a814ecfc83c 100644 --- a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts +++ b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts @@ -9,8 +9,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { dirname, joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IExtensionsScannerService, IScannedExtensionManifest } from 'vs/platform/extensionManagement/common/extensionsScannerService'; -import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService'; +import { AbstractExtensionsScannerService, IExtensionsScannerService, IScannedExtensionManifest, Translations } from 'vs/platform/extensionManagement/common/extensionsScannerService'; import { ExtensionType, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { FileService } from 'vs/platform/files/common/fileService'; @@ -19,6 +18,32 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; +let translations: Translations = Object.create(null); + +class ExtensionsScannerService extends AbstractExtensionsScannerService implements IExtensionsScannerService { + + readonly systemExtensionsLocation: URI; + readonly userExtensionsLocation: URI; + protected readonly extensionsControlLocation: URI; + + constructor( + @IFileService fileService: IFileService, + @ILogService logService: ILogService, + @INativeEnvironmentService nativeEnvironmentService: INativeEnvironmentService, + @IProductService productService: IProductService, + ) { + super(fileService, logService, nativeEnvironmentService, productService); + this.systemExtensionsLocation = URI.file(nativeEnvironmentService.builtinExtensionsPath); + this.userExtensionsLocation = URI.file(nativeEnvironmentService.extensionsPath); + this.extensionsControlLocation = joinPath(nativeEnvironmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json'); + } + + protected async getTranslations(language: string): Promise { + return translations; + } + +} + const ROOT = URI.file(tmpdir()); suite('NativeExtensionsScanerService Test', () => { @@ -27,6 +52,7 @@ suite('NativeExtensionsScanerService Test', () => { let instantiationService: TestInstantiationService; setup(async () => { + translations = {}; instantiationService = new TestInstantiationService(); const logService = new NullLogService(); const fileService = disposables.add(new FileService(logService)); @@ -258,7 +284,8 @@ suite('NativeExtensionsScanerService Test', () => { await instantiationService.get(IFileService).writeFile(nlsLocation, VSBuffer.fromString(JSON.stringify({ contents: { package: { displayName: 'Hello World EN' } } }))); const testObject: IExtensionsScannerService = instantiationService.createInstance(ExtensionsScannerService); - const actual = await testObject.scanUserExtensions({ nlsConfiguration: { locale: 'en', devMode: false, pseudo: false, translations: { 'pub.name': nlsLocation.fsPath } } }); + translations = { 'pub.name': nlsLocation.fsPath }; + const actual = await testObject.scanUserExtensions({ language: 'en' }); assert.deepStrictEqual(actual.length, 1); assert.deepStrictEqual(actual[0].identifier, { id: 'pub.name' }); @@ -272,7 +299,8 @@ suite('NativeExtensionsScanerService Test', () => { await instantiationService.get(IFileService).writeFile(nlsLocation, VSBuffer.fromString(JSON.stringify({ contents: { package: { displayName: 'Hello World EN' } } }))); const testObject: IExtensionsScannerService = instantiationService.createInstance(ExtensionsScannerService); - const actual = await testObject.scanUserExtensions({ nlsConfiguration: { locale: 'en', devMode: false, pseudo: false, translations: { 'pub.name2': nlsLocation.fsPath } } }); + translations = { 'pub.name2': nlsLocation.fsPath }; + const actual = await testObject.scanUserExtensions({ language: 'en' }); assert.deepStrictEqual(actual.length, 1); assert.deepStrictEqual(actual[0].identifier, { id: 'pub.name' }); diff --git a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionsScannerService.ts b/src/vs/server/node/extensionsScannerService.ts similarity index 51% rename from src/vs/workbench/services/extensionManagement/electron-sandbox/extensionsScannerService.ts rename to src/vs/server/node/extensionsScannerService.ts index 5fa1a022246..fa340e24a45 100644 --- a/src/vs/workbench/services/extensionManagement/electron-sandbox/extensionsScannerService.ts +++ b/src/vs/server/node/extensionsScannerService.ts @@ -6,12 +6,11 @@ import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; -import { AbstractExtensionsScannerService, IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService'; +import { AbstractExtensionsScannerService, IExtensionsScannerService, Translations } from 'vs/platform/extensionManagement/common/extensionsScannerService'; import { IFileService } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; import { IProductService } from 'vs/platform/product/common/productService'; -import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; +import { getNLSConfiguration, InternalNLSConfiguration } from 'vs/server/node/remoteLanguagePacks'; export class ExtensionsScannerService extends AbstractExtensionsScannerService implements IExtensionsScannerService { @@ -22,15 +21,24 @@ export class ExtensionsScannerService extends AbstractExtensionsScannerService i constructor( @IFileService fileService: IFileService, @ILogService logService: ILogService, - @INativeEnvironmentService environmentService: INativeWorkbenchEnvironmentService, + @INativeEnvironmentService private readonly nativeEnvironmentService: INativeEnvironmentService, @IProductService productService: IProductService, ) { - super(fileService, logService, environmentService, productService); - this.systemExtensionsLocation = URI.file(environmentService.builtinExtensionsPath); - this.userExtensionsLocation = URI.file(environmentService.extensionsPath); - this.extensionsControlLocation = joinPath(environmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json'); + super(fileService, logService, nativeEnvironmentService, productService); + this.systemExtensionsLocation = URI.file(nativeEnvironmentService.builtinExtensionsPath); + this.userExtensionsLocation = URI.file(nativeEnvironmentService.extensionsPath); + this.extensionsControlLocation = joinPath(nativeEnvironmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json'); + } + + protected async getTranslations(language: string): Promise { + const config = await getNLSConfiguration(language, this.nativeEnvironmentService.userDataPath); + if (InternalNLSConfiguration.is(config)) { + try { + const content = await this.fileService.readFile(URI.file(config._translationsConfigFile)); + return JSON.parse(content.value.toString()); + } catch (err) { /* Ignore error */ } + } + return Object.create(null); } } - -registerSingleton(IExtensionsScannerService, ExtensionsScannerService); diff --git a/src/vs/server/node/remoteAgentEnvironmentImpl.ts b/src/vs/server/node/remoteAgentEnvironmentImpl.ts index 0ed520f2c69..38ba9a01e20 100644 --- a/src/vs/server/node/remoteAgentEnvironmentImpl.ts +++ b/src/vs/server/node/remoteAgentEnvironmentImpl.ts @@ -16,7 +16,6 @@ import { IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { transformOutgoingURIs } from 'vs/base/common/uriIpc'; import { ILogService } from 'vs/platform/log/common/log'; -import { getNLSConfiguration, InternalNLSConfiguration } from 'vs/server/node/remoteLanguagePacks'; import { ContextKeyExpr, ContextKeyDefinedExpr, ContextKeyNotExpr, ContextKeyEqualsExpr, ContextKeyNotEqualsExpr, ContextKeyRegexExpr, IContextKeyExprMapper, ContextKeyExpression, ContextKeyInExpr, ContextKeyGreaterExpr, ContextKeyGreaterEqualsExpr, ContextKeySmallerExpr, ContextKeySmallerEqualsExpr } from 'vs/platform/contextkey/common/contextkey'; import { listProcesses } from 'vs/base/node/ps'; import { getMachineInfo, collectWorkspaceStats } from 'vs/platform/diagnostics/node/diagnosticsService'; @@ -25,10 +24,9 @@ import { basename, isAbsolute, join, resolve } from 'vs/base/common/path'; import { ProcessItem } from 'vs/base/common/processes'; import { IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { cwd } from 'vs/base/common/process'; -import * as pfs from 'vs/base/node/pfs'; import { ServerConnectionToken, ServerConnectionTokenType } from 'vs/server/node/serverConnectionToken'; import { IExtensionHostStatusService } from 'vs/server/node/extensionHostStatusService'; -import { IExtensionsScannerService, NlsConfiguration, toExtensionDescription, Translations } from 'vs/platform/extensionManagement/common/extensionsScannerService'; +import { IExtensionsScannerService, toExtensionDescription } from 'vs/platform/extensionManagement/common/extensionsScannerService'; export class RemoteAgentEnvironmentChannel implements IServerChannel { @@ -120,8 +118,7 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { return null; } - const translations = await this._getTranslations(language); - let extension = await this._scanSingleExtension(extensionPath, isBuiltin, language, translations); + let extension = await this._scanSingleExtension(extensionPath, isBuiltin, language); if (!extension) { return null; @@ -304,28 +301,13 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { }; } - private async _getTranslations(language: string): Promise { - const config = await getNLSConfiguration(language, this._environmentService.userDataPath); - if (InternalNLSConfiguration.is(config)) { - try { - const content = await pfs.Promises.readFile(config._translationsConfigFile, 'utf8'); - return JSON.parse(content); - } catch (err) { - return Object.create(null); - } - } else { - return Object.create(null); - } - } - private async _scanExtensions(language: string, extensionDevelopmentPath?: string[]): Promise { // Ensure that the language packs are available - const translations = await this._getTranslations(language); const [builtinExtensions, installedExtensions, developedExtensions] = await Promise.all([ - this._scanBuiltinExtensions(language, translations), - this._scanInstalledExtensions(language, translations), - this._scanDevelopedExtensions(language, translations, extensionDevelopmentPath) + this._scanBuiltinExtensions(language), + this._scanInstalledExtensions(language), + this._scanDevelopedExtensions(language, extensionDevelopmentPath) ]); let result = new Map(); @@ -359,45 +341,34 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { return r; } - private async _scanDevelopedExtensions(language: string, translations: Translations, extensionDevelopmentPaths?: string[]): Promise { + private async _scanDevelopedExtensions(language: string, extensionDevelopmentPaths?: string[]): Promise { if (extensionDevelopmentPaths) { - const nlsConfiguration = this.createNLSConfig({ locale: language, devMode: true, translations }); - return (await Promise.all(extensionDevelopmentPaths.map(extensionDevelopmentPath => this._extensionsScannerService.scanOneOrMultipleExtensions(URI.file(resolve(extensionDevelopmentPath)), ExtensionType.User, { nlsConfiguration })))) + return (await Promise.all(extensionDevelopmentPaths.map(extensionDevelopmentPath => this._extensionsScannerService.scanOneOrMultipleExtensions(URI.file(resolve(extensionDevelopmentPath)), ExtensionType.User, { language })))) .flat() .map(e => toExtensionDescription(e, true)); } return []; } - private async _scanBuiltinExtensions(language: string, translations: Translations): Promise { - const devMode = !!process.env['VSCODE_DEV']; - return this._scanExtensionDescriptions(true, this.createNLSConfig({ locale: language, devMode, translations })); + private async _scanBuiltinExtensions(language: string): Promise { + return this._scanExtensionDescriptions(true, language); } - private async _scanInstalledExtensions(language: string, translations: Translations): Promise { - return this._scanExtensionDescriptions(false, this.createNLSConfig({ devMode: !!process.env['VSCODE_DEV'], locale: language, translations })); + private async _scanInstalledExtensions(language: string): Promise { + return this._scanExtensionDescriptions(false, language); } - private async _scanSingleExtension(extensionPath: string, isBuiltin: boolean, language: string, translations: Translations): Promise { + private async _scanSingleExtension(extensionPath: string, isBuiltin: boolean, language: string): Promise { const extensionLocation = URI.file(resolve(extensionPath)); const type = isBuiltin ? ExtensionType.System : ExtensionType.User; - const nlsConfiguration = this.createNLSConfig({ devMode: !!process.env['VSCODE_DEV'], locale: language, translations }); - const scannedExtension = await this._extensionsScannerService.scanExistingExtension(extensionLocation, type, { nlsConfiguration }); + const scannedExtension = await this._extensionsScannerService.scanExistingExtension(extensionLocation, type, { language }); return scannedExtension ? toExtensionDescription(scannedExtension, false) : null; } - private async _scanExtensionDescriptions(isBuiltin: boolean, nlsConfiguration: NlsConfiguration): Promise { - const scannedExtensions = isBuiltin ? await this._extensionsScannerService.scanSystemExtensions({ nlsConfiguration }) - : await this._extensionsScannerService.scanUserExtensions({ nlsConfiguration }); + private async _scanExtensionDescriptions(isBuiltin: boolean, language: string): Promise { + const scannedExtensions = isBuiltin ? await this._extensionsScannerService.scanSystemExtensions({ language }) + : await this._extensionsScannerService.scanUserExtensions({ language }); return scannedExtensions.map(e => toExtensionDescription(e, false)); } - public createNLSConfig(input: { devMode: boolean; locale: string | undefined; translations: Translations }): NlsConfiguration { - return { - devMode: input.devMode, - locale: input.locale, - pseudo: input.locale === 'pseudo', - translations: input.translations - }; - } } diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 919924f53ad..82a43fc6717 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -69,7 +69,7 @@ import { RemoteExtensionLogFileName } from 'vs/workbench/services/remote/common/ import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from 'vs/workbench/services/remote/common/remoteFileSystemProviderClient'; import { ExtensionHostStatusService, IExtensionHostStatusService } from 'vs/server/node/extensionHostStatusService'; import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService'; -import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService'; +import { ExtensionsScannerService } from 'vs/server/node/extensionsScannerService'; const eventPrefix = 'monacoworkbench'; diff --git a/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts index 6357aee8c51..ba57d76d1f4 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts @@ -17,7 +17,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IExtensionsScannerService, IScannedExtension, NlsConfiguration, toExtensionDescription, Translations } from 'vs/platform/extensionManagement/common/extensionsScannerService'; +import { IExtensionsScannerService, IScannedExtension, toExtensionDescription, Translations } from 'vs/platform/extensionManagement/common/extensionsScannerService'; import { ILogService } from 'vs/platform/log/common/log'; interface IExtensionCacheData { @@ -43,15 +43,6 @@ class ExtensionScannerInput { // Keep empty!! (JSON.parse) } - public static createNLSConfig(input: { devMode: boolean; locale: string | undefined; translations: Translations }): NlsConfiguration { - return { - devMode: input.devMode, - locale: input.locale, - pseudo: input.locale === 'pseudo', - translations: input.translations - }; - } - public static equals(a: ExtensionScannerInput, b: ExtensionScannerInput): boolean { return ( a.ourVersion === b.ourVersion @@ -92,11 +83,9 @@ export class CachedExtensionScanner { } public async scanSingleExtension(extensionPath: string, isBuiltin: boolean): Promise { - const translations = await this.translationConfig; const extensionLocation = URI.file(path.resolve(extensionPath)); const type = isBuiltin ? ExtensionType.System : ExtensionType.User; - const nlsConfiguration = ExtensionScannerInput.createNLSConfig({ devMode: !this._environmentService.isBuilt, locale: platform.language, translations }); - const scannedExtension = await this._extensionsScannerService.scanExistingExtension(extensionLocation, type, { nlsConfiguration }); + const scannedExtension = await this._extensionsScannerService.scanExistingExtension(extensionLocation, type, { language: platform.language }); return scannedExtension ? toExtensionDescription(scannedExtension, false) : null; } @@ -115,7 +104,7 @@ export class CachedExtensionScanner { const cacheFolder = path.join(this._environmentService.userDataPath, MANIFEST_CACHE_FOLDER); const cacheFile = path.join(cacheFolder, cacheKey); - const expected = JSON.parse(JSON.stringify(await this.scanExtensionDescriptions(input.isBuiltin, ExtensionScannerInput.createNLSConfig(input)))); + const expected = JSON.parse(JSON.stringify(await this.scanExtensionDescriptions(input.isBuiltin, input.locale))); const cacheContents = await this._readExtensionCache(cacheKey); if (!cacheContents) { @@ -180,7 +169,7 @@ export class CachedExtensionScanner { private async _scanExtensionsWithCache(cacheKey: string, input: ExtensionScannerInput): Promise { if (input.devMode) { // Do not cache when running out of sources... - return this.scanExtensionDescriptions(input.isBuiltin, ExtensionScannerInput.createNLSConfig(input)); + return this.scanExtensionDescriptions(input.isBuiltin, input.locale); } try { @@ -211,7 +200,7 @@ export class CachedExtensionScanner { const result: IExtensionDescription[] = []; let canCache = true; - const scannedExtensions = await this.scanExtensions(input.isBuiltin, ExtensionScannerInput.createNLSConfig(input), true); + const scannedExtensions = await this.scanExtensions(input.isBuiltin, input.locale, true); for (const scannedExtension of scannedExtensions) { if (scannedExtension.isValid) { result.push(toExtensionDescription(scannedExtension, input.isUnderDevelopment)); @@ -251,21 +240,19 @@ export class CachedExtensionScanner { const commit = this._productService.commit; const date = this._productService.date; const devMode = !this._environmentService.isBuilt; - const locale = platform.language; + const language = platform.language; const builtinExtensions = this._scanExtensionsWithCache( BUILTIN_MANIFEST_CACHE_FILE, - new ExtensionScannerInput(version, date, commit, locale, devMode, this._extensionsScannerService.systemExtensionsLocation.path, true, false, translations), + new ExtensionScannerInput(version, date, commit, language, devMode, this._extensionsScannerService.systemExtensionsLocation.path, true, false, translations), ); const userExtensions = this._scanExtensionsWithCache( USER_MANIFEST_CACHE_FILE, - new ExtensionScannerInput(version, date, commit, locale, devMode, this._extensionsScannerService.userExtensionsLocation.path, false, false, translations), + new ExtensionScannerInput(version, date, commit, language, devMode, this._extensionsScannerService.userExtensionsLocation.path, false, false, translations), ); - // Always load developed extensions while extensions development - const nlsConfiguration = ExtensionScannerInput.createNLSConfig(ExtensionScannerInput.createNLSConfig({ devMode, locale, translations })); - const developedExtensions = this._extensionsScannerService.scanExtensionsUnderDevelopment({ nlsConfiguration }) + const developedExtensions = this._extensionsScannerService.scanExtensionsUnderDevelopment({ language }) .then(scannedExtensions => scannedExtensions.map(e => toExtensionDescription(e, true))); return Promise.all([builtinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => { @@ -280,14 +267,14 @@ export class CachedExtensionScanner { }); } - private async scanExtensionDescriptions(isBuiltin: boolean, nlsConfiguration: NlsConfiguration): Promise { - const scannedExtensions = await this.scanExtensions(isBuiltin, nlsConfiguration, false); + private async scanExtensionDescriptions(isBuiltin: boolean, language: string | undefined): Promise { + const scannedExtensions = await this.scanExtensions(isBuiltin, language, false); return scannedExtensions.map(e => toExtensionDescription(e, false)); } - private async scanExtensions(isBuiltin: boolean, nlsConfiguration: NlsConfiguration, includeInvalid: boolean): Promise { - return isBuiltin ? this._extensionsScannerService.scanSystemExtensions({ nlsConfiguration, checkControlFile: true, includeInvalid }) - : this._extensionsScannerService.scanUserExtensions({ nlsConfiguration, includeInvalid }); + private async scanExtensions(isBuiltin: boolean, language: string | undefined, includeInvalid: boolean): Promise { + return isBuiltin ? this._extensionsScannerService.scanSystemExtensions({ language, checkControlFile: true, includeInvalid }) + : this._extensionsScannerService.scanUserExtensions({ language, includeInvalid }); } } diff --git a/src/vs/workbench/workbench.sandbox.main.ts b/src/vs/workbench/workbench.sandbox.main.ts index 8c0ca67878d..e0708193c34 100644 --- a/src/vs/workbench/workbench.sandbox.main.ts +++ b/src/vs/workbench/workbench.sandbox.main.ts @@ -61,7 +61,7 @@ import 'vs/workbench/services/encryption/electron-sandbox/encryptionService'; import 'vs/workbench/services/localizations/electron-sandbox/localizationsService'; import 'vs/workbench/services/telemetry/electron-sandbox/telemetryService'; import 'vs/workbench/services/extensions/electron-sandbox/extensionHostStarter'; -import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionsScannerService'; +import 'vs/platform/extensionManagement/electron-sandbox/extensionsScannerService'; import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionManagementServerService'; import 'vs/workbench/services/extensionManagement/electron-sandbox/extensionTipsService'; import 'vs/workbench/services/userDataSync/electron-sandbox/userDataSyncMachinesService';