Add watchDirectory to be using dynamic polling
This commit is contained in:
parent
f4954d0529
commit
56d754cf0f
4 changed files with 69 additions and 31 deletions
|
@ -494,7 +494,7 @@ namespace ts {
|
|||
const useNonPollingWatchers = process.env.TSC_NONPOLLING_WATCHER;
|
||||
const tscWatchFile = process.env.TSC_WATCHFILE;
|
||||
const tscWatchDirectory = process.env.TSC_WATCHDIRECTORY;
|
||||
|
||||
let dynamicPollingWatchFile: HostWatchFile | undefined;
|
||||
const nodeSystem: System = {
|
||||
args: process.argv.slice(2),
|
||||
newLine: _os.EOL,
|
||||
|
@ -607,7 +607,8 @@ namespace ts {
|
|||
return watchFileUsingFsWatch;
|
||||
case "UseFsEventsWithFallbackDynamicPolling":
|
||||
// Use notifications from FS to watch with falling back to dynamic watch file
|
||||
return watchFileUsingDynamicWatchFile;
|
||||
dynamicPollingWatchFile = createDynamicPriorityPollingWatchFile(nodeSystem);
|
||||
return createWatchFileUsingDynamicWatchFile(dynamicPollingWatchFile);
|
||||
}
|
||||
return useNonPollingWatchers ?
|
||||
createNonPollingWatchFile() :
|
||||
|
@ -623,7 +624,11 @@ namespace ts {
|
|||
return watchDirectoryUsingFsWatch;
|
||||
}
|
||||
|
||||
const watchDirectory = tscWatchDirectory === "RecursiveDirectoryUsingFsWatchFile" ? watchDirectoryUsingFsWatchFile : watchDirectoryUsingFsWatch;
|
||||
const watchDirectory = tscWatchDirectory === "RecursiveDirectoryUsingFsWatchFile" ?
|
||||
createWatchDirectoryUsing(fsWatchFile) :
|
||||
tscWatchDirectory === "RecursiveDirectoryUsingDynamicPriorityPolling" ?
|
||||
createWatchDirectoryUsing(dynamicPollingWatchFile || createDynamicPriorityPollingWatchFile(nodeSystem)) :
|
||||
watchDirectoryUsingFsWatch;
|
||||
const watchDirectoryRecursively = createRecursiveDirectoryWatcher({
|
||||
filePathComparer: useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
|
||||
directoryExists,
|
||||
|
@ -838,9 +843,8 @@ namespace ts {
|
|||
return fsWatch(fileName, FileSystemEntryKind.File, createFsWatchCallbackForFileWatcherCallback(fileName, callback), /*recursive*/ false, fsWatchFile, pollingInterval);
|
||||
}
|
||||
|
||||
function watchFileUsingDynamicWatchFile(fileName: string, callback: FileWatcherCallback, pollingInterval?: number) {
|
||||
const watchFile = createDynamicPriorityPollingWatchFile(nodeSystem);
|
||||
return fsWatch(fileName, FileSystemEntryKind.File, createFsWatchCallbackForFileWatcherCallback(fileName, callback), /*recursive*/ false, watchFile, pollingInterval);
|
||||
function createWatchFileUsingDynamicWatchFile(watchFile: HostWatchFile): HostWatchFile {
|
||||
return (fileName, callback, pollingInterval) => fsWatch(fileName, FileSystemEntryKind.File, createFsWatchCallbackForFileWatcherCallback(fileName, callback), /*recursive*/ false, watchFile, pollingInterval);
|
||||
}
|
||||
|
||||
function fsWatchDirectory(directoryName: string, callback: FsWatchCallback, recursive?: boolean): FileWatcher {
|
||||
|
@ -851,8 +855,8 @@ namespace ts {
|
|||
return fsWatchDirectory(directoryName, createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback), recursive);
|
||||
}
|
||||
|
||||
function watchDirectoryUsingFsWatchFile(directoryName: string, callback: DirectoryWatcherCallback) {
|
||||
return fsWatchFile(directoryName, () => callback(directoryName), PollingInterval.Medium);
|
||||
function createWatchDirectoryUsing(fsWatchFile: HostWatchFile): HostWatchDirectory {
|
||||
return (directoryName, callback) => fsWatchFile(directoryName, () => callback(directoryName), PollingInterval.Medium);
|
||||
}
|
||||
|
||||
function readFile(fileName: string, _encoding?: string): string | undefined {
|
||||
|
|
|
@ -2177,7 +2177,7 @@ declare module "fs" {
|
|||
});
|
||||
|
||||
describe("tsc-watch when watchDirectories implementation", () => {
|
||||
function verifyRenamingFileInSubFolder(usesWatchFile: boolean) {
|
||||
function verifyRenamingFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) {
|
||||
const projectFolder = "/a/username/project";
|
||||
const projectSrcFolder = `${projectFolder}/src`;
|
||||
const configFile: FileOrFolder = {
|
||||
|
@ -2191,14 +2191,14 @@ declare module "fs" {
|
|||
const programFiles = [file, libFile];
|
||||
const files = [file, configFile, libFile];
|
||||
const environmentVariables = createMap<string>();
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", usesWatchFile ? "RecursiveDirectoryUsingFsWatchFile" : "RecursiveDirectoryUsingNonRecursiveWatchDirectory");
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", tscWatchDirectory);
|
||||
const host = createWatchedSystem(files, { environmentVariables });
|
||||
const watch = createWatchModeWithConfigFile(configFile.path, host);
|
||||
const projectFolders = [projectFolder, projectSrcFolder, `${projectFolder}/node_modules/@types`];
|
||||
// Watching files config file, file, lib file
|
||||
const expectedWatchedFiles = files.map(f => f.path);
|
||||
const expectedWatchedDirectories = usesWatchFile ? [] : projectFolders;
|
||||
if (usesWatchFile) {
|
||||
const expectedWatchedDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ? projectFolders : emptyArray;
|
||||
if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile) {
|
||||
expectedWatchedFiles.push(...projectFolders);
|
||||
}
|
||||
|
||||
|
@ -2208,31 +2208,40 @@ declare module "fs" {
|
|||
file.path = file.path.replace("file1.ts", "file2.ts");
|
||||
expectedWatchedFiles[0] = file.path;
|
||||
host.reloadFS(files);
|
||||
if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling) {
|
||||
// With dynamic polling the fs change would be detected only by running timeouts
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
}
|
||||
// Delayed update program
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyProgram(checkOutputErrorsIncremental);
|
||||
|
||||
function verifyProgram(checkOutputErrors: (host: WatchedSystem, errors: ReadonlyArray<Diagnostic>) => void) {
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
|
||||
|
||||
// Watching config file, file, lib file and directories
|
||||
ts.TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedFiles", host.watchedFiles, expectedWatchedFiles, 1);
|
||||
ts.TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedDirectories", host.watchedDirectories, expectedWatchedDirectories, 1);
|
||||
|
||||
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
|
||||
checkOutputErrors(host, emptyArray);
|
||||
|
||||
const outputFile = changeExtension(file.path, ".js");
|
||||
assert(host.fileExists(outputFile));
|
||||
assert.equal(host.readFile(outputFile), file.content);
|
||||
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
|
||||
|
||||
// Watching config file, file, lib file and directories
|
||||
ts.TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedFiles", host.watchedFiles, expectedWatchedFiles, 1);
|
||||
ts.TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedDirectories", host.watchedDirectories, expectedWatchedDirectories, 1);
|
||||
}
|
||||
}
|
||||
|
||||
it("uses watchFile when renaming file in subfolder", () => {
|
||||
verifyRenamingFileInSubFolder(/*usesWatchFile*/ true);
|
||||
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile);
|
||||
});
|
||||
|
||||
it("uses non recursive watchDirectory when renaming file in subfolder", () => {
|
||||
verifyRenamingFileInSubFolder(/*usesWatchFile*/ false);
|
||||
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory);
|
||||
});
|
||||
|
||||
it("uses non recursive dynamic polling when renaming file in subfolder", () => {
|
||||
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6581,7 +6581,7 @@ namespace ts.projectSystem {
|
|||
});
|
||||
|
||||
describe("watchDirectories implementation", () => {
|
||||
function verifyCompletionListWithNewFileInSubFolder(usesWatchFile: boolean) {
|
||||
function verifyCompletionListWithNewFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) {
|
||||
const projectFolder = "/a/username/project";
|
||||
const projectSrcFolder = `${projectFolder}/src`;
|
||||
const configFile: FileOrFolder = {
|
||||
|
@ -6602,7 +6602,11 @@ namespace ts.projectSystem {
|
|||
// All closed files(files other than index), project folder, project/src folder and project/node_modules/@types folder
|
||||
const expectedWatchedFiles = arrayToMap(fileNames.slice(1), s => s, () => 1);
|
||||
const expectedWatchedDirectories = createMap<number>();
|
||||
const mapOfDirectories = usesWatchFile ? expectedWatchedFiles : expectedWatchedDirectories;
|
||||
const mapOfDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ?
|
||||
expectedWatchedDirectories :
|
||||
tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile ?
|
||||
expectedWatchedFiles :
|
||||
createMap();
|
||||
// For failed resolution lookup and tsconfig files
|
||||
mapOfDirectories.set(projectFolder, 2);
|
||||
// Through above recursive watches
|
||||
|
@ -6612,7 +6616,7 @@ namespace ts.projectSystem {
|
|||
const expectedCompletions = ["file1"];
|
||||
const completionPosition = index.content.lastIndexOf('"');
|
||||
const environmentVariables = createMap<string>();
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", usesWatchFile ? "RecursiveDirectoryUsingFsWatchFile" : "RecursiveDirectoryUsingNonRecursiveWatchDirectory");
|
||||
environmentVariables.set("TSC_WATCHDIRECTORY", tscWatchDirectory);
|
||||
const host = createServerHost(files, { environmentVariables });
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(index.path);
|
||||
|
@ -6636,23 +6640,27 @@ namespace ts.projectSystem {
|
|||
verifyProjectAndCompletions();
|
||||
|
||||
function verifyProjectAndCompletions() {
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(index.path, completionPosition, { includeExternalModuleExports: false, includeInsertTextCompletions: false });
|
||||
checkArray("Completion Entries", completions.entries.map(e => e.name), expectedCompletions);
|
||||
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
|
||||
|
||||
ts.TestFSWithWatch.checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedWatchedFiles);
|
||||
ts.TestFSWithWatch.checkMultiMapKeyCount("watchedDirectories", host.watchedDirectories, expectedWatchedDirectories);
|
||||
checkProjectActualFiles(project, fileNames);
|
||||
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(index.path, completionPosition, { includeExternalModuleExports: false, includeInsertTextCompletions: false });
|
||||
checkArray("Completion Entries", completions.entries.map(e => e.name), expectedCompletions);
|
||||
}
|
||||
}
|
||||
|
||||
it("uses watchFile when file is added to subfolder, completion list has new file", () => {
|
||||
verifyCompletionListWithNewFileInSubFolder(/*usesWatchFile*/ true);
|
||||
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile);
|
||||
});
|
||||
|
||||
it("uses non recursive watchDirectory when file is added to subfolder, completion list has new file", () => {
|
||||
verifyCompletionListWithNewFileInSubFolder(/*usesWatchFile*/ false);
|
||||
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory);
|
||||
});
|
||||
|
||||
it("uses dynamic polling when file is added to subfolder, completion list has new file", () => {
|
||||
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -257,6 +257,12 @@ interface Array<T> {}`
|
|||
ignoreWatchInvokedWithTriggerAsFileCreate: boolean;
|
||||
}
|
||||
|
||||
export enum Tsc_WatchDirectory {
|
||||
WatchFile = "RecursiveDirectoryUsingFsWatchFile",
|
||||
NonRecursiveWatchDirectory = "RecursiveDirectoryUsingNonRecursiveWatchDirectory",
|
||||
DynamicPolling = "RecursiveDirectoryUsingDynamicPriorityPolling"
|
||||
}
|
||||
|
||||
export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost {
|
||||
args: string[] = [];
|
||||
|
||||
|
@ -286,8 +292,8 @@ interface Array<T> {}`
|
|||
this.dynamicPriorityWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") === "DynamicPriorityPolling" ?
|
||||
createDynamicPriorityPollingWatchFile(this) :
|
||||
undefined;
|
||||
const tscWatchDirectory = this.environmentVariables && this.environmentVariables.get("TSC_WATCHDIRECTORY");
|
||||
if (tscWatchDirectory === "RecursiveDirectoryUsingFsWatchFile") {
|
||||
const tscWatchDirectory = this.environmentVariables && this.environmentVariables.get("TSC_WATCHDIRECTORY") as Tsc_WatchDirectory;
|
||||
if (tscWatchDirectory === Tsc_WatchDirectory.WatchFile) {
|
||||
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchFile(directory, () => cb(directory), PollingInterval.Medium);
|
||||
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
|
||||
directoryExists: path => this.directoryExists(path),
|
||||
|
@ -296,7 +302,7 @@ interface Array<T> {}`
|
|||
watchDirectory
|
||||
});
|
||||
}
|
||||
else if (tscWatchDirectory === "RecursiveDirectoryUsingNonRecursiveWatchDirectory") {
|
||||
else if (tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory) {
|
||||
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchDirectory(directory, fileName => cb(fileName), /*recursive*/ false);
|
||||
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
|
||||
directoryExists: path => this.directoryExists(path),
|
||||
|
@ -305,6 +311,16 @@ interface Array<T> {}`
|
|||
watchDirectory
|
||||
});
|
||||
}
|
||||
else if (tscWatchDirectory === Tsc_WatchDirectory.DynamicPolling) {
|
||||
const watchFile = createDynamicPriorityPollingWatchFile(this);
|
||||
const watchDirectory: HostWatchDirectory = (directory, cb) => watchFile(directory, () => cb(directory), PollingInterval.Medium);
|
||||
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
|
||||
directoryExists: path => this.directoryExists(path),
|
||||
getAccessileSortedChildDirectories: path => this.getDirectories(path),
|
||||
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
|
||||
watchDirectory
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getNewLine() {
|
||||
|
@ -348,6 +364,7 @@ interface Array<T> {}`
|
|||
if (currentEntry.content !== fileOrDirectory.content) {
|
||||
currentEntry.content = fileOrDirectory.content;
|
||||
currentEntry.modifiedTime = new Date();
|
||||
this.fs.get(getDirectoryPath(currentEntry.path)).modifiedTime = new Date();
|
||||
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
|
||||
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue