Do not watch child directories of the sym link folders

Fixes #22668
This commit is contained in:
Sheetal Nandi 2018-03-28 18:37:07 -07:00
parent e40f2943b1
commit f885cd971e
3 changed files with 70 additions and 16 deletions

View File

@ -337,6 +337,7 @@ namespace ts {
getAccessileSortedChildDirectories(path: string): ReadonlyArray<string>;
directoryExists(dir: string): boolean;
filePathComparer: Comparer<string>;
realpath(s: string): string;
}
/**
@ -392,9 +393,12 @@ namespace ts {
function watchChildDirectories(parentDir: string, existingChildWatches: ChildWatches, callback: DirectoryWatcherCallback): ChildWatches {
let newChildWatches: DirectoryWatcher[] | undefined;
enumerateInsertsAndDeletes<string, DirectoryWatcher>(
host.directoryExists(parentDir) ? host.getAccessileSortedChildDirectories(parentDir) : emptyArray,
host.directoryExists(parentDir) ? mapDefined(host.getAccessileSortedChildDirectories(parentDir), child => {
const childFullName = getNormalizedAbsolutePath(child, parentDir);
return host.filePathComparer(childFullName, host.realpath(childFullName)) === Comparison.EqualTo ? childFullName : undefined;
}) : emptyArray,
existingChildWatches,
(child, childWatcher) => host.filePathComparer(getNormalizedAbsolutePath(child, parentDir), childWatcher.dirName),
(child, childWatcher) => host.filePathComparer(child, childWatcher.dirName),
createAndAddChildDirectoryWatcher,
closeFileWatcher,
addChildDirectoryWatcher
@ -406,7 +410,7 @@ namespace ts {
* Create new childDirectoryWatcher and add it to the new ChildDirectoryWatcher list
*/
function createAndAddChildDirectoryWatcher(childName: string) {
const result = createDirectoryWatcher(getNormalizedAbsolutePath(childName, parentDir), callback);
const result = createDirectoryWatcher(childName, callback);
addChildDirectoryWatcher(result);
}
@ -601,14 +605,7 @@ namespace ts {
exit(exitCode?: number): void {
process.exit(exitCode);
},
realpath(path: string): string {
try {
return _fs.realpathSync(path);
}
catch {
return path;
}
},
realpath,
debugMode: some(<string[]>process.execArgv, arg => /^--(inspect|debug)(-brk)?(=\d+)?$/i.test(arg)),
tryEnableSourceMapsForHost() {
try {
@ -700,7 +697,8 @@ namespace ts {
filePathComparer: useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
directoryExists,
getAccessileSortedChildDirectories: path => getAccessibleFileSystemEntries(path).directories,
watchDirectory
watchDirectory,
realpath
});
return (directoryName, callback, recursive) => {
@ -1043,6 +1041,15 @@ namespace ts {
return filter<string>(_fs.readdirSync(path), dir => fileSystemEntryExists(combinePaths(path, dir), FileSystemEntryKind.Directory));
}
function realpath(path: string): string {
try {
return _fs.realpathSync(path);
}
catch {
return path;
}
}
function getModifiedTime(path: string) {
try {
return _fs.statSync(path).mtime;

View File

@ -2358,6 +2358,50 @@ declare module "fs" {
it("uses non recursive dynamic polling when renaming file in subfolder", () => {
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
});
it("when there are symlinks to folders in recursive folders", () => {
const cwd = "/home/user/projects/myproject";
const file1: FileOrFolder = {
path: `${cwd}/src/file.ts`,
content: `import * as a from "a"`
};
const tsconfig: FileOrFolder = {
path: `${cwd}/tsconfig.json`,
content: `{ "compilerOptions": { "extendedDiagnostics": true, "traceResolution": true }}`
};
const realA: FileOrFolder = {
path: `${cwd}/node_modules/reala/index.d.ts`,
content: `export {}`
};
const realB: FileOrFolder = {
path: `${cwd}/node_modules/realb/index.d.ts`,
content: `export {}`
};
const symLinkA: FileOrFolder = {
path: `${cwd}/node_modules/a`,
symLink: `${cwd}/node_modules/reala`
};
const symLinkB: FileOrFolder = {
path: `${cwd}/node_modules/b`,
symLink: `${cwd}/node_modules/realb`
};
const symLinkBInA: FileOrFolder = {
path: `${cwd}/node_modules/reala/node_modules/b`,
symLink: `${cwd}/node_modules/b`
};
const symLinkAInB: FileOrFolder = {
path: `${cwd}/node_modules/realb/node_modules/a`,
symLink: `${cwd}/node_modules/a`
};
const files = [file1, tsconfig, realA, realB, symLinkA, symLinkB, symLinkBInA, symLinkAInB];
const environmentVariables = createMap<string>();
environmentVariables.set("TSC_WATCHDIRECTORY", TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory);
const host = createWatchedSystem(files, { environmentVariables, currentDirectory: cwd });
createWatchOfConfigFile("tsconfig.json", host);
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
checkWatchedDirectories(host, [cwd, `${cwd}/node_modules`, `${cwd}/node_modules/@types`, `${cwd}/node_modules/reala`, `${cwd}/node_modules/realb`,
`${cwd}/node_modules/reala/node_modules`, `${cwd}/node_modules/realb/node_modules`, `${cwd}/src`], /*recursive*/ false);
});
});
});
}

View File

@ -314,7 +314,8 @@ interface Array<T> {}`
directoryExists: path => this.directoryExists(path),
getAccessileSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory
watchDirectory,
realpath: s => this.realpath(s)
});
}
else if (tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory) {
@ -323,7 +324,8 @@ interface Array<T> {}`
directoryExists: path => this.directoryExists(path),
getAccessileSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory
watchDirectory,
realpath: s => this.realpath(s)
});
}
else if (tscWatchDirectory === Tsc_WatchDirectory.DynamicPolling) {
@ -333,7 +335,8 @@ interface Array<T> {}`
directoryExists: path => this.directoryExists(path),
getAccessileSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory
watchDirectory,
realpath: s => this.realpath(s)
});
}
}
@ -649,7 +652,7 @@ interface Array<T> {}`
const realpath = this.realpath(path);
if (path !== realpath) {
return this.getRealFsEntry(isFsEntry, realpath as Path);
return this.getRealFsEntry(isFsEntry, this.toPath(realpath));
}
return undefined;