提交 523f7893 编写于 作者: B Benjamin Pasero

fix #40533

上级 d8e9d0ed
......@@ -99,7 +99,7 @@ export class FileService extends Disposable implements IFileService {
get onDidChangeFileSystemProviderRegistrations(): Event<IFileSystemProviderRegistrationEvent> { return this._onDidChangeFileSystemProviderRegistrations.event; }
private activeWorkspaceFileChangeWatcher: IDisposable;
private activeFileChangesWatchers: ResourceMap<fs.FSWatcher>;
private activeFileChangesWatchers: ResourceMap<{ unwatch: Function, count: number }>;
private fileChangesWatchDelayer: ThrottledDelayer<void>;
private undeliveredRawFileChangesEvents: IRawFileChange[];
......@@ -117,7 +117,7 @@ export class FileService extends Disposable implements IFileService {
) {
super();
this.activeFileChangesWatchers = new ResourceMap<fs.FSWatcher>();
this.activeFileChangesWatchers = new ResourceMap<{ unwatch: Function, count: number }>();
this.fileChangesWatchDelayer = new ThrottledDelayer<void>(FileService.FS_EVENT_DELAY);
this.undeliveredRawFileChangesEvents = [];
......@@ -991,58 +991,67 @@ export class FileService extends Disposable implements IFileService {
watchFileChanges(resource: uri): void {
assert.ok(resource && resource.scheme === Schemas.file, `Invalid resource for watching: ${resource}`);
// Create or get watcher for provided path
let watcher = this.activeFileChangesWatchers.get(resource);
if (!watcher) {
const fsPath = resource.fsPath;
const fsName = paths.basename(resource.fsPath);
watcher = extfs.watch(fsPath, (eventType: string, filename: string) => {
const renamedOrDeleted = ((filename && filename !== fsName) || eventType === 'rename');
// The file was either deleted or renamed. Many tools apply changes to files in an
// atomic way ("Atomic Save") by first renaming the file to a temporary name and then
// renaming it back to the original name. Our watcher will detect this as a rename
// and then stops to work on Mac and Linux because the watcher is applied to the
// inode and not the name. The fix is to detect this case and trying to watch the file
// again after a certain delay.
// In addition, we send out a delete event if after a timeout we detect that the file
// does indeed not exist anymore.
if (renamedOrDeleted) {
// Very important to dispose the watcher which now points to a stale inode
this.unwatchFileChanges(resource);
// Wait a bit and try to install watcher again, assuming that the file was renamed quickly ("Atomic Save")
setTimeout(() => {
this.existsFile(resource).done(exists => {
// File still exists, so reapply the watcher
if (exists) {
this.watchFileChanges(resource);
}
// Check for existing watcher first
const entry = this.activeFileChangesWatchers.get(resource);
if (entry) {
entry.count += 1;
// File seems to be really gone, so emit a deleted event
else {
this.onRawFileChange({
type: FileChangeType.DELETED,
path: fsPath
});
}
});
}, FileService.FS_REWATCH_DELAY);
}
return;
}
// Handle raw file change
this.onRawFileChange({
type: FileChangeType.UPDATED,
path: fsPath
});
}, (error: string) => this.handleError(error));
// Create or get watcher for provided path
const fsPath = resource.fsPath;
const fsName = paths.basename(resource.fsPath);
const watcher = extfs.watch(fsPath, (eventType: string, filename: string) => {
const renamedOrDeleted = ((filename && filename !== fsName) || eventType === 'rename');
// The file was either deleted or renamed. Many tools apply changes to files in an
// atomic way ("Atomic Save") by first renaming the file to a temporary name and then
// renaming it back to the original name. Our watcher will detect this as a rename
// and then stops to work on Mac and Linux because the watcher is applied to the
// inode and not the name. The fix is to detect this case and trying to watch the file
// again after a certain delay.
// In addition, we send out a delete event if after a timeout we detect that the file
// does indeed not exist anymore.
if (renamedOrDeleted) {
// Very important to dispose the watcher which now points to a stale inode
this.unwatchFileChanges(resource);
// Wait a bit and try to install watcher again, assuming that the file was renamed quickly ("Atomic Save")
setTimeout(() => {
this.existsFile(resource).done(exists => {
// File still exists, so reapply the watcher
if (exists) {
this.watchFileChanges(resource);
}
if (watcher) {
this.activeFileChangesWatchers.set(resource, watcher);
// File seems to be really gone, so emit a deleted event
else {
this.onRawFileChange({
type: FileChangeType.DELETED,
path: fsPath
});
}
});
}, FileService.FS_REWATCH_DELAY);
}
// Handle raw file change
this.onRawFileChange({
type: FileChangeType.UPDATED,
path: fsPath
});
}, (error: string) => this.handleError(error));
// Remember in map
if (watcher) {
this.activeFileChangesWatchers.set(resource, {
count: 1,
unwatch: () => watcher.close()
});
}
}
......@@ -1079,8 +1088,8 @@ export class FileService extends Disposable implements IFileService {
unwatchFileChanges(resource: uri): void {
const watcher = this.activeFileChangesWatchers.get(resource);
if (watcher) {
watcher.close();
if (watcher && --watcher.count === 0) {
watcher.unwatch();
this.activeFileChangesWatchers.delete(resource);
}
}
......@@ -1093,7 +1102,7 @@ export class FileService extends Disposable implements IFileService {
this.activeWorkspaceFileChangeWatcher = null;
}
this.activeFileChangesWatchers.forEach(watcher => watcher.close());
this.activeFileChangesWatchers.forEach(watcher => watcher.unwatch());
this.activeFileChangesWatchers.clear();
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册