handle errors in config watcher

This commit is contained in:
Benjamin Pasero 2017-07-17 16:25:02 +02:00
parent a1789df48d
commit 99b26336d7
6 changed files with 15 additions and 9 deletions

View file

@ -26,6 +26,7 @@ export interface IConfigWatcher<T> {
}
export interface IConfigOptions<T> {
onError: (error: Error | string) => void;
defaultConfig?: T;
changeBufferDelay?: number;
parse?: (content: string, errors: any[]) => T;
@ -49,7 +50,7 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
private disposables: IDisposable[];
private _onDidUpdateConfiguration: Emitter<IConfigurationChangeEvent<T>>;
constructor(private _path: string, private options: IConfigOptions<T> = { changeBufferDelay: 0, defaultConfig: Object.create(null) }) {
constructor(private _path: string, private options: IConfigOptions<T> = { changeBufferDelay: 0, defaultConfig: Object.create(null), onError: error => console.error(error) }) {
this.disposables = [];
this._onDidUpdateConfiguration = new Emitter<IConfigurationChangeEvent<T>>();
@ -150,6 +151,7 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
try {
const watcher = fs.watch(path);
watcher.on('change', () => this.onConfigFileChange());
watcher.on('error', (code, signal) => this.options.onError(`Error watching ${path} for configuration changes (${code}, ${signal})`));
this.disposables.push(toDisposable(() => {
watcher.removeAllListeners();
@ -158,7 +160,7 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
} catch (error) {
fs.exists(path, exists => {
if (exists) {
console.warn(`Failed to watch ${path} for configuration changes (${error.toString()})`);
this.options.onError(`Failed to watch ${path} for configuration changes (${error.toString()})`);
}
});
}

View file

@ -42,7 +42,7 @@ suite('Config', () => {
watcher.dispose();
let watcher2 = new ConfigWatcher<any[]>(testFile, { defaultConfig: ['foo'] });
let watcher2 = new ConfigWatcher<any[]>(testFile, { defaultConfig: ['foo'], onError: console.error });
let config2 = watcher2.getConfig();
assert.ok(Array.isArray(config2));
@ -184,7 +184,7 @@ suite('Config', () => {
fs.writeFileSync(testFile, '// my comment\n{ "foo": "bar" }');
let watcher = new ConfigWatcher<{ foo: string; }>(testFile, { changeBufferDelay: 100 });
let watcher = new ConfigWatcher<{ foo: string; }>(testFile, { changeBufferDelay: 100, onError: console.error });
watcher.getConfig(); // ensure we are in sync
fs.writeFileSync(testFile, '// my comment\n{ "foo": "changed" }');

View file

@ -15,6 +15,7 @@ import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybindin
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ipcMain as ipc } from 'electron';
import { IWindowsMainService } from "vs/platform/windows/electron-main/windows";
import { ILogService } from "vs/platform/log/common/log";
export class KeyboardLayoutMonitor {
@ -95,11 +96,12 @@ export class KeybindingsResolver {
constructor(
@IStorageService private storageService: IStorageService,
@IEnvironmentService environmentService: IEnvironmentService,
@IWindowsMainService private windowsService: IWindowsMainService
@IWindowsMainService private windowsService: IWindowsMainService,
@ILogService private logService: ILogService
) {
this.commandIds = new Set<string>();
this.keybindings = this.storageService.getItem<{ [id: string]: string; }>(KeybindingsResolver.lastKnownKeybindingsMapStorageKey) || Object.create(null);
this.keybindingsWatcher = new ConfigWatcher<IUserFriendlyKeybinding[]>(environmentService.appKeybindingsPath, { changeBufferDelay: 100 });
this.keybindingsWatcher = new ConfigWatcher<IUserFriendlyKeybinding[]>(environmentService.appKeybindingsPath, { changeBufferDelay: 100, onError: error => this.logService.error(error) });
this.registerListeners();
}

View file

@ -13,6 +13,7 @@ import { ConfigurationSource, IConfigurationService, IConfigurationServiceEvent,
import { CustomConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/model';
import Event, { Emitter } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { onUnexpectedError } from "vs/base/common/errors";
export class ConfigurationService<T> extends Disposable implements IConfigurationService, IDisposable {
@ -30,7 +31,7 @@ export class ConfigurationService<T> extends Disposable implements IConfiguratio
super();
this.userConfigModelWatcher = new ConfigWatcher(environmentService.appSettingsPath, {
changeBufferDelay: 300, defaultConfig: new CustomConfigurationModel<T>(null, environmentService.appSettingsPath), parse: (content: string, parseErrors: any[]) => {
changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new CustomConfigurationModel<T>(null, environmentService.appSettingsPath), parse: (content: string, parseErrors: any[]) => {
const userConfigModel = new CustomConfigurationModel<T>(content, environmentService.appSettingsPath);
parseErrors = [...userConfigModel.errors];
return userConfigModel;

View file

@ -584,7 +584,7 @@ class WorkspaceConfiguration extends Disposable {
this._workspaceConfigurationWatcherDisposables = dispose(this._workspaceConfigurationWatcherDisposables);
return new TPromise<void>((c, e) => {
this._workspaceConfigurationWatcher = new ConfigWatcher(this._workspaceConfigPath.fsPath, {
changeBufferDelay: 300, defaultConfig: new WorkspaceConfigurationModel(null, this._workspaceConfigPath.fsPath), parse: (content: string, parseErrors: any[]) => {
changeBufferDelay: 300, onError: error => errors.onUnexpectedError(error), defaultConfig: new WorkspaceConfigurationModel(null, this._workspaceConfigPath.fsPath), parse: (content: string, parseErrors: any[]) => {
const workspaceConfigurationModel = new WorkspaceConfigurationModel(content, this._workspaceConfigPath.fsPath);
parseErrors = [...workspaceConfigurationModel.errors];
return workspaceConfigurationModel;

View file

@ -36,6 +36,7 @@ import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding
import Event, { Emitter } from 'vs/base/common/event';
import { Extensions as ConfigExtensions, IConfigurationRegistry, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { onUnexpectedError } from "vs/base/common/errors";
export class KeyboardMapperFactory {
public static INSTANCE = new KeyboardMapperFactory();
@ -294,7 +295,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService {
this._cachedResolver = null;
this._firstTimeComputingResolver = true;
this.userKeybindings = new ConfigWatcher(environmentService.appKeybindingsPath, { defaultConfig: [] });
this.userKeybindings = new ConfigWatcher(environmentService.appKeybindingsPath, { defaultConfig: [], onError: error => onUnexpectedError(error) });
this.toDispose.push(toDisposable(() => this.userKeybindings.dispose()));
keybindingsExtPoint.setHandler((extensions) => {