Handle network style paths for watching (#32888)

* Refactoring

* take windows style root as test server host parameter

* Handle network style paths for watching
Fixes #32796
This commit is contained in:
Sheetal Nandi 2019-08-20 10:52:56 -07:00 committed by GitHub
parent 1bf218291f
commit 5ac450510a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 37 deletions

View File

@ -90,14 +90,28 @@ namespace ts {
return false;
}
const nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
let nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
if (nextDirectorySeparator === -1) {
// ignore "/user", "c:/users" or "c:/folderAtRoot"
return false;
}
if (dirPath.charCodeAt(0) !== CharacterCodes.slash &&
dirPath.substr(rootLength, nextDirectorySeparator).search(/users/i) === -1) {
let pathPartForUserCheck = dirPath.substring(rootLength, nextDirectorySeparator + 1);
const isNonDirectorySeparatorRoot = rootLength > 1 || dirPath.charCodeAt(0) !== CharacterCodes.slash;
if (isNonDirectorySeparatorRoot &&
dirPath.search(/[a-zA-Z]:/) !== 0 && // Non dos style paths
pathPartForUserCheck.search(/[a-zA-z]\$\//) === 0) { // Dos style nextPart
nextDirectorySeparator = dirPath.indexOf(directorySeparator, nextDirectorySeparator + 1);
if (nextDirectorySeparator === -1) {
// ignore "//vda1cs4850/c$/folderAtRoot"
return false;
}
pathPartForUserCheck = dirPath.substring(rootLength + pathPartForUserCheck.length, nextDirectorySeparator + 1);
}
if (isNonDirectorySeparatorRoot &&
pathPartForUserCheck.search(/users\//i) !== 0) {
// Paths like c:/folderAtRoot/subFolder are allowed
return true;
}
@ -105,7 +119,7 @@ namespace ts {
for (let searchIndex = nextDirectorySeparator + 1, searchLevels = 2; searchLevels > 0; searchLevels--) {
searchIndex = dirPath.indexOf(directorySeparator, searchIndex) + 1;
if (searchIndex === 0) {
// Folder isnt at expected minimun levels
// Folder isnt at expected minimum levels
return false;
}
}

View File

@ -35,38 +35,16 @@ interface Array<T> { length: number; [n: number]: T; }`
executingFilePath?: string;
currentDirectory?: string;
newLine?: string;
useWindowsStylePaths?: boolean;
windowsStyleRoot?: string;
environmentVariables?: Map<string>;
}
export function createWatchedSystem(fileOrFolderList: ReadonlyArray<FileOrFolderOrSymLink>, params?: TestServerHostCreationParameters): TestServerHost {
if (!params) {
params = {};
}
const host = new TestServerHost(/*withSafelist*/ false,
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
params.executingFilePath || getExecutingFilePathFromLibFile(),
params.currentDirectory || "/",
fileOrFolderList,
params.newLine,
params.useWindowsStylePaths,
params.environmentVariables);
return host;
return new TestServerHost(/*withSafelist*/ false, fileOrFolderList, params);
}
export function createServerHost(fileOrFolderList: ReadonlyArray<FileOrFolderOrSymLink>, params?: TestServerHostCreationParameters): TestServerHost {
if (!params) {
params = {};
}
const host = new TestServerHost(/*withSafelist*/ true,
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
params.executingFilePath || getExecutingFilePathFromLibFile(),
params.currentDirectory || "/",
fileOrFolderList,
params.newLine,
params.useWindowsStylePaths,
params.environmentVariables);
return host;
return new TestServerHost(/*withSafelist*/ true, fileOrFolderList, params);
}
export interface File {
@ -326,6 +304,16 @@ interface Array<T> { length: number; [n: number]: T; }`
}
const timeIncrements = 1000;
export interface TestServerHostOptions {
useCaseSensitiveFileNames: boolean;
executingFilePath: string;
currentDirectory: string;
fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>;
newLine?: string;
useWindowsStylePaths?: boolean;
environmentVariables?: Map<string>;
}
export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost {
args: string[] = [];
@ -342,16 +330,31 @@ interface Array<T> { length: number; [n: number]: T; }`
readonly watchedDirectories = createMultiMap<TestDirectoryWatcher>();
readonly watchedDirectoriesRecursive = createMultiMap<TestDirectoryWatcher>();
readonly watchedFiles = createMultiMap<TestFileWatcher>();
public readonly useCaseSensitiveFileNames: boolean;
public readonly newLine: string;
public readonly windowsStyleRoot?: string;
private readonly environmentVariables?: Map<string>;
private readonly executingFilePath: string;
private readonly currentDirectory: string;
private readonly customWatchFile: HostWatchFile | undefined;
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
public require: ((initialPath: string, moduleName: string) => server.RequireResult) | undefined;
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
constructor(
public withSafeList: boolean,
fileOrFolderorSymLinkList: ReadonlyArray<FileOrFolderOrSymLink>,
{
useCaseSensitiveFileNames, executingFilePath, currentDirectory,
newLine, windowsStyleRoot, environmentVariables
}: TestServerHostCreationParameters = {}) {
this.useCaseSensitiveFileNames = !!useCaseSensitiveFileNames;
this.newLine = newLine || "\n";
this.windowsStyleRoot = windowsStyleRoot;
this.environmentVariables = environmentVariables;
currentDirectory = currentDirectory || "/";
this.getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
this.executingFilePath = this.getHostSpecificPath(executingFilePath || getExecutingFilePathFromLibFile());
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
this.reloadFS(fileOrFolderorSymLinkList);
const tscWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") as Tsc_WatchFile;
@ -418,8 +421,8 @@ interface Array<T> { length: number; [n: number]: T; }`
}
getHostSpecificPath(s: string) {
if (this.useWindowsStylePath && s.startsWith(directorySeparator)) {
return "c:/" + s.substring(1);
if (this.windowsStyleRoot && s.startsWith(directorySeparator)) {
return this.windowsStyleRoot + s.substring(1);
}
return s;
}
@ -433,7 +436,7 @@ interface Array<T> { length: number; [n: number]: T; }`
const mapNewLeaves = createMap<true>();
const isNewFs = this.fs.size === 0;
fileOrFolderOrSymLinkList = fileOrFolderOrSymLinkList.concat(this.withSafeList ? safeList : []);
const filesOrFoldersToLoad: ReadonlyArray<FileOrFolderOrSymLink> = !this.useWindowsStylePath ? fileOrFolderOrSymLinkList :
const filesOrFoldersToLoad: ReadonlyArray<FileOrFolderOrSymLink> = !this.windowsStyleRoot ? fileOrFolderOrSymLinkList :
fileOrFolderOrSymLinkList.map<FileOrFolderOrSymLink>(f => {
const result = clone(f);
result.path = this.getHostSpecificPath(f.path);

View File

@ -1061,7 +1061,7 @@ namespace ts.projectSystem {
content: "let x = 1;"
};
const host = createServerHost([file1, configFile], { useWindowsStylePaths: true });
const host = createServerHost([file1, configFile], { windowsStyleRoot: "c:/" });
const projectService = createProjectService(host);
projectService.openClientFile(file1.path);

View File

@ -99,7 +99,7 @@ namespace ts.projectSystem {
content: "let y = 10;"
};
const files = [configFile, file1, file2, libFile];
const host = createServerHost(files, { useWindowsStylePaths: true });
const host = createServerHost(files, { windowsStyleRoot: "c:/" });
const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
const project = projectService.configuredProjects.get(configFile.path)!;
@ -211,4 +211,39 @@ namespace ts.projectSystem {
}
});
describe("unittests:: tsserver:: watchEnvironment:: tsserverProjectSystem watching files with network style paths", () => {
function verifyFilePathStyle(path: string) {
const windowsStyleRoot = path.substr(0, getRootLength(path));
const host = createServerHost(
[libFile, { path, content: "const x = 10" }],
{ windowsStyleRoot }
);
const service = createProjectService(host);
service.openClientFile(path);
checkNumberOfProjects(service, { inferredProjects: 1 });
const libPath = `${windowsStyleRoot}${libFile.path.substring(1)}`;
checkProjectActualFiles(service.inferredProjects[0], [path, libPath]);
checkWatchedFiles(host, [libPath, `${getDirectoryPath(path)}/tsconfig.json`, `${getDirectoryPath(path)}/jsconfig.json`]);
}
it("for file of style c:/myprojects/project/x.js", () => {
verifyFilePathStyle("c:/myprojects/project/x.js");
});
it("for file of style //vda1cs4850/myprojects/project/x.js", () => {
verifyFilePathStyle("//vda1cs4850/myprojects/project/x.js");
});
it("for file of style //vda1cs4850/c$/myprojects/project/x.js", () => {
verifyFilePathStyle("//vda1cs4850/c$/myprojects/project/x.js");
});
it("for file of style c:/users/username/myprojects/project/x.js", () => {
verifyFilePathStyle("c:/users/username/myprojects/project/x.js");
});
it("for file of style //vda1cs4850/c$/users/username/myprojects/project/x.js", () => {
verifyFilePathStyle("//vda1cs4850/c$/users/username/myprojects/project/x.js");
});
});
}