提交 c98431ec 编写于 作者: S Sandeep Somavarapu

#59478 Use file service to read user configuration

上级 23ffed03
......@@ -3,13 +3,17 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ConfigurationModelParser, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { ConfigWatcher } from 'vs/base/node/config';
import { Event, Emitter } from 'vs/base/common/event';
import { RunOnceScheduler } from 'vs/base/common/async';
import { URI } from 'vs/base/common/uri';
import { IFileService, FileChangesEvent } from 'vs/platform/files/common/files';
import * as resources from 'vs/base/common/resources';
export class UserConfiguration extends Disposable {
export class NodeBasedUserConfiguration extends Disposable {
private userConfigModelWatcher: ConfigWatcher<ConfigurationModelParser>;
private initializePromise: Promise<void>;
......@@ -50,4 +54,53 @@ export class UserConfiguration extends Disposable {
return this.initialize().then(() => new Promise<ConfigurationModel>(c => this.userConfigModelWatcher.reload(userConfigModelParser => c(userConfigModelParser.configurationModel))));
}
}
export class FileServiceBasedUserConfiguration extends Disposable {
private readonly reloadConfigurationScheduler: RunOnceScheduler;
protected readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
constructor(
private readonly configurationResource: URI,
private readonly fileService: IFileService
) {
super();
this._register(fileService.onFileChanges(e => this.handleFileEvents(e)));
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
this.fileService.watchFileChanges(this.configurationResource);
this._register(toDisposable(() => this.fileService.unwatchFileChanges(this.configurationResource)));
}
initialize(): Promise<ConfigurationModel> {
return this.reload();
}
reload(): Promise<ConfigurationModel> {
return this.fileService.resolveContent(this.configurationResource)
.then(content => content.value, () => {
// File not found
return '';
}).then(content => {
const parser = new ConfigurationModelParser(this.configurationResource.toString());
parser.parse(content);
return parser.configurationModel;
});
}
private handleFileEvents(event: FileChangesEvent): void {
const events = event.changes;
let affectedByChanges = false;
// Find changes that affect workspace file
for (let i = 0, len = events.length; i < len && !affectedByChanges; i++) {
affectedByChanges = resources.isEqual(this.configurationResource, events[i].resource);
}
if (affectedByChanges) {
this.reloadConfigurationScheduler.schedule();
}
}
}
\ No newline at end of file
......@@ -11,14 +11,14 @@ import { DefaultConfigurationModel, Configuration, ConfigurationChangeEvent, Con
import { Event, Emitter } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { UserConfiguration } from 'vs/platform/configuration/node/configuration';
import { NodeBasedUserConfiguration } from 'vs/platform/configuration/node/configuration';
export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable {
_serviceBrand: any;
private _configuration: Configuration;
private userConfiguration: UserConfiguration;
private userConfiguration: NodeBasedUserConfiguration;
private readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
readonly onDidChangeConfiguration: Event<IConfigurationChangeEvent> = this._onDidChangeConfiguration.event;
......@@ -28,7 +28,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
) {
super();
this.userConfiguration = this._register(new UserConfiguration(environmentService.appSettingsPath));
this.userConfiguration = this._register(new NodeBasedUserConfiguration(environmentService.appSettingsPath));
// Initialize
const defaults = new DefaultConfigurationModel();
......
......@@ -13,7 +13,7 @@ import * as collections from 'vs/base/common/collections';
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
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 { ConfigurationModel } 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 { IStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces';
......@@ -26,14 +26,52 @@ 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 { FileServiceBasedUserConfiguration, NodeBasedUserConfiguration } from 'vs/platform/configuration/node/configuration';
export class LocalUserConfiguration extends Disposable {
private readonly userConfigurationResource: URI;
private userConfiguration: NodeBasedUserConfiguration | FileServiceBasedUserConfiguration;
private changeDisposable: IDisposable = Disposable.None;
private readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
public readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
constructor(
environmentService: IEnvironmentService
) {
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)));
}
initialize(): Promise<ConfigurationModel> {
return this.userConfiguration.initialize();
}
reload(): Promise<ConfigurationModel> {
return this.userConfiguration.reload();
}
async adopt(fileService: IFileService): Promise<ConfigurationModel | null> {
if (this.userConfiguration instanceof NodeBasedUserConfiguration) {
this.userConfiguration.dispose();
dispose(this.changeDisposable);
this.userConfiguration = this._register(new FileServiceBasedUserConfiguration(this.userConfigurationResource, fileService));
this.changeDisposable = this._register(this.userConfiguration.onDidChangeConfiguration(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)));
}
return null;
}
}
export class RemoteUserConfiguration extends Disposable {
private readonly _cachedConfiguration: CachedUserConfiguration;
private _userConfiguration: FileServiceBasedUserConfiguration | CachedUserConfiguration;
private readonly _onDidUpdateConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
public readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidUpdateConfiguration.event;
private readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
public readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
constructor(
remoteAuthority: string,
......@@ -43,8 +81,12 @@ export class RemoteUserConfiguration extends Disposable {
this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, environmentService);
}
load(): Promise<ConfigurationModel> {
return this._userConfiguration.loadConfiguration();
initialize(): Promise<ConfigurationModel> {
return this._userConfiguration.initialize();
}
reload(): Promise<ConfigurationModel> {
return this._userConfiguration.reload();
}
async adopt(configurationResource: URI | null, fileService: IFileService): Promise<ConfigurationModel | null> {
......@@ -52,9 +94,9 @@ export class RemoteUserConfiguration extends Disposable {
const oldConfigurationModel = this._userConfiguration.getConfigurationModel();
let newConfigurationModel = new ConfigurationModel();
if (configurationResource) {
this._userConfiguration = new FileServiceBasedUserConfiguration(configurationResource, oldConfigurationModel, fileService);
this._register(this._userConfiguration.onDidChange(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
newConfigurationModel = await this._userConfiguration.loadConfiguration();
this._userConfiguration = new FileServiceBasedUserConfiguration(configurationResource, fileService);
this._register(this._userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel)));
newConfigurationModel = await this._userConfiguration.initialize();
}
const { added, updated, removed } = compare(oldConfigurationModel, newConfigurationModel);
if (added.length > 0 || updated.length > 0 || removed.length > 0) {
......@@ -67,7 +109,7 @@ export class RemoteUserConfiguration extends Disposable {
private onDidUserConfigurationChange(configurationModel: ConfigurationModel): void {
this.updateCache(configurationModel);
this._onDidUpdateConfiguration.fire(configurationModel);
this._onDidChangeConfiguration.fire(configurationModel);
}
private updateCache(configurationModel: ConfigurationModel): Promise<void> {
......@@ -75,53 +117,6 @@ export class RemoteUserConfiguration extends Disposable {
}
}
class FileServiceBasedUserConfiguration extends Disposable {
private readonly reloadConfigurationScheduler: RunOnceScheduler;
protected readonly _onDidChange: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
readonly onDidChange: Event<ConfigurationModel> = this._onDidChange.event;
constructor(
private readonly configurationResource: URI,
private configurationModel: ConfigurationModel,
private readonly fileService: IFileService
) {
super();
this._register(fileService.onFileChanges(e => this.handleFileEvents(e)));
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.loadConfiguration().then(configurationModel => this._onDidChange.fire(configurationModel)), 50));
this.fileService.watchFileChanges(this.configurationResource);
this._register(toDisposable(() => this.fileService.unwatchFileChanges(this.configurationResource)));
}
loadConfiguration(): Promise<ConfigurationModel> {
return this.fileService.resolveContent(this.configurationResource)
.then(content => content.value, e => {
errors.onUnexpectedError(e);
return '';
}).then(content => {
const parser = new ConfigurationModelParser(this.configurationResource.toString());
parser.parse(content);
this.configurationModel = parser.configurationModel;
return this.configurationModel;
});
}
private handleFileEvents(event: FileChangesEvent): void {
const events = event.changes;
let affectedByChanges = false;
// Find changes that affect workspace file
for (let i = 0, len = events.length; i < len && !affectedByChanges; i++) {
affectedByChanges = resources.isEqual(this.configurationResource, events[i].resource);
}
if (affectedByChanges) {
this.reloadConfigurationScheduler.schedule();
}
}
}
class CachedUserConfiguration extends Disposable {
private readonly _onDidChange: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
......@@ -145,7 +140,11 @@ class CachedUserConfiguration extends Disposable {
return this.configurationModel;
}
loadConfiguration(): Promise<ConfigurationModel> {
initialize(): Promise<ConfigurationModel> {
return this.reload();
}
reload(): Promise<ConfigurationModel> {
return pfs.readFile(this.cachedConfigurationPath)
.then(content => content.toString(), () => '')
.then(content => {
......
......@@ -28,9 +28,8 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
import product from 'vs/platform/product/node/product';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditingService';
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration } from 'vs/workbench/services/configuration/node/configuration';
import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, LocalUserConfiguration } from 'vs/workbench/services/configuration/node/configuration';
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
import { UserConfiguration } from 'vs/platform/configuration/node/configuration';
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
import { localize } from 'vs/nls';
import { isEqual, dirname } from 'vs/base/common/resources';
......@@ -47,7 +46,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
private completeWorkspaceBarrier: Barrier;
private _configuration: Configuration;
private defaultConfiguration: DefaultConfigurationModel;
private localUserConfiguration: UserConfiguration;
private localUserConfiguration: LocalUserConfiguration;
private remoteUserConfiguration: RemoteUserConfiguration | null = null;
private workspaceConfiguration: WorkspaceConfiguration;
private cachedFolderConfigs: ResourceMap<FolderConfiguration>;
......@@ -75,13 +74,13 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
this.completeWorkspaceBarrier = new Barrier();
this.defaultConfiguration = new DefaultConfigurationModel();
this.localUserConfiguration = this._register(new UserConfiguration(environmentService.appSettingsPath));
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._register(this.remoteUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onRemoteUserConfigurationChanged(userConfiguration)));
}
this.workspaceConfiguration = this._register(new WorkspaceConfiguration(environmentService));
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => this.onWorkspaceConfigurationChanged()));
this._register(Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidSchemaChange(e => this.registerConfigurationSchemas()));
......@@ -296,6 +295,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
acquireFileService(fileService: IFileService): void {
this.fileService = fileService;
const changedWorkspaceFolders: IWorkspaceFolder[] = [];
this.localUserConfiguration.adopt(fileService);
Promise.all([this.workspaceConfiguration.adopt(fileService), ...this.cachedFolderConfigs.values()
.map(folderConfiguration => folderConfiguration.adopt(fileService)
.then(result => {
......@@ -446,12 +446,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.load() : Promise.resolve(new ConfigurationModel())])
return Promise.all([this.localUserConfiguration.initialize(), 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.load() : Promise.resolve(new ConfigurationModel())])
return Promise.all([this.localUserConfiguration.reload(), this.remoteUserConfiguration ? this.remoteUserConfiguration.reload() : Promise.resolve(new ConfigurationModel())])
.then(([local, remote]) => ({ local, remote }));
}
......@@ -645,7 +645,13 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
.then(() => {
switch (target) {
case ConfigurationTarget.USER:
return this.reloadUserConfiguration().then(_ => Promise.resolve());
return this.reloadUserConfiguration()
.then(({ local, remote }) => {
this.onLocalUserConfigurationChanged(local);
if (this.remoteUserConfiguration) {
this.onRemoteUserConfigurationChanged(remote);
}
});
case ConfigurationTarget.WORKSPACE:
return this.reloadWorkspaceConfiguration();
case ConfigurationTarget.WORKSPACE_FOLDER:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册