Revert System changes and consume fs directly

This commit is contained in:
Andrew Casey
2020-08-20 18:04:38 -07:00
parent 5d60972ef4
commit a0479da1e5
10 changed files with 133 additions and 111 deletions

View File

@@ -201,7 +201,8 @@ namespace ts {
name: "generateTrace",
type: "string",
isFilePath: true,
paramType: Diagnostics.FILE_OR_DIRECTORY,
isCommandLineOnly: true,
paramType: Diagnostics.DIRECTORY,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Generates_an_event_trace_and_a_list_of_types
},

View File

@@ -1047,13 +1047,11 @@ namespace ts {
args: string[];
newLine: string;
useCaseSensitiveFileNames: boolean;
write(s: string, fd?: number): void;
write(s: string): void;
writeOutputIsTTY?(): boolean;
readFile(path: string, encoding?: string): string | undefined;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
openFile(path: string, mode: "w"): number | undefined;
closeFile(fd: number): void;
/**
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
@@ -1185,33 +1183,12 @@ namespace ts {
args: process.argv.slice(2),
newLine: _os.EOL,
useCaseSensitiveFileNames,
write(s: string, fd?: number): void {
if (fd) {
_fs.writeSync(fd, s);
}
else {
process.stdout.write(s);
}
write(s: string): void {
process.stdout.write(s);
},
writeOutputIsTTY() {
return process.stdout.isTTY;
},
openFile: (path, mode) => {
try {
return _fs.openSync(path, mode);
}
catch {
return undefined;
}
},
closeFile: (fd) => {
try {
_fs.closeSync(fd);
}
catch {
// ignore
}
},
readFile,
writeFile,
watchFile,

View File

@@ -1,27 +1,83 @@
/*@internal*/
/** Tracing events for the compiler. */
namespace ts.tracing {
type WriteFn = (data: string) => void;
let fs: typeof import("fs") | false | undefined;
let write: WriteFn | undefined;
let traceCount = 0;
let traceFd: number | undefined;
/** Enables (and resets) tracing events for the compiler. */
export function startTracing(w: WriteFn) {
write = w;
write(`[\n`);
let legendPath: string | undefined;
const legend: TraceRecord[] = [];
/** Starts tracing for the given project (unless the `fs` module is unavailable). */
export function startTracing(configFilePath: string | undefined, traceDir: string, isBuildMode: boolean) {
Debug.assert(!traceFd, "Tracing already started");
if (fs === undefined) {
try {
fs = require("fs");
}
catch {
fs = false;
}
}
if (!fs) {
return;
}
if (legendPath === undefined) {
legendPath = combinePaths(traceDir, "legend.json");
}
// Note that writing will fail later on if it exists and is not a directory
if (!fs.existsSync(traceDir)) {
fs.mkdirSync(traceDir, { recursive: true });
}
const countPart = isBuildMode ? `.${++traceCount}` : ``;
const tracePath = combinePaths(traceDir, `trace${countPart}.json`);
const typesPath = combinePaths(traceDir, `types${countPart}.json`);
legend.push({
configFilePath,
tracePath,
typesPath,
});
traceFd = fs.openSync(tracePath, "w");
fs.writeSync(traceFd, `[\n`);
}
/** Disables tracing events for the compiler. */
export function stopTracing() {
/** Stops tracing for the in-progress project and dumps the type catalog (unless the `fs` module is unavailable). */
export function stopTracing(typeCatalog: readonly Type[]) {
if (!traceFd) {
Debug.assert(!fs, "Tracing is not in progress");
return;
}
Debug.assert(fs);
// This both indicates that the trace is untruncated and conveniently
// ensures that the last array element won't have a trailing comma.
write?.(`{"pid":1,"tid":1,"ph":"i","ts":${1000 * timestamp()},"name":"done","s":"g"}\n`);
write?.(`]\n`);
write = undefined;
fs.writeSync(traceFd, `{"pid":1,"tid":1,"ph":"i","ts":${1000 * timestamp()},"name":"done","s":"g"}\n`);
fs.writeSync(traceFd, `]\n`);
fs.closeSync(traceFd);
traceFd = undefined;
if (typeCatalog) {
dumpTypes(typeCatalog);
}
else {
// We pre-computed this path for convenience, but clear it
// now that the file won't be created.
legend[legend.length - 1].typesPath = undefined;
}
}
export function isTracing() {
return !!write;
return !!traceFd;
}
export const enum Phase {
@@ -33,15 +89,25 @@ namespace ts.tracing {
}
export function begin(phase: Phase, name: string, args: object) {
if (!traceFd) {
return;
}
Debug.assert(fs);
performance.mark("beginTracing");
write?.(`{"pid":1,"tid":1,"ph":"B","cat":"${phase}","ts":${1000 * timestamp()},"name":"${name}","args":{ "ts": ${JSON.stringify(args)} }},\n`);
fs.writeSync(traceFd, `{"pid":1,"tid":1,"ph":"B","cat":"${phase}","ts":${1000 * timestamp()},"name":"${name}","args":{ "ts": ${JSON.stringify(args)} }},\n`);
performance.mark("endTracing");
performance.measure("Tracing", "beginTracing", "endTracing");
}
export function end() {
if (!traceFd) {
return;
}
Debug.assert(fs);
performance.mark("beginTracing");
write?.(`{"pid":1,"tid":1,"ph":"E","ts":${1000 * timestamp()}},\n`);
fs.writeSync(traceFd, `{"pid":1,"tid":1,"ph":"E","ts":${1000 * timestamp()}},\n`);
performance.mark("endTracing");
performance.measure("Tracing", "beginTracing", "endTracing");
}
@@ -53,13 +119,18 @@ namespace ts.tracing {
};
}
export function dumpTypes(types: readonly Type[], write: WriteFn) {
function dumpTypes(types: readonly Type[]) {
Debug.assert(fs);
performance.mark("beginDumpTypes");
const numTypes = types.length;
const typesPath = legend[legend.length - 1].typesPath!;
const typesFd = fs.openSync(typesPath, "w");
// Cleverness: no line break hear so that the type ID will match the line number
write("[");
// Cleverness: no line break here so that the type ID will match the line number
fs.writeSync(typesFd, "[");
const numTypes = types.length;
for (let i = 0; i < numTypes; i++) {
const type = types[i];
const objectFlags = (type as any).objectFlags;
@@ -127,14 +198,32 @@ namespace ts.tracing {
display,
};
write(JSON.stringify(descriptor));
fs.writeSync(typesFd, JSON.stringify(descriptor));
if (i < numTypes - 1) {
write(",\n");
fs.writeSync(typesFd, ",\n");
}
}
write("]\n");
fs.writeSync(typesFd, "]\n");
fs.closeSync(typesFd);
performance.mark("endDumpTypes");
performance.measure("Dump types", "beginDumpTypes", "endDumpTypes");
}
export function dumpLegend() {
if (!legendPath) {
return;
}
Debug.assert(fs);
fs.writeFileSync(legendPath, JSON.stringify(legend));
}
interface TraceRecord {
configFilePath?: string;
tracePath: string;
typesPath?: string;
}
}

View File

@@ -456,6 +456,7 @@ namespace ts {
updateSolutionBuilderHost(sys, cb, buildHost);
const builder = createSolutionBuilder(buildHost, projects, buildOptions);
const exitStatus = buildOptions.clean ? builder.clean() : builder.build();
tracing.dumpLegend();
return sys.exit(exitStatus);
}
@@ -476,7 +477,7 @@ namespace ts {
const currentDirectory = host.getCurrentDirectory();
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName));
enableStatisticsAndTracing(sys, options);
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
const programOptions: CreateProgramOptions = {
rootNames: fileNames,
@@ -504,7 +505,7 @@ namespace ts {
config: ParsedCommandLine
) {
const { options, fileNames, projectReferences } = config;
enableStatisticsAndTracing(sys, options);
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
const host = createIncrementalCompilerHost(options, sys);
const exitStatus = ts.performIncrementalCompilation({
host,
@@ -541,7 +542,7 @@ namespace ts {
host.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => {
Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram));
if (options !== undefined) {
enableStatisticsAndTracing(sys, options);
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ true);
}
return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
};
@@ -610,41 +611,25 @@ namespace ts {
return system === sys && (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics);
}
let traceCount = 0;
let tracingFd: number | undefined;
function canTrace(system: System, compilerOptions: CompilerOptions) {
return system === sys && compilerOptions.generateTrace;
}
function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions) {
function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions, isBuildMode: boolean) {
if (canReportDiagnostics(system, compilerOptions)) {
performance.enable();
}
Debug.assert(!tracingFd, "Tracing already started");
if (system === sys) {
const tracePath = compilerOptions.generateTrace;
if (tracePath) {
const extension = getAnyExtensionFromPath(tracePath);
tracingFd = sys.openFile(changeAnyExtension(tracePath, `${++traceCount}${extension}`), "w");
if (tracingFd) {
tracing.startTracing(event => sys.write(event, tracingFd));
}
}
if (canTrace(system, compilerOptions)) {
tracing.startTracing(compilerOptions.configFilePath, compilerOptions.generateTrace!, isBuildMode);
}
}
function reportStatistics(sys: System, program: Program) {
const compilerOptions = program.getCompilerOptions();
if (tracingFd) {
tracing.stopTracing();
sys.closeFile(tracingFd);
tracingFd = undefined;
const typesPath = changeAnyExtension(compilerOptions.generateTrace!, `${traceCount}.types.json`);
const typesFd = sys.openFile(typesPath, "w");
if (typesFd) {
tracing.dumpTypes(program.getTypeCatalog(), type => sys.write(type, typesFd));
sys.closeFile(typesFd);
}
if (canTrace(sys, compilerOptions)) {
tracing.stopTracing(program.getTypeCatalog());
}
let statistics: Statistic[];

View File

@@ -37,8 +37,7 @@ namespace fakes {
return true;
}
public write(message: string, fd?: number) {
assert.isUndefined(fd);
public write(message: string) {
this.output.push(message);
}
@@ -61,15 +60,6 @@ namespace fakes {
this.vfs.unlinkSync(path);
}
public openFile(_path: string, _mode: "w"): number | undefined {
assert.fail("NYI");
return undefined;
}
public closeFile(_fd: number): void{
assert.fail("NYI");
}
public fileExists(path: string) {
const stats = this._getStats(path);
return stats ? stats.isFile() : false;

View File

@@ -724,8 +724,7 @@ namespace Harness.LanguageService {
onMessage = ts.noop;
writeMessage = ts.noop; // overridden
write(message: string, fd?: number): void {
assert.isUndefined(fd);
write(message: string): void {
this.writeMessage(message);
}
@@ -745,9 +744,6 @@ namespace Harness.LanguageService {
writeFile = ts.noop;
openFile = ts.returnUndefined;
closeFile = ts.noop;
resolvePath(path: string): string {
return path;
}

View File

@@ -1011,21 +1011,11 @@ interface Array<T> { length: number; [n: number]: T; }`
}
}
openFile(_path: string, _mode: "w"): number | undefined {
assert.fail("NYI");
return undefined;
}
closeFile(_fd: number): void {
assert.fail("NYI");
}
appendFile(path: string, content: string, options?: Partial<ReloadWatchInvokeOptions>): void {
this.modifyFile(path, this.readFile(path) + content, options);
}
write(message: string, fd?: number) {
assert.isUndefined(fd);
write(message: string) {
this.output.push(message);
}

View File

@@ -7,11 +7,9 @@ namespace ts.server {
args: [],
newLine: "\n",
useCaseSensitiveFileNames: true,
write(s, _fd: number): void { lastWrittenToHost = s; },
write(s): void { lastWrittenToHost = s; },
readFile: returnUndefined,
writeFile: noop,
openFile: returnUndefined,
closeFile: noop,
resolvePath(): string { return undefined!; }, // TODO: GH#18217
fileExists: () => false,
directoryExists: () => false,