diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index ecdbf415422..5afbb0f9f24 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -50,6 +50,9 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationExportHelper'; +import { HashService } from 'vs/workbench/services/hash/node/hashService'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; +import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; class CodeRendererMain extends Disposable { @@ -202,8 +205,12 @@ class CodeRendererMain extends Disposable { fileService.registerProvider(REMOTE_HOST_SCHEME, remoteFileSystemProvider); } + // Hash Service + const hashService = new HashService(); + serviceCollection.set(IHashService, hashService); + return this.resolveWorkspaceInitializationPayload(environmentService).then(payload => Promise.all([ - this.createWorkspaceService(payload, environmentService, remoteAgentService, logService).then(service => { + this.createWorkspaceService(payload, environmentService, hashService, remoteAgentService, logService).then(service => { // Workspace serviceCollection.set(IWorkspaceContextService, service); @@ -294,8 +301,8 @@ class CodeRendererMain extends Disposable { }, error => onUnexpectedError(error)); } - private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise { - const workspaceService = new WorkspaceService(this.configuration, environmentService, remoteAgentService); + private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, hashService: IHashService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise { + const workspaceService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, hashService, remoteAgentService); return workspaceService.initialize(payload).then(() => workspaceService, error => { onUnexpectedError(error); diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index ad2658aa60e..8fcb72881e1 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -19,3 +19,14 @@ export const LAUNCH_CONFIGURATION_KEY = 'launch'; export const WORKSPACE_STANDALONE_CONFIGURATIONS = Object.create(null); WORKSPACE_STANDALONE_CONFIGURATIONS[TASKS_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/${TASKS_CONFIGURATION_KEY}.json`; WORKSPACE_STANDALONE_CONFIGURATIONS[LAUNCH_CONFIGURATION_KEY] = `${FOLDER_CONFIG_FOLDER_NAME}/${LAUNCH_CONFIGURATION_KEY}.json`; + + +export type ConfigurationKey = { type: 'user' | 'workspaces' | 'folder', key: string }; + +export interface IConfigurationCache { + + read(key: ConfigurationKey): Promise; + write(key: ConfigurationKey, content: string): Promise; + remove(key: ConfigurationKey): Promise; + +} diff --git a/src/vs/workbench/services/configuration/node/configuration.ts b/src/vs/workbench/services/configuration/node/configuration.ts index fbf33d295f2..0f46600facc 100644 --- a/src/vs/workbench/services/configuration/node/configuration.ts +++ b/src/vs/workbench/services/configuration/node/configuration.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { createHash } from 'crypto'; import * as resources from 'vs/base/common/resources'; import { Event, Emitter } from 'vs/base/common/event'; import * as pfs from 'vs/base/node/pfs'; @@ -15,7 +14,7 @@ import { RunOnceScheduler, Delayer } from 'vs/base/common/async'; import { FileChangeType, FileChangesEvent, IContent, IFileService } from 'vs/platform/files/common/files'; import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels'; import { WorkspaceConfigurationModelParser, FolderSettingsModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration'; import { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService'; import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -23,9 +22,9 @@ import { ConfigurationScope } from 'vs/platform/configuration/common/configurati import { extname, join } from 'vs/base/common/path'; import { equals } from 'vs/base/common/objects'; import { Schemas } from 'vs/base/common/network'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IConfigurationModel, compare } from 'vs/platform/configuration/common/configuration'; import { NodeBasedUserConfiguration } from 'vs/platform/configuration/node/configuration'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export class LocalUserConfiguration extends Disposable { @@ -37,12 +36,11 @@ export class LocalUserConfiguration extends Disposable { public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; constructor( - environmentService: IEnvironmentService + userSettingsPath: string ) { super(); - this.userConfigurationResource = URI.file(environmentService.appSettingsPath); - this.userConfiguration = this._register(new NodeBasedUserConfiguration(environmentService.appSettingsPath)); - this.changeDisposable = this._register(this.userConfiguration.onDidChangeConfiguration(configurationModel => this._onDidChangeConfiguration.fire(configurationModel))); + this.userConfigurationResource = URI.file(userSettingsPath); + this.userConfiguration = this._register(new NodeBasedUserConfiguration(userSettingsPath)); } initialize(): Promise { @@ -74,10 +72,10 @@ export class RemoteUserConfiguration extends Disposable { constructor( remoteAuthority: string, - environmentService: IEnvironmentService + configurationCache: IConfigurationCache ) { super(); - this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, environmentService); + this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, configurationCache); } initialize(): Promise { @@ -169,17 +167,15 @@ class CachedUserConfiguration extends Disposable { private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - private readonly cachedFolderPath: string; - private readonly cachedConfigurationPath: string; + private readonly key: ConfigurationKey; private configurationModel: ConfigurationModel; constructor( remoteAuthority: string, - private environmentService: IEnvironmentService + private readonly configurationCache: IConfigurationCache ) { super(); - this.cachedFolderPath = join(this.environmentService.userDataPath, 'CachedConfigurations', 'user', remoteAuthority); - this.cachedConfigurationPath = join(this.cachedFolderPath, 'configuration.json'); + this.key = { type: 'user', key: remoteAuthority }; this.configurationModel = new ConfigurationModel(); } @@ -191,33 +187,22 @@ class CachedUserConfiguration extends Disposable { return this.reload(); } - reload(): Promise { - return pfs.readFile(this.cachedConfigurationPath) - .then(content => content.toString(), () => '') - .then(content => { - try { - const parsed: IConfigurationModel = JSON.parse(content); - this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides); - } catch (e) { - } - return this.configurationModel; - }); + async reload(): Promise { + const content = await this.configurationCache.read(this.key); + try { + const parsed: IConfigurationModel = JSON.parse(content); + this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides); + } catch (e) { + } + return this.configurationModel; } updateConfiguration(configurationModel: ConfigurationModel): Promise { - const raw = JSON.stringify(configurationModel.toJSON()); - return this.createCachedFolder().then(created => { - if (created) { - return configurationModel.keys.length ? pfs.writeFile(this.cachedConfigurationPath, raw) : pfs.rimraf(this.cachedFolderPath); - } - return undefined; - }); - } - - private createCachedFolder(): Promise { - return Promise.resolve(pfs.exists(this.cachedFolderPath)) - .then(undefined, () => false) - .then(exists => exists ? exists : pfs.mkdirp(this.cachedFolderPath).then(() => true, () => false)); + if (configurationModel.keys.length) { + return this.configurationCache.write(this.key, JSON.stringify(configurationModel.toJSON())); + } else { + return this.configurationCache.remove(this.key); + } } } @@ -237,10 +222,10 @@ export class WorkspaceConfiguration extends Disposable { public readonly onDidUpdateConfiguration: Event = this._onDidUpdateConfiguration.event; constructor( - environmentService: IEnvironmentService + configurationCache: IConfigurationCache ) { super(); - this._cachedConfiguration = new CachedWorkspaceConfiguration(environmentService); + this._cachedConfiguration = new CachedWorkspaceConfiguration(configurationCache); this._workspaceConfiguration = this._cachedConfiguration; } @@ -473,25 +458,24 @@ class CachedWorkspaceConfiguration extends Disposable implements IWorkspaceConfi private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - private cachedWorkspacePath: string; - private cachedConfigurationPath: string; workspaceConfigurationModelParser: WorkspaceConfigurationModelParser; workspaceSettings: ConfigurationModel; - constructor(private environmentService: IEnvironmentService) { + constructor(private readonly configurationCache: IConfigurationCache) { super(); this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(''); this.workspaceSettings = new ConfigurationModel(); } - load(workspaceIdentifier: IWorkspaceIdentifier): Promise { - this.createPaths(workspaceIdentifier); - return pfs.readFile(this.cachedConfigurationPath) - .then(contents => { - this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(this.cachedConfigurationPath); - this.workspaceConfigurationModelParser.parse(contents.toString()); - this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel); - }, () => { }); + async load(workspaceIdentifier: IWorkspaceIdentifier): Promise { + try { + const key = this.getKey(workspaceIdentifier); + const contents = await this.configurationCache.read(key); + this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(key.key); + this.workspaceConfigurationModelParser.parse(contents); + this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel); + } catch (e) { + } } get workspaceIdentifier(): IWorkspaceIdentifier | null { @@ -516,25 +500,21 @@ class CachedWorkspaceConfiguration extends Disposable implements IWorkspaceConfi async updateWorkspace(workspaceIdentifier: IWorkspaceIdentifier, configurationModel: ConfigurationModel): Promise { try { - this.createPaths(workspaceIdentifier); + const key = this.getKey(workspaceIdentifier); if (configurationModel.keys.length) { - const exists = await pfs.exists(this.cachedWorkspacePath); - if (!exists) { - await pfs.mkdirp(this.cachedWorkspacePath); - } - const raw = JSON.stringify(configurationModel.toJSON().contents); - await pfs.writeFile(this.cachedConfigurationPath, raw); + await this.configurationCache.write(key, JSON.stringify(configurationModel.toJSON().contents)); } else { - pfs.rimraf(this.cachedWorkspacePath); + await this.configurationCache.remove(key); } } catch (error) { - errors.onUnexpectedError(error); } } - private createPaths(workspaceIdentifier: IWorkspaceIdentifier) { - this.cachedWorkspacePath = join(this.environmentService.userDataPath, 'CachedConfigurations', 'workspaces', workspaceIdentifier.id); - this.cachedConfigurationPath = join(this.cachedWorkspacePath, 'workspace.json'); + private getKey(workspaceIdentifier: IWorkspaceIdentifier): ConfigurationKey { + return { + type: 'workspaces', + key: workspaceIdentifier.id + }; } } @@ -758,45 +738,45 @@ export class FileServiceBasedFolderConfiguration extends AbstractFolderConfigura } } -export class CachedFolderConfiguration extends Disposable implements IFolderConfiguration { +class CachedFolderConfiguration extends Disposable implements IFolderConfiguration { private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - private readonly cachedFolderPath: string; - private readonly cachedConfigurationPath: string; private configurationModel: ConfigurationModel; - + private readonly key: Thenable; loaded: boolean = false; constructor( folder: URI, configFolderRelativePath: string, - environmentService: IEnvironmentService) { + hashService: IHashService, + private readonly configurationCache: IConfigurationCache + ) { super(); - this.cachedFolderPath = join(environmentService.userDataPath, 'CachedConfigurations', 'folders', createHash('md5').update(join(folder.path, configFolderRelativePath)).digest('hex')); - this.cachedConfigurationPath = join(this.cachedFolderPath, 'configuration.json'); + this.key = hashService.createSHA1(join(folder.path, configFolderRelativePath)).then(key => ({ type: 'folder', key })); this.configurationModel = new ConfigurationModel(); } - loadConfiguration(): Promise { - return pfs.readFile(this.cachedConfigurationPath) - .then(contents => { - const parsed: IConfigurationModel = JSON.parse(contents.toString()); - this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides); - this.loaded = true; - return this.configurationModel; - }, () => this.configurationModel); + async loadConfiguration(): Promise { + try { + const key = await this.key; + const contents = await this.configurationCache.read(key); + const parsed: IConfigurationModel = JSON.parse(contents.toString()); + this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides); + this.loaded = true; + } catch (e) { + } + return this.configurationModel; } - updateConfiguration(configurationModel: ConfigurationModel): Promise { - const raw = JSON.stringify(configurationModel.toJSON()); - return this.createCachedFolder().then(created => { - if (created) { - return configurationModel.keys.length ? pfs.writeFile(this.cachedConfigurationPath, raw) : pfs.rimraf(this.cachedFolderPath); - } - return undefined; - }); + async updateConfiguration(configurationModel: ConfigurationModel): Promise { + const key = await this.key; + if (configurationModel.keys.length) { + await this.configurationCache.write(key, JSON.stringify(configurationModel.toJSON())); + } else { + await this.configurationCache.remove(key); + } } reprocess(): ConfigurationModel { @@ -806,12 +786,6 @@ export class CachedFolderConfiguration extends Disposable implements IFolderConf getUnsupportedKeys(): string[] { return []; } - - private createCachedFolder(): Promise { - return Promise.resolve(pfs.exists(this.cachedFolderPath)) - .then(undefined, () => false) - .then(exists => exists ? exists : pfs.mkdirp(this.cachedFolderPath).then(() => true, () => false)); - } } export class FolderConfiguration extends Disposable implements IFolderConfiguration { @@ -827,12 +801,13 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat readonly workspaceFolder: IWorkspaceFolder, private readonly configFolderRelativePath: string, private readonly workbenchState: WorkbenchState, - private environmentService: IEnvironmentService, + hashService: IHashService, + configurationCache: IConfigurationCache, fileService?: IFileService ) { super(); - this.cachedFolderConfiguration = new CachedFolderConfiguration(this.workspaceFolder.uri, this.configFolderRelativePath, this.environmentService); + this.cachedFolderConfiguration = new CachedFolderConfiguration(this.workspaceFolder.uri, this.configFolderRelativePath, hashService, configurationCache); this.folderConfiguration = this.cachedFolderConfiguration; if (fileService) { this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.workspaceFolder.uri, this.configFolderRelativePath, this.workbenchState, fileService); diff --git a/src/vs/workbench/services/configuration/node/configurationCache.ts b/src/vs/workbench/services/configuration/node/configurationCache.ts new file mode 100644 index 00000000000..67b46a14cb2 --- /dev/null +++ b/src/vs/workbench/services/configuration/node/configurationCache.ts @@ -0,0 +1,82 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as pfs from 'vs/base/node/pfs'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { join } from 'vs/base/common/path'; +import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration'; + +export class ConfigurationCache implements IConfigurationCache { + + private readonly cachedConfigurations: Map = new Map(); + + constructor(private readonly environmentService: IEnvironmentService) { + } + + read(key: ConfigurationKey): Promise { + return this.getCachedConfiguration(key).read(); + } + + write(key: ConfigurationKey, content: string): Promise { + return this.getCachedConfiguration(key).save(content); + } + + remove(key: ConfigurationKey): Promise { + return this.getCachedConfiguration(key).remove(); + } + + private getCachedConfiguration({ type, key }: ConfigurationKey): CachedConfiguration { + const k = `${type}:${key}`; + let cachedConfiguration = this.cachedConfigurations.get(k); + if (!cachedConfiguration) { + cachedConfiguration = new CachedConfiguration({ type, key }, this.environmentService); + this.cachedConfigurations.set(k, cachedConfiguration); + } + return cachedConfiguration; + } + +} + + +class CachedConfiguration { + + private cachedConfigurationFolderPath: string; + private cachedConfigurationFilePath: string; + + constructor( + { type, key }: ConfigurationKey, + environmentService: IEnvironmentService + ) { + this.cachedConfigurationFolderPath = join(environmentService.userDataPath, 'CachedConfigurations', type, key); + this.cachedConfigurationFilePath = join(this.cachedConfigurationFolderPath, type === 'workspaces' ? 'workspace.json' : 'configuration.json'); + } + + async read(): Promise { + try { + const content = await pfs.readFile(this.cachedConfigurationFilePath); + return content.toString(); + } catch (e) { + return ''; + } + } + + async save(content: string): Promise { + const created = await this.createCachedFolder(); + if (created) { + await pfs.writeFile(this.cachedConfigurationFilePath, content); + } + } + + remove(): Promise { + return pfs.rimraf(this.cachedConfigurationFolderPath); + } + + private createCachedFolder(): Promise { + return Promise.resolve(pfs.exists(this.cachedConfigurationFolderPath)) + .then(undefined, () => false) + .then(exists => exists ? exists : pfs.mkdirp(this.cachedConfigurationFolderPath).then(() => true, () => false)); + } +} + diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 3bd94d9baf0..7c827800954 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -14,11 +14,10 @@ import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/plat import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { isLinux } from 'vs/base/common/platform'; import { IFileService } from 'vs/platform/files/common/files'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, isSingleFolderWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; @@ -32,7 +31,7 @@ import { isEqual, dirname } from 'vs/base/common/resources'; import { mark } from 'vs/base/common/performance'; import { Schemas } from 'vs/base/common/network'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { IHashService } from 'vs/workbench/services/hash/common/hashService'; export class WorkspaceService extends Disposable implements IConfigurationService, IWorkspaceContextService { @@ -40,9 +39,10 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private workspace: Workspace; private completeWorkspaceBarrier: Barrier; + private readonly configurationCache: IConfigurationCache; private _configuration: Configuration; private defaultConfiguration: DefaultConfigurationModel; - private localUserConfiguration: LocalUserConfiguration; + private localUserConfiguration: LocalUserConfiguration | null = null; private remoteUserConfiguration: RemoteUserConfiguration | null = null; private workspaceConfiguration: WorkspaceConfiguration; private cachedFolderConfigs: ResourceMap; @@ -65,18 +65,25 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private configurationEditingService: ConfigurationEditingService; private jsonEditingService: JSONEditingService; - constructor(configuration: IWindowConfiguration, private environmentService: IEnvironmentService, private remoteAgentService: IRemoteAgentService, private workspaceSettingsRootFolder: string = FOLDER_CONFIG_FOLDER_NAME) { + constructor( + { userSettingsPath, remoteAuthority, configurationCache }: { userSettingsPath?: string, remoteAuthority?: string, configurationCache: IConfigurationCache }, + private readonly hashService: IHashService, + private readonly remoteAgentService: IRemoteAgentService, + ) { super(); this.completeWorkspaceBarrier = new Barrier(); this.defaultConfiguration = new DefaultConfigurationModel(); - this.localUserConfiguration = this._register(new LocalUserConfiguration(environmentService)); - this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration))); - if (configuration.remoteAuthority) { - this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(configuration.remoteAuthority, environmentService)); + this.configurationCache = configurationCache; + if (userSettingsPath) { + this.localUserConfiguration = this._register(new LocalUserConfiguration(userSettingsPath)); + this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration))); + } + if (remoteAuthority) { + this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache)); this._register(this.remoteUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onRemoteUserConfigurationChanged(userConfiguration))); } - this.workspaceConfiguration = this._register(new WorkspaceConfiguration(environmentService)); + this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache)); this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => this.onWorkspaceConfigurationChanged())); this._register(Registry.as(Extensions.Configuration).onDidSchemaChange(e => this.registerConfigurationSchemas())); @@ -291,7 +298,9 @@ export class WorkspaceService extends Disposable implements IConfigurationServic acquireFileService(fileService: IFileService): void { this.fileService = fileService; const changedWorkspaceFolders: IWorkspaceFolder[] = []; - this.localUserConfiguration.adopt(fileService); + if (this.localUserConfiguration) { + this.localUserConfiguration.adopt(fileService); + } Promise.all([this.workspaceConfiguration.adopt(fileService), ...this.cachedFolderConfigs.values() .map(folderConfiguration => folderConfiguration.adopt(fileService) .then(result => { @@ -440,12 +449,12 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private initializeUserConfiguration(): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> { - return Promise.all([this.localUserConfiguration.initialize(), this.remoteUserConfiguration ? this.remoteUserConfiguration.initialize() : Promise.resolve(new ConfigurationModel())]) + return Promise.all([this.localUserConfiguration ? this.localUserConfiguration.initialize() : Promise.resolve(new ConfigurationModel()), this.remoteUserConfiguration ? this.remoteUserConfiguration.initialize() : Promise.resolve(new ConfigurationModel())]) .then(([local, remote]) => ({ local, remote })); } private reloadUserConfiguration(key?: string): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> { - return Promise.all([this.localUserConfiguration.reload(), this.remoteUserConfiguration ? this.remoteUserConfiguration.reload() : Promise.resolve(new ConfigurationModel())]) + return Promise.all([this.localUserConfiguration ? this.localUserConfiguration.reload() : Promise.resolve(new ConfigurationModel()), this.remoteUserConfiguration ? this.remoteUserConfiguration.reload() : Promise.resolve(new ConfigurationModel())]) .then(([local, remote]) => ({ local, remote })); } @@ -616,7 +625,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic return Promise.all([...folders.map(folder => { let folderConfiguration = this.cachedFolderConfigs.get(folder.uri); if (!folderConfiguration) { - folderConfiguration = new FolderConfiguration(folder, this.workspaceSettingsRootFolder, this.getWorkbenchState(), this.environmentService, this.fileService); + folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.hashService, this.configurationCache, this.fileService); this._register(folderConfiguration.onDidChange(() => this.onWorkspaceFolderConfigurationChanged(folder))); this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); } diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index 60dc3caedec..64d3819250e 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -32,7 +32,6 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { CommandService } from 'vs/workbench/services/commands/common/commandService'; import { URI } from 'vs/base/common/uri'; import { createHash } from 'crypto'; -import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { FileService2 } from 'vs/workbench/services/files2/common/fileService2'; @@ -41,6 +40,8 @@ import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/workbench/services/files2/node/diskFileSystemProvider'; import { IFileService } from 'vs/platform/files/common/files'; import { setUnexpectedErrorHandler } from 'vs/base/common/errors'; +import { HashService } from 'vs/workbench/services/hash/node/hashService'; +import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; class SettingsTestEnvironmentService extends EnvironmentService { @@ -107,7 +108,7 @@ suite('ConfigurationEditingService', () => { instantiationService.stub(IEnvironmentService, environmentService); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({}, environmentService, remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, configurationCache: new ConfigurationCache(environmentService) }, new HashService(), remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); return workspaceService.initialize(noWorkspace ? { id: '' } : { folder: URI.file(workspaceDir), id: createHash('md5').update(URI.file(workspaceDir).toString()).digest('hex') }).then(() => { instantiationService.stub(IConfigurationService, workspaceService); diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index 7d3060e271d..b85a4bb87c0 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -44,6 +44,8 @@ import { FileService2 } from 'vs/workbench/services/files2/common/fileService2'; import { NullLogService } from 'vs/platform/log/common/log'; import { DiskFileSystemProvider } from 'vs/workbench/services/files2/node/diskFileSystemProvider'; import { setUnexpectedErrorHandler } from 'vs/base/common/errors'; +import { HashService } from 'vs/workbench/services/hash/node/hashService'; +import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; class SettingsTestEnvironmentService extends EnvironmentService { @@ -102,7 +104,7 @@ suite('WorkspaceContextService - Folder', () => { workspaceResource = folderDir; const globalSettingsFile = path.join(parentDir, 'settings.json'); const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); - workspaceContextService = new WorkspaceService({}, environmentService, new RemoteAgentService({}, environmentService, new RemoteAuthorityResolverService())); + workspaceContextService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, configurationCache: new ConfigurationCache(environmentService) }, new HashService(), new RemoteAgentService({}, environmentService, new RemoteAuthorityResolverService())); return (workspaceContextService).initialize(convertToWorkspacePayload(URI.file(folderDir))); }); }); @@ -164,7 +166,7 @@ suite('WorkspaceContextService - Workspace', () => { const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({}, environmentService, remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, configurationCache: new ConfigurationCache(environmentService) }, new HashService(), remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); @@ -220,7 +222,7 @@ suite('WorkspaceContextService - Workspace Editing', () => { const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({}, environmentService, remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, configurationCache: new ConfigurationCache(environmentService) }, new HashService(), remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); @@ -491,7 +493,7 @@ suite('WorkspaceService - Initialization', () => { const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({}, environmentService, remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, configurationCache: new ConfigurationCache(environmentService) }, new HashService(), remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); instantiationService.stub(IEnvironmentService, environmentService); @@ -756,7 +758,7 @@ suite('WorkspaceConfigurationService - Folder', () => { const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({}, environmentService, remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, configurationCache: new ConfigurationCache(environmentService) }, new HashService(), remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); instantiationService.stub(IEnvironmentService, environmentService); @@ -1054,7 +1056,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({}, environmentService, remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsPath: environmentService.appSettingsPath, configurationCache: new ConfigurationCache(environmentService) }, new HashService(), remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); diff --git a/src/vs/workbench/services/hash/node/hashService.ts b/src/vs/workbench/services/hash/node/hashService.ts index f18b3662fcf..019931bdfe5 100644 --- a/src/vs/workbench/services/hash/node/hashService.ts +++ b/src/vs/workbench/services/hash/node/hashService.ts @@ -5,7 +5,6 @@ import { createHash } from 'crypto'; import { IHashService } from 'vs/workbench/services/hash/common/hashService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export class HashService implements IHashService { @@ -15,5 +14,3 @@ export class HashService implements IHashService { return Promise.resolve(createHash('sha1').update(content).digest('hex')); } } - -registerSingleton(IHashService, HashService, true); \ No newline at end of file diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 2827a10405c..fbb589ae809 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -94,7 +94,6 @@ import { RelayURLService } from 'vs/platform/url/electron-browser/urlService'; import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; import 'vs/workbench/services/integrity/node/integrityService'; import 'vs/workbench/services/keybinding/common/keybindingEditing'; -import 'vs/workbench/services/hash/node/hashService'; import 'vs/workbench/services/textMate/electron-browser/textMateService'; import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import 'vs/workbench/services/workspace/node/workspaceEditingService';