Skip to content

Commit 70953ac

Browse files
author
Benjamin Pasero
committed
debt - adopt IPC utilities for chokidar watcher service
1 parent 795b0db commit 70953ac

8 files changed

Lines changed: 64 additions & 357 deletions

File tree

src/vs/platform/files/node/watcher/nsfw/test/nsfwWatcherService.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import * as assert from 'assert';
77
import * as platform from 'vs/base/common/platform';
8-
98
import { NsfwWatcherService } from 'vs/platform/files/node/watcher/nsfw/nsfwWatcherService';
109
import { IWatcherRequest } from 'vs/platform/files/node/watcher/nsfw/watcher';
1110

src/vs/platform/files/node/watcher/nsfw/watcher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export interface IWatcherRequest {
1313

1414
export interface IWatcherService {
1515

16-
readonly onDidLogMessage: Event<ILogMessage>;
1716
readonly onDidChangeFile: Event<IDiskFileChange[]>;
17+
readonly onDidLogMessage: Event<ILogMessage>;
1818

1919
setRoots(roots: IWatcherRequest[]): Promise<void>;
2020
setVerboseLogging(enabled: boolean): Promise<void>;

src/vs/platform/files/node/watcher/unix/chokidarWatcherService.ts

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/platform/
1818
import { IWatcherRequest, IWatcherService, IWatcherOptions } from 'vs/platform/files/node/watcher/unix/watcher';
1919
import { Emitter, Event } from 'vs/base/common/event';
2020
import { equals } from 'vs/base/common/arrays';
21+
import { Disposable } from 'vs/base/common/lifecycle';
2122

2223
process.noAsar = true; // disable ASAR support in watcher process
2324

@@ -30,81 +31,76 @@ interface ExtendedWatcherRequest extends IWatcherRequest {
3031
parsedPattern?: glob.ParsedPattern;
3132
}
3233

33-
export class ChokidarWatcherService implements IWatcherService {
34+
export class ChokidarWatcherService extends Disposable implements IWatcherService {
3435

3536
private static readonly FS_EVENT_DELAY = 50; // aggregate and only emit events when changes have stopped for this duration (in ms)
3637
private static readonly EVENT_SPAM_WARNING_THRESHOLD = 60 * 1000; // warn after certain time span of event spam
3738

38-
private _watchers: { [watchPath: string]: IWatcher } = Object.create(null);
39+
private readonly _onDidChangeFile = this._register(new Emitter<IDiskFileChange[]>());
40+
readonly onDidChangeFile = this._onDidChangeFile.event;
41+
42+
private readonly _onDidLogMessage = this._register(new Emitter<ILogMessage>());
43+
readonly onDidLogMessage: Event<ILogMessage> = this._onDidLogMessage.event;
44+
45+
private watchers = new Map<string, IWatcher>();
46+
3947
private _watcherCount = 0;
48+
get wacherCount() { return this._watcherCount; }
4049

41-
private _pollingInterval?: number;
42-
private _usePolling?: boolean;
43-
private _verboseLogging: boolean | undefined;
50+
private pollingInterval?: number;
51+
private usePolling?: boolean;
52+
private verboseLogging: boolean | undefined;
4453

4554
private spamCheckStartTime: number | undefined;
4655
private spamWarningLogged: boolean | undefined;
4756
private enospcErrorLogged: boolean | undefined;
4857

49-
private readonly _onWatchEvent = new Emitter<IDiskFileChange[]>();
50-
readonly onWatchEvent = this._onWatchEvent.event;
51-
52-
private readonly _onLogMessage = new Emitter<ILogMessage>();
53-
readonly onLogMessage: Event<ILogMessage> = this._onLogMessage.event;
54-
55-
watch(options: IWatcherOptions): Event<IDiskFileChange[]> {
56-
this._pollingInterval = options.pollingInterval;
57-
this._usePolling = options.usePolling;
58-
this._watchers = Object.create(null);
58+
async init(options: IWatcherOptions): Promise<void> {
59+
this.pollingInterval = options.pollingInterval;
60+
this.usePolling = options.usePolling;
61+
this.watchers.clear();
5962
this._watcherCount = 0;
60-
61-
return this.onWatchEvent;
63+
this.verboseLogging = options.verboseLogging;
6264
}
6365

6466
async setVerboseLogging(enabled: boolean): Promise<void> {
65-
this._verboseLogging = enabled;
67+
this.verboseLogging = enabled;
6668
}
6769

6870
async setRoots(requests: IWatcherRequest[]): Promise<void> {
69-
const watchers = Object.create(null);
71+
const watchers = new Map<string, IWatcher>();
7072
const newRequests: string[] = [];
7173

7274
const requestsByBasePath = normalizeRoots(requests);
7375

7476
// evaluate new & remaining watchers
7577
for (const basePath in requestsByBasePath) {
76-
const watcher = this._watchers[basePath];
78+
const watcher = this.watchers.get(basePath);
7779
if (watcher && isEqualRequests(watcher.requests, requestsByBasePath[basePath])) {
78-
watchers[basePath] = watcher;
79-
delete this._watchers[basePath];
80+
watchers.set(basePath, watcher);
81+
this.watchers.delete(basePath);
8082
} else {
8183
newRequests.push(basePath);
8284
}
8385
}
8486

8587
// stop all old watchers
86-
for (const path in this._watchers) {
87-
await this._watchers[path].stop();
88+
for (const [, watcher] of this.watchers) {
89+
await watcher.stop();
8890
}
8991

9092
// start all new watchers
9193
for (const basePath of newRequests) {
9294
const requests = requestsByBasePath[basePath];
93-
watchers[basePath] = this._watch(basePath, requests);
95+
watchers.set(basePath, this.watch(basePath, requests));
9496
}
9597

96-
this._watchers = watchers;
98+
this.watchers = watchers;
9799
}
98100

99-
// for test purposes
100-
get wacherCount() {
101-
return this._watcherCount;
102-
}
103-
104-
private _watch(basePath: string, requests: IWatcherRequest[]): IWatcher {
105-
106-
const pollingInterval = this._pollingInterval || 5000;
107-
const usePolling = this._usePolling;
101+
private watch(basePath: string, requests: IWatcherRequest[]): IWatcher {
102+
const pollingInterval = this.pollingInterval || 5000;
103+
const usePolling = this.usePolling;
108104

109105
const watcherOpts: chokidar.WatchOptions = {
110106
ignoreInitial: true,
@@ -120,8 +116,7 @@ export class ChokidarWatcherService implements IWatcherService {
120116

121117
const isSingleFolder = requests.length === 1;
122118
if (isSingleFolder) {
123-
// if there's only one request, use the built-in ignore-filterering
124-
excludes.push(...requests[0].excludes);
119+
excludes.push(...requests[0].excludes); // if there's only one request, use the built-in ignore-filterering
125120
}
126121

127122
if ((isMacintosh || isLinux) && (basePath.length === 0 || basePath === '/')) {
@@ -146,7 +141,7 @@ export class ChokidarWatcherService implements IWatcherService {
146141
this.warn(`Watcher basePath does not match version on disk and was corrected (original: ${basePath}, real: ${realBasePath})`);
147142
}
148143

149-
if (this._verboseLogging) {
144+
if (this.verboseLogging) {
150145
this.log(`Start watching with chockidar: ${realBasePath}, excludes: ${excludes.join(',')}, usePolling: ${usePolling ? 'true, interval ' + pollingInterval : 'false'}`);
151146
}
152147

@@ -165,7 +160,7 @@ export class ChokidarWatcherService implements IWatcherService {
165160
requests,
166161
stop: async () => {
167162
try {
168-
if (this._verboseLogging) {
163+
if (this.verboseLogging) {
169164
this.log(`Stop watching: ${basePath}]`);
170165
}
171166
if (chokidarWatcher) {
@@ -227,7 +222,7 @@ export class ChokidarWatcherService implements IWatcherService {
227222
const event = { type: eventType, path };
228223

229224
// Logging
230-
if (this._verboseLogging) {
225+
if (this.verboseLogging) {
231226
this.log(`${eventType === FileChangeType.ADDED ? '[ADDED]' : eventType === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${path}`);
232227
}
233228

@@ -253,10 +248,10 @@ export class ChokidarWatcherService implements IWatcherService {
253248

254249
// Broadcast to clients normalized
255250
const res = normalizeFileChanges(events);
256-
this._onWatchEvent.fire(res);
251+
this._onDidChangeFile.fire(res);
257252

258253
// Logging
259-
if (this._verboseLogging) {
254+
if (this.verboseLogging) {
260255
res.forEach(r => {
261256
this.log(` >> normalized ${r.type === FileChangeType.ADDED ? '[ADDED]' : r.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${r.path}`);
262257
});
@@ -290,24 +285,23 @@ export class ChokidarWatcherService implements IWatcherService {
290285
}
291286

292287
async stop(): Promise<void> {
293-
for (const path in this._watchers) {
294-
const watcher = this._watchers[path];
288+
for (const [, watcher] of this.watchers) {
295289
await watcher.stop();
296290
}
297291

298-
this._watchers = Object.create(null);
292+
this.watchers.clear();
299293
}
300294

301295
private log(message: string) {
302-
this._onLogMessage.fire({ type: 'trace', message: `[File Watcher (chokidar)] ` + message });
296+
this._onDidLogMessage.fire({ type: 'trace', message: `[File Watcher (chokidar)] ` + message });
303297
}
304298

305299
private warn(message: string) {
306-
this._onLogMessage.fire({ type: 'warn', message: `[File Watcher (chokidar)] ` + message });
300+
this._onDidLogMessage.fire({ type: 'warn', message: `[File Watcher (chokidar)] ` + message });
307301
}
308302

309303
private error(message: string) {
310-
this._onLogMessage.fire({ type: 'error', message: `[File Watcher (chokidar)] ` + message });
304+
this._onDidLogMessage.fire({ type: 'error', message: `[File Watcher (chokidar)] ` + message });
311305
}
312306
}
313307

0 commit comments

Comments
 (0)