Skip to content

Commit

Permalink
Handle exclude options in the system watches
Browse files Browse the repository at this point in the history
  • Loading branch information
sheetalkamat committed Jun 24, 2020
1 parent 317a35d commit dddd906
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 30 deletions.
83 changes: 59 additions & 24 deletions src/compiler/sys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ namespace ts {
export interface RecursiveDirectoryWatcherHost {
watchDirectory: HostWatchDirectory;
useCaseSensitiveFileNames: boolean;
getCurrentDirectory: System["getCurrentDirectory"];
getAccessibleSortedChildDirectories(path: string): readonly string[];
directoryExists(dir: string): boolean;
realpath(s: string): string;
Expand All @@ -462,7 +463,16 @@ namespace ts {
* (eg on OS that dont support recursive watch using fs.watch use fs.watchFile)
*/
/*@internal*/
export function createDirectoryWatcherSupportingRecursive(host: RecursiveDirectoryWatcherHost): HostWatchDirectory {
export function createDirectoryWatcherSupportingRecursive({
watchDirectory,
useCaseSensitiveFileNames,
getCurrentDirectory,
getAccessibleSortedChildDirectories,
directoryExists,
realpath,
setTimeout,
clearTimeout
}: RecursiveDirectoryWatcherHost): HostWatchDirectory {
interface ChildDirectoryWatcher extends FileWatcher {
dirName: string;
}
Expand All @@ -478,12 +488,12 @@ namespace ts {
const cacheToUpdateChildWatches = createMap<{ dirName: string; options: WatchOptions | undefined; fileNames: string[]; }>();
let timerToUpdateChildWatches: any;

const filePathComparer = getStringComparer(!host.useCaseSensitiveFileNames);
const toCanonicalFilePath = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
const filePathComparer = getStringComparer(!useCaseSensitiveFileNames);
const toCanonicalFilePath = createGetCanonicalFileName(useCaseSensitiveFileNames);

return (dirName, callback, recursive, options) => recursive ?
createDirectoryWatcher(dirName, options, callback) :
host.watchDirectory(dirName, callback, recursive, options);
watchDirectory(dirName, callback, recursive, options);

/**
* Create the directory watcher for the dirPath.
Expand All @@ -496,8 +506,8 @@ namespace ts {
}
else {
directoryWatcher = {
watcher: host.watchDirectory(dirName, fileName => {
if (isIgnoredPath(fileName)) return;
watcher: watchDirectory(dirName, fileName => {
if (isIgnoredPath(fileName, options)) return;

if (options?.synchronousWatchDirectory) {
// Call the actual callback
Expand Down Expand Up @@ -578,7 +588,7 @@ namespace ts {
function nonSyncUpdateChildWatches(dirName: string, dirPath: Path, fileName: string, options: WatchOptions | undefined) {
// Iterate through existing children and update the watches if needed
const parentWatcher = cache.get(dirPath);
if (parentWatcher && host.directoryExists(dirName)) {
if (parentWatcher && directoryExists(dirName)) {
// Schedule the update and postpone invoke for callbacks
scheduleUpdateChildWatches(dirName, dirPath, fileName, options);
return;
Expand All @@ -598,10 +608,10 @@ namespace ts {
cacheToUpdateChildWatches.set(dirPath, { dirName, options, fileNames: [fileName] });
}
if (timerToUpdateChildWatches) {
host.clearTimeout(timerToUpdateChildWatches);
clearTimeout(timerToUpdateChildWatches);
timerToUpdateChildWatches = undefined;
}
timerToUpdateChildWatches = host.setTimeout(onTimerToUpdateChildWatches, 1000);
timerToUpdateChildWatches = setTimeout(onTimerToUpdateChildWatches, 1000);
}

function onTimerToUpdateChildWatches() {
Expand Down Expand Up @@ -655,11 +665,11 @@ namespace ts {
if (!parentWatcher) return false;
let newChildWatches: ChildDirectoryWatcher[] | undefined;
const hasChanges = enumerateInsertsAndDeletes<string, ChildDirectoryWatcher>(
host.directoryExists(parentDir) ? mapDefined(host.getAccessibleSortedChildDirectories(parentDir), child => {
directoryExists(parentDir) ? mapDefined(getAccessibleSortedChildDirectories(parentDir), child => {
const childFullName = getNormalizedAbsolutePath(child, parentDir);
// Filter our the symbolic link directories since those arent included in recursive watch
// which is same behaviour when recursive: true is passed to fs.watch
return !isIgnoredPath(childFullName) && filePathComparer(childFullName, normalizePath(host.realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined;
return !isIgnoredPath(childFullName, options) && filePathComparer(childFullName, normalizePath(realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined;
}) : emptyArray,
parentWatcher.childWatches,
(child, childWatcher) => filePathComparer(child, childWatcher.dirName),
Expand All @@ -686,13 +696,14 @@ namespace ts {
}
}

function isIgnoredPath(path: string) {
return some(ignoredPaths, searchPath => isInPath(path, searchPath));
function isIgnoredPath(path: string, options: WatchOptions | undefined) {
return some(ignoredPaths, searchPath => isInPath(path, searchPath)) ||
isIgnoredByWatchOptions(path, options, useCaseSensitiveFileNames, getCurrentDirectory);
}

function isInPath(path: string, searchPath: string) {
if (stringContains(path, searchPath)) return true;
if (host.useCaseSensitiveFileNames) return false;
if (useCaseSensitiveFileNames) return false;
return stringContains(toCanonicalFilePath(path), searchPath);
}
}
Expand Down Expand Up @@ -729,14 +740,35 @@ namespace ts {
};
}

function createFsWatchCallbackForDirectoryWatcherCallback(directoryName: string, callback: DirectoryWatcherCallback): FsWatchCallback {
function isIgnoredByWatchOptions(
pathToCheck: string,
options: WatchOptions | undefined,
useCaseSensitiveFileNames: boolean,
getCurrentDirectory: System["getCurrentDirectory"],
) {
return (options?.excludeDirectories || options?.excludeFiles) && (
matchesExclude(pathToCheck, options?.excludeFiles, useCaseSensitiveFileNames, getCurrentDirectory()) ||
matchesExclude(pathToCheck, options?.excludeDirectories, useCaseSensitiveFileNames, getCurrentDirectory())
);
}

function createFsWatchCallbackForDirectoryWatcherCallback(
directoryName: string,
callback: DirectoryWatcherCallback,
options: WatchOptions | undefined,
useCaseSensitiveFileNames: boolean,
getCurrentDirectory: System["getCurrentDirectory"],
): FsWatchCallback {
return (eventName, relativeFileName) => {
// In watchDirectory we only care about adding and removing files (when event name is
// "rename"); changes made within files are handled by corresponding fileWatchers (when
// event name is "change")
if (eventName === "rename") {
// When deleting a file, the passed baseFileName is null
callback(!relativeFileName ? directoryName : normalizePath(combinePaths(directoryName, relativeFileName)));
const fileName = !relativeFileName ? directoryName : normalizePath(combinePaths(directoryName, relativeFileName));
if (!relativeFileName || !isIgnoredByWatchOptions(fileName, options, useCaseSensitiveFileNames, getCurrentDirectory)) {
callback(fileName);
}
}
};
}
Expand All @@ -753,6 +785,7 @@ namespace ts {
fsWatch: FsWatch;
fileExists: System["fileExists"];
useCaseSensitiveFileNames: boolean;
getCurrentDirectory: System["getCurrentDirectory"];
fsSupportsRecursiveFsWatch: boolean;
directoryExists: System["directoryExists"];
getAccessibleSortedChildDirectories(path: string): readonly string[];
Expand All @@ -772,6 +805,7 @@ namespace ts {
fsWatch,
fileExists,
useCaseSensitiveFileNames,
getCurrentDirectory,
fsSupportsRecursiveFsWatch,
directoryExists,
getAccessibleSortedChildDirectories,
Expand Down Expand Up @@ -868,7 +902,7 @@ namespace ts {
return fsWatch(
directoryName,
FileSystemEntryKind.Directory,
createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback),
createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback, options, useCaseSensitiveFileNames, getCurrentDirectory),
recursive,
PollingInterval.Medium,
getFallbackOptions(options)
Expand All @@ -878,6 +912,7 @@ namespace ts {
if (!hostRecursiveDirectoryWatcher) {
hostRecursiveDirectoryWatcher = createDirectoryWatcherSupportingRecursive({
useCaseSensitiveFileNames,
getCurrentDirectory,
directoryExists,
getAccessibleSortedChildDirectories,
watchDirectory: nonRecursiveWatchDirectory,
Expand All @@ -891,8 +926,8 @@ namespace ts {

function nonRecursiveWatchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean, options: WatchOptions | undefined): FileWatcher {
Debug.assert(!recursive);
options = updateOptionsForWatchDirectory(options);
const watchDirectoryKind = Debug.checkDefined(options.watchDirectory);
const watchDirectoryOptions = updateOptionsForWatchDirectory(options);
const watchDirectoryKind = Debug.checkDefined(watchDirectoryOptions.watchDirectory);
switch (watchDirectoryKind) {
case WatchDirectoryKind.FixedPollingInterval:
return pollingWatchFile(
Expand All @@ -912,10 +947,10 @@ namespace ts {
return fsWatch(
directoryName,
FileSystemEntryKind.Directory,
createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback),
createFsWatchCallbackForDirectoryWatcherCallback(directoryName, callback, options, useCaseSensitiveFileNames, getCurrentDirectory),
recursive,
PollingInterval.Medium,
getFallbackOptions(options)
getFallbackOptions(watchDirectoryOptions)
);
default:
Debug.assertNever(watchDirectoryKind);
Expand Down Expand Up @@ -1161,13 +1196,15 @@ namespace ts {
const platform: string = _os.platform();
const useCaseSensitiveFileNames = isFileSystemCaseSensitive();
const fsSupportsRecursiveFsWatch = isNode4OrLater && (process.platform === "win32" || process.platform === "darwin");
const getCurrentDirectory = memoize(() => process.cwd());
const { watchFile, watchDirectory } = createSystemWatchFunctions({
pollingWatchFile: createSingleFileWatcherPerName(fsWatchFileWorker, useCaseSensitiveFileNames),
getModifiedTime,
setTimeout,
clearTimeout,
fsWatch,
useCaseSensitiveFileNames,
getCurrentDirectory,
fileExists,
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
Expand Down Expand Up @@ -1214,9 +1251,7 @@ namespace ts {
getExecutingFilePath() {
return __filename;
},
getCurrentDirectory() {
return process.cwd();
},
getCurrentDirectory,
getDirectories,
getEnvironmentVariable(name: string) {
return process.env[name] || "";
Expand Down
1 change: 1 addition & 0 deletions src/harness/virtualFileSystemWithWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ interface Array<T> { length: number; [n: number]: T; }`
fsWatch: this.fsWatch.bind(this),
fileExists: this.fileExists.bind(this),
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames,
getCurrentDirectory: this.getCurrentDirectory.bind(this),
fsSupportsRecursiveFsWatch: tscWatchDirectory ? false : !runWithoutRecursiveWatches,
directoryExists: this.directoryExists.bind(this),
getAccessibleSortedChildDirectories: path => this.getDirectories(path),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,6 @@ Input::
//// [/user/username/projects/myproject/node_modules/bar/fooBar.d.ts] deleted

Output::
DirectoryWatcher:: Triggered with /user/username/projects/myproject/node_modules/bar/fooBar.d.ts :: WatchInfo: /user/username/projects/myproject 1 {"excludeDirectories":["/user/username/projects/myproject/node_modules"]} Wild card directory

Project: /user/username/projects/myproject/tsconfig.json Detected excluded file: /user/username/projects/myproject/node_modules/bar/fooBar.d.ts

Elapsed:: *ms DirectoryWatcher:: Triggered with /user/username/projects/myproject/node_modules/bar/fooBar.d.ts :: WatchInfo: /user/username/projects/myproject 1 {"excludeDirectories":["/user/username/projects/myproject/node_modules"]} Wild card directory


WatchedFiles::
/user/username/projects/myproject/tsconfig.json:
Expand Down

0 comments on commit dddd906

Please sign in to comment.